Merge "test_create_server_from_volume_snapshot: assert dict is not empty before accessing a key"
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index 6b87b4d..572d425 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -243,3 +243,7 @@
  * `2.37`_
 
  .. _2.37: http://docs.openstack.org/developer/nova/api_microversion_history.html#id34
+
+ * `2.42`_
+
+ .. _2.42: http://docs.openstack.org/developer/nova/api_microversion_history.html#maximum-in-ocata
diff --git a/releasenotes/notes/add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml b/releasenotes/notes/add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml
new file mode 100644
index 0000000..9116ef8
--- /dev/null
+++ b/releasenotes/notes/add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add the implied roles feature API to the roles_client library. This
+    feature enables the possibility to create inferences rules between
+    roles (a role being implied by another role).
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index 8eac1d0..242d133 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -6,6 +6,7 @@
     :maxdepth: 1
 
     unreleased
+    v14.0.0
     v13.0.0
     v12.0.0
     v11.0.0
diff --git a/releasenotes/source/v14.0.0.rst b/releasenotes/source/v14.0.0.rst
new file mode 100644
index 0000000..440c85b
--- /dev/null
+++ b/releasenotes/source/v14.0.0.rst
@@ -0,0 +1,6 @@
+=====================
+v14.0.0 Release Notes
+=====================
+
+.. release-notes:: 14.0.0 Release Notes
+   :version: 14.0.0
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 85c7fba..9e1c0e9 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -18,6 +18,7 @@
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest.lib import decorators
+from tempest import test
 
 
 class ServersAdminTestJSON(base.BaseV2ComputeAdminTest):
@@ -91,6 +92,7 @@
         self.assertIn(self.s1_name, servers_name)
         self.assertIn(self.s2_name, servers_name)
 
+    @test.related_bug('1659811')
     @decorators.idempotent_id('7e5d6b8f-454a-4ba1-8ae2-da857af8338b')
     def test_list_servers_by_admin_with_specified_tenant(self):
         # In nova v2, tenant_id is ignored unless all_tenants is specified
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index d77ea90..c3c5460 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -304,14 +304,28 @@
         cls.images.append(image_id)
 
         if 'wait_until' in kwargs:
-            waiters.wait_for_image_status(cls.compute_images_client,
-                                          image_id, kwargs['wait_until'])
+            try:
+                waiters.wait_for_image_status(cls.compute_images_client,
+                                              image_id, kwargs['wait_until'])
+            except lib_exc.NotFound:
+                if kwargs['wait_until'].upper() == 'ACTIVE':
+                    # If the image is not found after create_image returned
+                    # that means the snapshot failed in nova-compute and nova
+                    # deleted the image. There should be a compute fault
+                    # recorded with the server in that case, so get the server
+                    # and dump some details.
+                    server = (
+                        cls.servers_client.show_server(server_id)['server'])
+                    if 'fault' in server:
+                        raise exceptions.SnapshotNotFoundException(
+                            server['fault'], image_id=image_id)
+                    else:
+                        raise exceptions.SnapshotNotFoundException(
+                            image_id=image_id)
+                else:
+                    raise
             image = cls.compute_images_client.show_image(image_id)['image']
 
-            if kwargs['wait_until'] == 'ACTIVE':
-                if kwargs.get('wait_for_server', True):
-                    waiters.wait_for_server_status(cls.servers_client,
-                                                   server_id, 'ACTIVE')
         return image
 
     @classmethod
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index a0c860a..d9db0b5 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -60,7 +60,6 @@
         snapshot_name = data_utils.rand_name('test-snap')
         image = self.create_image_from_server(server['id'],
                                               name=snapshot_name,
-                                              wait_until='ACTIVE',
-                                              wait_for_server=False)
+                                              wait_until='ACTIVE')
         self.addCleanup(self.client.delete_image, image['id'])
         self.assertEqual(snapshot_name, image['name'])
diff --git a/tempest/api/compute/servers/test_device_tagging.py b/tempest/api/compute/servers/test_device_tagging.py
index ae8f47d..d9e83a6 100644
--- a/tempest/api/compute/servers/test_device_tagging.py
+++ b/tempest/api/compute/servers/test_device_tagging.py
@@ -33,7 +33,11 @@
 class DeviceTaggingTest(base.BaseV2ComputeTest):
 
     min_microversion = '2.32'
-    max_microversion = 'latest'
+    # NOTE(mriedem): max_version looks odd but it's actually correct. Due to a
+    # bug in the 2.32 microversion, tags on block devices only worked with the
+    # 2.32 microversion specifically. And tags on networks only worked between
+    # 2.32 and 2.36 inclusive; the 2.37 microversion broke tags for networks.
+    max_microversion = '2.32'
 
     @classmethod
     def skip_checks(cls):
@@ -262,3 +266,8 @@
             cmd_md = 'sudo cat /mnt/openstack/latest/meta_data.json'
             md_json = self.ssh_client.exec_command(cmd_md)
             self.verify_device_metadata(md_json)
+
+
+class DeviceTaggingTestV2_42(DeviceTaggingTest):
+    min_microversion = '2.42'
+    max_microversion = 'latest'
diff --git a/tempest/api/compute/volumes/test_attach_volume_negative.py b/tempest/api/compute/volumes/test_attach_volume_negative.py
index acab4b1..c017690 100644
--- a/tempest/api/compute/volumes/test_attach_volume_negative.py
+++ b/tempest/api/compute/volumes/test_attach_volume_negative.py
@@ -30,6 +30,7 @@
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
 
+    @test.attr(type=['negative'])
     @test.related_bug('1630783', status_code=500)
     @decorators.idempotent_id('a313b5cd-fbd0-49cc-94de-870e99f763c7')
     def test_delete_attached_volume(self):
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index fef6020..b37d33d 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -88,6 +88,30 @@
         self.assertEqual(project_name, project['name'])
         self.assertEqual(root_project_id, parent_id)
 
+    @decorators.idempotent_id('a7eb9416-6f9b-4dbb-b71b-7f73aaef59d5')
+    @testtools.skipUnless(CONF.identity_feature_enabled.reseller,
+                          'Reseller not available.')
+    def test_create_is_domain_project(self):
+        project_name = data_utils.rand_name('is_domain_project')
+        project = self.projects_client.create_project(
+            project_name, domain_id=None, is_domain=True)['project']
+        # To delete a domain, we need to disable it first
+        self.addCleanup(self.projects_client.delete_project, project['id'])
+        self.addCleanup(self.projects_client.update_project, project['id'],
+                        enabled=False)
+
+        # Check if the is_domain project is correctly returned by both
+        # project and domain APIs
+        projects_list = self.projects_client.list_projects(
+            params={'is_domain': True})['projects']
+        self.assertIn(project, projects_list)
+
+        # The domains API return different attributes for the entity, so we
+        # compare the entities IDs
+        domains_ids = [d['id'] for d in self.domains_client.list_domains()[
+            'domains']]
+        self.assertIn(project['id'], domains_ids)
+
     @decorators.idempotent_id('1f66dc76-50cc-4741-a200-af984509e480')
     def test_project_create_enabled(self):
         # Create a project that is enabled
diff --git a/tempest/api/network/base_routers.py b/tempest/api/network/base_routers.py
index 5fb5232..f6fd871 100644
--- a/tempest/api/network/base_routers.py
+++ b/tempest/api/network/base_routers.py
@@ -38,10 +38,8 @@
         client.delete_router(router_id)
         # Asserting that the router is not found in the list
         # after deletion
-        list_body = self.routers_client.list_routers()
-        routers_list = list()
-        for router in list_body['routers']:
-            routers_list.append(router['id'])
+        list_body = client.list_routers()
+        routers_list = [router['id'] for router in list_body['routers']]
         self.assertNotIn(router_id, routers_list)
 
     def _add_router_interface_with_subnet_id(self, router_id, subnet_id):
diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py
index 1eda49a..d882731 100644
--- a/tempest/api/object_storage/test_account_bulk.py
+++ b/tempest/api/object_storage/test_account_bulk.py
@@ -17,6 +17,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -68,7 +69,7 @@
         self.assertHeaders(resp, 'Account', 'GET')
         self.assertNotIn(container_name, body)
 
-    @test.idempotent_id('a407de51-1983-47cc-9f14-47c2b059413c')
+    @decorators.idempotent_id('a407de51-1983-47cc-9f14-47c2b059413c')
     @test.requires_ext(extension='bulk_upload', service='object')
     def test_extract_archive(self):
         # Test bulk operation of file upload with an archived file
@@ -104,7 +105,7 @@
 
         self.assertIn(object_name, [c['name'] for c in contents_list])
 
-    @test.idempotent_id('c075e682-0d2a-43b2-808d-4116200d736d')
+    @decorators.idempotent_id('c075e682-0d2a-43b2-808d-4116200d736d')
     @test.requires_ext(extension='bulk_delete', service='object')
     def test_bulk_delete(self):
         # Test bulk operation of deleting multiple files
@@ -131,7 +132,7 @@
         # Check if uploaded contents are completely deleted
         self._check_contents_deleted(container_name)
 
-    @test.idempotent_id('dbea2bcb-efbb-4674-ac8a-a5a0e33d1d79')
+    @decorators.idempotent_id('dbea2bcb-efbb-4674-ac8a-a5a0e33d1d79')
     @test.requires_ext(extension='bulk_delete', service='object')
     def test_bulk_delete_by_POST(self):
         # Test bulk operation of deleting multiple files
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
index fcbd6eb..cbf0d4b 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -15,6 +15,7 @@
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -76,7 +77,7 @@
         super(AccountQuotasTest, cls).resource_cleanup()
 
     @test.attr(type="smoke")
-    @test.idempotent_id('a22ef352-a342-4587-8f47-3bbdb5b039c4')
+    @decorators.idempotent_id('a22ef352-a342-4587-8f47-3bbdb5b039c4')
     @test.requires_ext(extension='account_quotas', service='object')
     def test_upload_valid_object(self):
         object_name = data_utils.rand_name(name="TestObject")
@@ -87,7 +88,7 @@
         self.assertHeaders(resp, 'Object', 'PUT')
 
     @test.attr(type=["smoke"])
-    @test.idempotent_id('63f51f9f-5f1d-4fc6-b5be-d454d70949d6')
+    @decorators.idempotent_id('63f51f9f-5f1d-4fc6-b5be-d454d70949d6')
     @test.requires_ext(extension='account_quotas', service='object')
     def test_admin_modify_quota(self):
         """Test ResellerAdmin can modify/remove the quota on a user's account
diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py
index ae8dfcc..2e85a43 100644
--- a/tempest/api/object_storage/test_account_quotas_negative.py
+++ b/tempest/api/object_storage/test_account_quotas_negative.py
@@ -14,6 +14,7 @@
 
 from tempest.api.object_storage import base
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -75,7 +76,7 @@
         super(AccountQuotasNegativeTest, cls).resource_cleanup()
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('d1dc5076-555e-4e6d-9697-28f1fe976324')
+    @decorators.idempotent_id('d1dc5076-555e-4e6d-9697-28f1fe976324')
     @test.requires_ext(extension='account_quotas', service='object')
     def test_user_modify_quota(self):
         """Test that a user cannot modify or remove a quota on its account."""
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 59129e5..d779d42 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -22,6 +22,7 @@
 from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -54,7 +55,7 @@
         super(AccountTest, cls).resource_cleanup()
 
     @test.attr(type='smoke')
-    @test.idempotent_id('3499406a-ae53-4f8c-b43a-133d4dc6fe3f')
+    @decorators.idempotent_id('3499406a-ae53-4f8c-b43a-133d4dc6fe3f')
     def test_list_containers(self):
         # list of all containers should not be empty
         resp, container_list = self.account_client.list_account_containers()
@@ -66,7 +67,7 @@
             self.assertIn(six.text_type(container_name).encode('utf-8'),
                           container_list)
 
-    @test.idempotent_id('884ec421-fbad-4fcc-916b-0580f2699565')
+    @decorators.idempotent_id('884ec421-fbad-4fcc-916b-0580f2699565')
     def test_list_no_containers(self):
         # List request to empty account
 
@@ -103,7 +104,7 @@
 
         self.assertEqual(len(container_list), 0)
 
-    @test.idempotent_id('1c7efa35-e8a2-4b0b-b5ff-862c7fd83704')
+    @decorators.idempotent_id('1c7efa35-e8a2-4b0b-b5ff-862c7fd83704')
     def test_list_containers_with_format_json(self):
         # list containers setting format parameter to 'json'
         params = {'format': 'json'}
@@ -115,7 +116,7 @@
         self.assertTrue([c['count'] for c in container_list])
         self.assertTrue([c['bytes'] for c in container_list])
 
-    @test.idempotent_id('4477b609-1ca6-4d4b-b25d-ad3f01086089')
+    @decorators.idempotent_id('4477b609-1ca6-4d4b-b25d-ad3f01086089')
     def test_list_containers_with_format_xml(self):
         # list containers setting format parameter to 'xml'
         params = {'format': 'xml'}
@@ -130,7 +131,7 @@
         self.assertEqual(container_list.find(".//count").tag, 'count')
         self.assertEqual(container_list.find(".//bytes").tag, 'bytes')
 
-    @test.idempotent_id('6eb04a6a-4860-4e31-ba91-ea3347d76b58')
+    @decorators.idempotent_id('6eb04a6a-4860-4e31-ba91-ea3347d76b58')
     @testtools.skipIf(
         not CONF.object_storage_feature_enabled.discoverability,
         'Discoverability function is disabled')
@@ -139,7 +140,7 @@
 
         self.assertThat(resp, custom_matchers.AreAllWellFormatted())
 
-    @test.idempotent_id('5cfa4ab2-4373-48dd-a41f-a532b12b08b2')
+    @decorators.idempotent_id('5cfa4ab2-4373-48dd-a41f-a532b12b08b2')
     def test_list_containers_with_limit(self):
         # list containers one of them, half of them then all of them
         for limit in (1, self.containers_count // 2,
@@ -151,7 +152,7 @@
 
             self.assertEqual(len(container_list), limit)
 
-    @test.idempotent_id('638f876d-6a43-482a-bbb3-0840bca101c6')
+    @decorators.idempotent_id('638f876d-6a43-482a-bbb3-0840bca101c6')
     def test_list_containers_with_marker(self):
         # list containers using marker param
         # first expect to get 0 container as we specified last
@@ -172,7 +173,7 @@
         self.assertEqual(len(container_list),
                          self.containers_count // 2 - 1)
 
-    @test.idempotent_id('5ca164e4-7bde-43fa-bafb-913b53b9e786')
+    @decorators.idempotent_id('5ca164e4-7bde-43fa-bafb-913b53b9e786')
     def test_list_containers_with_end_marker(self):
         # list containers using end_marker param
         # first expect to get 0 container as we specified first container as
@@ -190,7 +191,7 @@
         self.assertHeaders(resp, 'Account', 'GET')
         self.assertEqual(len(container_list), self.containers_count // 2)
 
-    @test.idempotent_id('ac8502c2-d4e4-4f68-85a6-40befea2ef5e')
+    @decorators.idempotent_id('ac8502c2-d4e4-4f68-85a6-40befea2ef5e')
     def test_list_containers_with_marker_and_end_marker(self):
         # list containers combining marker and end_marker param
         params = {'marker': self.containers[0],
@@ -200,7 +201,7 @@
         self.assertHeaders(resp, 'Account', 'GET')
         self.assertEqual(len(container_list), self.containers_count - 2)
 
-    @test.idempotent_id('f7064ae8-dbcc-48da-b594-82feef6ea5af')
+    @decorators.idempotent_id('f7064ae8-dbcc-48da-b594-82feef6ea5af')
     def test_list_containers_with_limit_and_marker(self):
         # list containers combining marker and limit param
         # result are always limitated by the limit whatever the marker
@@ -215,7 +216,7 @@
             self.assertLessEqual(len(container_list), limit,
                                  str(container_list))
 
-    @test.idempotent_id('888a3f0e-7214-4806-8e50-5e0c9a69bb5e')
+    @decorators.idempotent_id('888a3f0e-7214-4806-8e50-5e0c9a69bb5e')
     def test_list_containers_with_limit_and_end_marker(self):
         # list containers combining limit and end_marker param
         limit = random.randint(1, self.containers_count)
@@ -227,7 +228,7 @@
         self.assertEqual(len(container_list),
                          min(limit, self.containers_count // 2))
 
-    @test.idempotent_id('8cf98d9c-e3a0-4e44-971b-c87656fdddbd')
+    @decorators.idempotent_id('8cf98d9c-e3a0-4e44-971b-c87656fdddbd')
     def test_list_containers_with_limit_and_marker_and_end_marker(self):
         # list containers combining limit, marker and end_marker param
         limit = random.randint(1, self.containers_count)
@@ -240,7 +241,7 @@
         self.assertEqual(len(container_list),
                          min(limit, self.containers_count - 2))
 
-    @test.idempotent_id('365e6fc7-1cfe-463b-a37c-8bd08d47b6aa')
+    @decorators.idempotent_id('365e6fc7-1cfe-463b-a37c-8bd08d47b6aa')
     def test_list_containers_with_prefix(self):
         # list containers that have a name that starts with a prefix
         prefix = '{0}-a'.format(CONF.resources_prefix)
@@ -253,7 +254,7 @@
                 'utf-8').startswith(prefix))
 
     @test.attr(type='smoke')
-    @test.idempotent_id('4894c312-6056-4587-8d6f-86ffbf861f80')
+    @decorators.idempotent_id('4894c312-6056-4587-8d6f-86ffbf861f80')
     def test_list_account_metadata(self):
         # list all account metadata
 
@@ -268,14 +269,14 @@
         self.assertIn('x-account-meta-test-account-meta2', resp)
         self.account_client.delete_account_metadata(metadata)
 
-    @test.idempotent_id('b904c2e3-24c2-4dba-ad7d-04e90a761be5')
+    @decorators.idempotent_id('b904c2e3-24c2-4dba-ad7d-04e90a761be5')
     def test_list_no_account_metadata(self):
         # list no account metadata
         resp, _ = self.account_client.list_account_metadata()
         self.assertHeaders(resp, 'Account', 'HEAD')
         self.assertNotIn('x-account-meta-', str(resp))
 
-    @test.idempotent_id('e2a08b5f-3115-4768-a3ee-d4287acd6c08')
+    @decorators.idempotent_id('e2a08b5f-3115-4768-a3ee-d4287acd6c08')
     def test_update_account_metadata_with_create_metadata(self):
         # add metadata to account
         metadata = {'test-account-meta1': 'Meta1'}
@@ -289,7 +290,7 @@
 
         self.account_client.delete_account_metadata(metadata)
 
-    @test.idempotent_id('9f60348d-c46f-4465-ae06-d51dbd470953')
+    @decorators.idempotent_id('9f60348d-c46f-4465-ae06-d51dbd470953')
     def test_update_account_metadata_with_delete_matadata(self):
         # delete metadata from account
         metadata = {'test-account-meta1': 'Meta1'}
@@ -300,7 +301,7 @@
         resp, _ = self.account_client.list_account_metadata()
         self.assertNotIn('x-account-meta-test-account-meta1', resp)
 
-    @test.idempotent_id('64fd53f3-adbd-4639-af54-436e4982dbfb')
+    @decorators.idempotent_id('64fd53f3-adbd-4639-af54-436e4982dbfb')
     def test_update_account_metadata_with_create_matadata_key(self):
         # if the value of metadata is not set, the metadata is not
         # registered at a server
@@ -311,7 +312,7 @@
         resp, _ = self.account_client.list_account_metadata()
         self.assertNotIn('x-account-meta-test-account-meta1', resp)
 
-    @test.idempotent_id('d4d884d3-4696-4b85-bc98-4f57c4dd2bf1')
+    @decorators.idempotent_id('d4d884d3-4696-4b85-bc98-4f57c4dd2bf1')
     def test_update_account_metadata_with_delete_matadata_key(self):
         # Although the value of metadata is not set, the feature of
         # deleting metadata is valid
@@ -324,7 +325,7 @@
         resp, _ = self.account_client.list_account_metadata()
         self.assertNotIn('x-account-meta-test-account-meta1', resp)
 
-    @test.idempotent_id('8e5fc073-59b9-42ee-984a-29ed11b2c749')
+    @decorators.idempotent_id('8e5fc073-59b9-42ee-984a-29ed11b2c749')
     def test_update_account_metadata_with_create_and_delete_metadata(self):
         # Send a request adding and deleting metadata requests simultaneously
         metadata_1 = {'test-account-meta1': 'Meta1'}
diff --git a/tempest/api/object_storage/test_account_services_negative.py b/tempest/api/object_storage/test_account_services_negative.py
index 254a9b3..d46534b 100644
--- a/tempest/api/object_storage/test_account_services_negative.py
+++ b/tempest/api/object_storage/test_account_services_negative.py
@@ -14,6 +14,7 @@
 
 from tempest.api.object_storage import base
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -32,7 +33,7 @@
         cls.os_operator = cls.os_roles_operator_alt
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('070e6aca-6152-4867-868d-1118d68fb38c')
+    @decorators.idempotent_id('070e6aca-6152-4867-868d-1118d68fb38c')
     def test_list_containers_with_non_authorized_user(self):
         # list containers using non-authorized user
 
diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py
index e555fd9..aa4e92c 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -16,7 +16,7 @@
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -34,7 +34,7 @@
         self.delete_containers()
         super(ObjectTestACLs, self).tearDown()
 
-    @test.idempotent_id('a3270f3f-7640-4944-8448-c7ea783ea5b6')
+    @decorators.idempotent_id('a3270f3f-7640-4944-8448-c7ea783ea5b6')
     def test_read_object_with_rights(self):
         # attempt to read object using authorized user
         # update X-Container-Read metadata ACL
@@ -61,7 +61,7 @@
             self.container_name, object_name)
         self.assertHeaders(resp, 'Object', 'GET')
 
-    @test.idempotent_id('aa58bfa5-40d9-4bc3-82b4-d07f4a9e392a')
+    @decorators.idempotent_id('aa58bfa5-40d9-4bc3-82b4-d07f4a9e392a')
     def test_write_object_with_rights(self):
         # attempt to write object using authorized user
         # update X-Container-Write metadata ACL
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index 0055bf9..d5d5ea7 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -15,6 +15,7 @@
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -47,7 +48,7 @@
         super(ObjectACLsNegativeTest, self).tearDown()
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('af587587-0c24-4e15-9822-8352ce711013')
+    @decorators.idempotent_id('af587587-0c24-4e15-9822-8352ce711013')
     def test_write_object_without_using_creds(self):
         # trying to create object with empty headers
         # X-Auth-Token is not provided
@@ -61,7 +62,7 @@
                           self.container_name, object_name, 'data', headers={})
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('af85af0b-a025-4e72-a90e-121babf55720')
+    @decorators.idempotent_id('af85af0b-a025-4e72-a90e-121babf55720')
     def test_delete_object_without_using_creds(self):
         # create object
         object_name = data_utils.rand_name(name='Object')
@@ -78,7 +79,7 @@
                           self.container_name, object_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('63d84e37-55a6-42e2-9e5f-276e60e26a00')
+    @decorators.idempotent_id('63d84e37-55a6-42e2-9e5f-276e60e26a00')
     def test_write_object_with_non_authorized_user(self):
         # attempt to upload another file using non-authorized user
         # User provided token is forbidden. ACL are not set
@@ -93,7 +94,7 @@
                           self.container_name, object_name, 'data', headers={})
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('abf63359-be52-4feb-87dd-447689fc77fd')
+    @decorators.idempotent_id('abf63359-be52-4feb-87dd-447689fc77fd')
     def test_read_object_with_non_authorized_user(self):
         # attempt to read object using non-authorized user
         # User provided token is forbidden. ACL are not set
@@ -111,7 +112,7 @@
                           self.container_name, object_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7343ac3d-cfed-4198-9bb0-00149741a492')
+    @decorators.idempotent_id('7343ac3d-cfed-4198-9bb0-00149741a492')
     def test_delete_object_with_non_authorized_user(self):
         # attempt to delete object using non-authorized user
         # User provided token is forbidden. ACL are not set
@@ -129,7 +130,7 @@
                           self.container_name, object_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9ed01334-01e9-41ea-87ea-e6f465582823')
+    @decorators.idempotent_id('9ed01334-01e9-41ea-87ea-e6f465582823')
     def test_read_object_without_rights(self):
         # attempt to read object using non-authorized user
         # update X-Container-Read metadata ACL
@@ -153,7 +154,7 @@
                           self.container_name, object_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a3a585a7-d8cf-4b65-a1a0-edc2b1204f85')
+    @decorators.idempotent_id('a3a585a7-d8cf-4b65-a1a0-edc2b1204f85')
     def test_write_object_without_rights(self):
         # attempt to write object using non-authorized user
         # update X-Container-Write metadata ACL
@@ -174,7 +175,7 @@
                           object_name, 'data', headers={})
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('8ba512ad-aa6e-444e-b882-2906a0ea2052')
+    @decorators.idempotent_id('8ba512ad-aa6e-444e-b882-2906a0ea2052')
     def test_write_object_without_write_rights(self):
         # attempt to write object using non-authorized user
         # update X-Container-Read and X-Container-Write metadata ACL
@@ -199,7 +200,7 @@
                           object_name, 'data', headers={})
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('b4e366f8-f185-47ab-b789-df4416f9ecdb')
+    @decorators.idempotent_id('b4e366f8-f185-47ab-b789-df4416f9ecdb')
     def test_delete_object_without_write_rights(self):
         # attempt to delete object using non-authorized user
         # update X-Container-Read and X-Container-Write metadata ACL
diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py
index 8cbe441..d3b456a 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -15,6 +15,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -47,7 +48,7 @@
         self.delete_containers()
         super(ContainerQuotasTest, self).tearDown()
 
-    @test.idempotent_id('9a0fb034-86af-4df0-86fa-f8bd7db21ae0')
+    @decorators.idempotent_id('9a0fb034-86af-4df0-86fa-f8bd7db21ae0')
     @test.requires_ext(extension='container_quotas', service='object')
     @test.attr(type="smoke")
     def test_upload_valid_object(self):
@@ -64,7 +65,7 @@
         nafter = self._get_bytes_used()
         self.assertEqual(nbefore + len(data), nafter)
 
-    @test.idempotent_id('22eeeb2b-3668-4160-baef-44790f65a5a0')
+    @decorators.idempotent_id('22eeeb2b-3668-4160-baef-44790f65a5a0')
     @test.requires_ext(extension='container_quotas', service='object')
     @test.attr(type="smoke")
     def test_upload_large_object(self):
@@ -81,7 +82,7 @@
         nafter = self._get_bytes_used()
         self.assertEqual(nbefore, nafter)
 
-    @test.idempotent_id('3a387039-697a-44fc-a9c0-935de31f426b')
+    @decorators.idempotent_id('3a387039-697a-44fc-a9c0-935de31f426b')
     @test.requires_ext(extension='container_quotas', service='object')
     @test.attr(type="smoke")
     def test_upload_too_many_objects(self):
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index e4476a1..4b65584 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -15,6 +15,7 @@
 
 from tempest.api.object_storage import base
 from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -24,14 +25,14 @@
         super(ContainerTest, self).tearDown()
 
     @test.attr(type='smoke')
-    @test.idempotent_id('92139d73-7819-4db1-85f8-3f2f22a8d91f')
+    @decorators.idempotent_id('92139d73-7819-4db1-85f8-3f2f22a8d91f')
     def test_create_container(self):
         container_name = data_utils.rand_name(name='TestContainer')
         resp, body = self.container_client.create_container(container_name)
         self.containers.append(container_name)
         self.assertHeaders(resp, 'Container', 'PUT')
 
-    @test.idempotent_id('49f866ed-d6af-4395-93e7-4187eb56d322')
+    @decorators.idempotent_id('49f866ed-d6af-4395-93e7-4187eb56d322')
     def test_create_container_overwrite(self):
         # overwrite container with the same name
         container_name = data_utils.rand_name(name='TestContainer')
@@ -41,7 +42,7 @@
         resp, _ = self.container_client.create_container(container_name)
         self.assertHeaders(resp, 'Container', 'PUT')
 
-    @test.idempotent_id('c2ac4d59-d0f5-40d5-ba19-0635056d48cd')
+    @decorators.idempotent_id('c2ac4d59-d0f5-40d5-ba19-0635056d48cd')
     def test_create_container_with_metadata_key(self):
         # create container with the blank value of metadata
         container_name = data_utils.rand_name(name='TestContainer')
@@ -58,7 +59,7 @@
         # in the server
         self.assertNotIn('x-container-meta-test-container-meta', resp)
 
-    @test.idempotent_id('e1e8df32-7b22-44e1-aa08-ccfd8d446b58')
+    @decorators.idempotent_id('e1e8df32-7b22-44e1-aa08-ccfd8d446b58')
     def test_create_container_with_metadata_value(self):
         # create container with metadata value
         container_name = data_utils.rand_name(name='TestContainer')
@@ -77,7 +78,7 @@
         self.assertEqual(resp['x-container-meta-test-container-meta'],
                          metadata['test_container_meta'])
 
-    @test.idempotent_id('24d16451-1c0c-4e4f-b59c-9840a3aba40e')
+    @decorators.idempotent_id('24d16451-1c0c-4e4f-b59c-9840a3aba40e')
     def test_create_container_with_remove_metadata_key(self):
         # create container with the blank value of remove metadata
         container_name = data_utils.rand_name(name='TestContainer')
@@ -97,7 +98,7 @@
             container_name)
         self.assertNotIn('x-container-meta-test-container-meta', resp)
 
-    @test.idempotent_id('8a21ebad-a5c7-4e29-b428-384edc8cd156')
+    @decorators.idempotent_id('8a21ebad-a5c7-4e29-b428-384edc8cd156')
     def test_create_container_with_remove_metadata_value(self):
         # create container with remove metadata
         container_name = data_utils.rand_name(name='TestContainer')
@@ -115,7 +116,7 @@
             container_name)
         self.assertNotIn('x-container-meta-test-container-meta', resp)
 
-    @test.idempotent_id('95d3a249-b702-4082-a2c4-14bb860cf06a')
+    @decorators.idempotent_id('95d3a249-b702-4082-a2c4-14bb860cf06a')
     def test_delete_container(self):
         # create a container
         container_name = self.create_container()
@@ -124,7 +125,7 @@
         self.assertHeaders(resp, 'Container', 'DELETE')
 
     @test.attr(type='smoke')
-    @test.idempotent_id('312ff6bd-5290-497f-bda1-7c5fec6697ab')
+    @decorators.idempotent_id('312ff6bd-5290-497f-bda1-7c5fec6697ab')
     def test_list_container_contents(self):
         # get container contents list
         container_name = self.create_container()
@@ -135,7 +136,7 @@
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual([object_name], object_list)
 
-    @test.idempotent_id('4646ac2d-9bfb-4c7d-a3c5-0f527402b3df')
+    @decorators.idempotent_id('4646ac2d-9bfb-4c7d-a3c5-0f527402b3df')
     def test_list_container_contents_with_no_object(self):
         # get empty container contents list
         container_name = self.create_container()
@@ -145,7 +146,7 @@
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEmpty(object_list)
 
-    @test.idempotent_id('fe323a32-57b9-4704-a996-2e68f83b09bc')
+    @decorators.idempotent_id('fe323a32-57b9-4704-a996-2e68f83b09bc')
     def test_list_container_contents_with_delimiter(self):
         # get container contents list using delimiter param
         container_name = self.create_container()
@@ -159,7 +160,7 @@
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual([object_name.split('/')[0] + '/'], object_list)
 
-    @test.idempotent_id('55b4fa5c-e12e-4ca9-8fcf-a79afe118522')
+    @decorators.idempotent_id('55b4fa5c-e12e-4ca9-8fcf-a79afe118522')
     def test_list_container_contents_with_end_marker(self):
         # get container contents list using end_marker param
         container_name = self.create_container()
@@ -172,7 +173,7 @@
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual([object_name], object_list)
 
-    @test.idempotent_id('196f5034-6ab0-4032-9da9-a937bbb9fba9')
+    @decorators.idempotent_id('196f5034-6ab0-4032-9da9-a937bbb9fba9')
     def test_list_container_contents_with_format_json(self):
         # get container contents list using format_json param
         container_name = self.create_container()
@@ -191,7 +192,7 @@
         self.assertTrue([c['content_type'] for c in object_list])
         self.assertTrue([c['last_modified'] for c in object_list])
 
-    @test.idempotent_id('655a53ca-4d15-408c-a377-f4c6dbd0a1fa')
+    @decorators.idempotent_id('655a53ca-4d15-408c-a377-f4c6dbd0a1fa')
     def test_list_container_contents_with_format_xml(self):
         # get container contents list using format_xml param
         container_name = self.create_container()
@@ -215,7 +216,7 @@
         self.assertEqual(object_list.find(".//last_modified").tag,
                          'last_modified')
 
-    @test.idempotent_id('297ec38b-2b61-4ff4-bcd1-7fa055e97b61')
+    @decorators.idempotent_id('297ec38b-2b61-4ff4-bcd1-7fa055e97b61')
     def test_list_container_contents_with_limit(self):
         # get container contents list using limit param
         container_name = self.create_container()
@@ -228,7 +229,7 @@
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual([object_name], object_list)
 
-    @test.idempotent_id('c31ddc63-2a58-4f6b-b25c-94d2937e6867')
+    @decorators.idempotent_id('c31ddc63-2a58-4f6b-b25c-94d2937e6867')
     def test_list_container_contents_with_marker(self):
         # get container contents list using marker param
         container_name = self.create_container()
@@ -241,7 +242,7 @@
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual([object_name], object_list)
 
-    @test.idempotent_id('58ca6cc9-6af0-408d-aaec-2a6a7b2f0df9')
+    @decorators.idempotent_id('58ca6cc9-6af0-408d-aaec-2a6a7b2f0df9')
     def test_list_container_contents_with_path(self):
         # get container contents list using path param
         container_name = self.create_container()
@@ -255,7 +256,7 @@
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual([object_name], object_list)
 
-    @test.idempotent_id('77e742c7-caf2-4ec9-8aa4-f7d509a3344c')
+    @decorators.idempotent_id('77e742c7-caf2-4ec9-8aa4-f7d509a3344c')
     def test_list_container_contents_with_prefix(self):
         # get container contents list using prefix param
         container_name = self.create_container()
@@ -270,7 +271,7 @@
         self.assertEqual([object_name], object_list)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('96e68f0e-19ec-4aa2-86f3-adc6a45e14dd')
+    @decorators.idempotent_id('96e68f0e-19ec-4aa2-86f3-adc6a45e14dd')
     def test_list_container_metadata(self):
         # List container metadata
         container_name = self.create_container()
@@ -286,7 +287,7 @@
         self.assertIn('x-container-meta-name', resp)
         self.assertEqual(resp['x-container-meta-name'], metadata['name'])
 
-    @test.idempotent_id('a2faf936-6b13-4f8d-92a2-c2278355821e')
+    @decorators.idempotent_id('a2faf936-6b13-4f8d-92a2-c2278355821e')
     def test_list_no_container_metadata(self):
         # HEAD container without metadata
         container_name = self.create_container()
@@ -296,7 +297,7 @@
         self.assertHeaders(resp, 'Container', 'HEAD')
         self.assertNotIn('x-container-meta-', str(resp))
 
-    @test.idempotent_id('cf19bc0b-7e16-4a5a-aaed-cb0c2fe8deef')
+    @decorators.idempotent_id('cf19bc0b-7e16-4a5a-aaed-cb0c2fe8deef')
     def test_update_container_metadata_with_create_and_delete_metadata(self):
         # Send one request of adding and deleting metadata
         container_name = data_utils.rand_name(name='TestContainer')
@@ -319,7 +320,7 @@
         self.assertEqual(resp['x-container-meta-test-container-meta2'],
                          metadata_2['test-container-meta2'])
 
-    @test.idempotent_id('2ae5f295-4bf1-4e04-bfad-21e54b62cec5')
+    @decorators.idempotent_id('2ae5f295-4bf1-4e04-bfad-21e54b62cec5')
     def test_update_container_metadata_with_create_metadata(self):
         # update container metadata using add metadata
         container_name = self.create_container()
@@ -336,7 +337,7 @@
         self.assertEqual(resp['x-container-meta-test-container-meta1'],
                          metadata['test-container-meta1'])
 
-    @test.idempotent_id('3a5ce7d4-6e4b-47d0-9d87-7cd42c325094')
+    @decorators.idempotent_id('3a5ce7d4-6e4b-47d0-9d87-7cd42c325094')
     def test_update_container_metadata_with_delete_metadata(self):
         # update container metadata using delete metadata
         container_name = data_utils.rand_name(name='TestContainer')
@@ -354,7 +355,7 @@
             container_name)
         self.assertNotIn('x-container-meta-test-container-meta1', resp)
 
-    @test.idempotent_id('31f40a5f-6a52-4314-8794-cd89baed3040')
+    @decorators.idempotent_id('31f40a5f-6a52-4314-8794-cd89baed3040')
     def test_update_container_metadata_with_create_metadata_key(self):
         # update container metadata with a blank value of metadata
         container_name = self.create_container()
@@ -369,7 +370,7 @@
             container_name)
         self.assertNotIn('x-container-meta-test-container-meta1', resp)
 
-    @test.idempotent_id('a2e36378-6f1f-43f4-840a-ffd9cfd61914')
+    @decorators.idempotent_id('a2e36378-6f1f-43f4-840a-ffd9cfd61914')
     def test_update_container_metadata_with_delete_metadata_key(self):
         # update container metadata with a blank value of metadata
         container_name = data_utils.rand_name(name='TestContainer')
diff --git a/tempest/api/object_storage/test_container_services_negative.py b/tempest/api/object_storage/test_container_services_negative.py
index 2856fab..be066ba 100644
--- a/tempest/api/object_storage/test_container_services_negative.py
+++ b/tempest/api/object_storage/test_container_services_negative.py
@@ -18,6 +18,7 @@
 from tempest.api.object_storage import base
 from tempest import config
 from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions
 from tempest import test
 
@@ -36,7 +37,7 @@
             cls.constraints = body['swift']
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('30686921-4bed-4764-a038-40d741ed4e78')
+    @decorators.idempotent_id('30686921-4bed-4764-a038-40d741ed4e78')
     @testtools.skipUnless(
         CONF.object_storage_feature_enabled.discoverability,
         'Discoverability function is disabled')
@@ -52,7 +53,7 @@
                       ' longer than ' + str(max_length), str(ex))
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('41e645bf-2e68-4f84-bf7b-c71aa5cd76ce')
+    @decorators.idempotent_id('41e645bf-2e68-4f84-bf7b-c71aa5cd76ce')
     @testtools.skipUnless(
         CONF.object_storage_feature_enabled.discoverability,
         'Discoverability function is disabled')
@@ -69,7 +70,7 @@
         self.assertIn('Metadata name too long', str(ex))
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('81e36922-326b-4b7c-8155-3bbceecd7a82')
+    @decorators.idempotent_id('81e36922-326b-4b7c-8155-3bbceecd7a82')
     @testtools.skipUnless(
         CONF.object_storage_feature_enabled.discoverability,
         'Discoverability function is disabled')
@@ -86,7 +87,7 @@
         self.assertIn('Metadata value longer than ' + str(max_length), str(ex))
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('ac666539-d566-4f02-8ceb-58e968dfb732')
+    @decorators.idempotent_id('ac666539-d566-4f02-8ceb-58e968dfb732')
     @testtools.skipUnless(
         CONF.object_storage_feature_enabled.discoverability,
         'Discoverability function is disabled')
@@ -106,7 +107,7 @@
                       str(ex))
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('1a95ab2e-b712-4a98-8a4d-8ce21b7557d6')
+    @decorators.idempotent_id('1a95ab2e-b712-4a98-8a4d-8ce21b7557d6')
     def test_get_metadata_headers_with_invalid_container_name(self):
         # Attempts to retrieve metadata headers with an invalid
         # container name.
@@ -115,7 +116,7 @@
                           'invalid_container_name')
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('125a24fa-90a7-4cfc-b604-44e49d788390')
+    @decorators.idempotent_id('125a24fa-90a7-4cfc-b604-44e49d788390')
     def test_update_metadata_with_nonexistent_container_name(self):
         # Attempts to update metadata using a nonexistent container name.
         metadata = {'animal': 'penguin'}
@@ -125,7 +126,7 @@
                           'nonexistent_container_name', metadata)
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('65387dbf-a0e2-4aac-9ddc-16eb3f1f69ba')
+    @decorators.idempotent_id('65387dbf-a0e2-4aac-9ddc-16eb3f1f69ba')
     def test_delete_with_nonexistent_container_name(self):
         # Attempts to delete metadata using a nonexistent container name.
         metadata = {'animal': 'penguin'}
@@ -135,7 +136,7 @@
                           'nonexistent_container_name', metadata)
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('14331d21-1e81-420a-beea-19cb5e5207f5')
+    @decorators.idempotent_id('14331d21-1e81-420a-beea-19cb5e5207f5')
     def test_list_all_container_objects_with_nonexistent_container(self):
         # Attempts to get a listing of all objects on a container
         # that doesn't exist.
@@ -145,7 +146,7 @@
                           'nonexistent_container_name', params)
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('86b2ab08-92d5-493d-acd2-85f0c848819e')
+    @decorators.idempotent_id('86b2ab08-92d5-493d-acd2-85f0c848819e')
     def test_list_all_container_objects_on_deleted_container(self):
         # Attempts to get a listing of all objects on a container
         # that was deleted.
@@ -159,7 +160,7 @@
                           container_name, params)
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('42da116e-1e8c-4c96-9e06-2f13884ed2b1')
+    @decorators.idempotent_id('42da116e-1e8c-4c96-9e06-2f13884ed2b1')
     def test_delete_non_empty_container(self):
         # create a container and an object within it
         # attempt to delete a container that isn't empty.
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index edc9271..a280248 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -15,6 +15,7 @@
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -43,7 +44,7 @@
         cls.delete_containers()
         super(StaticWebTest, cls).resource_cleanup()
 
-    @test.idempotent_id('c1f055ab-621d-4a6a-831f-846fcb578b8b')
+    @decorators.idempotent_id('c1f055ab-621d-4a6a-831f-846fcb578b8b')
     @test.requires_ext(extension='staticweb', service='object')
     def test_web_index(self):
         headers = {'web-index': self.object_name}
@@ -74,7 +75,7 @@
             self.container_name)
         self.assertNotIn('x-container-meta-web-index', body)
 
-    @test.idempotent_id('941814cf-db9e-4b21-8112-2b6d0af10ee5')
+    @decorators.idempotent_id('941814cf-db9e-4b21-8112-2b6d0af10ee5')
     @test.requires_ext(extension='staticweb', service='object')
     def test_web_listing(self):
         headers = {'web-listings': 'true'}
@@ -106,7 +107,7 @@
             self.container_name)
         self.assertNotIn('x-container-meta-web-listings', body)
 
-    @test.idempotent_id('bc37ec94-43c8-4990-842e-0e5e02fc8926')
+    @decorators.idempotent_id('bc37ec94-43c8-4990-842e-0e5e02fc8926')
     @test.requires_ext(extension='staticweb', service='object')
     def test_web_listing_css(self):
         headers = {'web-listings': 'true',
@@ -130,7 +131,7 @@
         css = '<link rel="stylesheet" type="text/css" href="listings.css" />'
         self.assertIn(css, body.decode())
 
-    @test.idempotent_id('f18b4bef-212e-45e7-b3ca-59af3a465f82')
+    @decorators.idempotent_id('f18b4bef-212e-45e7-b3ca-59af3a465f82')
     @test.requires_ext(extension='staticweb', service='object')
     def test_web_error(self):
         headers = {'web-listings': 'true',
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index f134335..63fb93d 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -131,7 +131,7 @@
 
     @test.attr(type='slow')
     @decorators.skip_because(bug='1317133')
-    @test.idempotent_id('be008325-1bba-4925-b7dd-93b58f22ce9b')
+    @decorators.idempotent_id('be008325-1bba-4925-b7dd-93b58f22ce9b')
     @testtools.skipIf(
         not CONF.object_storage_feature_enabled.container_sync,
         'Old-style container sync function is disabled')
diff --git a/tempest/api/object_storage/test_container_sync_middleware.py b/tempest/api/object_storage/test_container_sync_middleware.py
index 4491a84..df738b3 100644
--- a/tempest/api/object_storage/test_container_sync_middleware.py
+++ b/tempest/api/object_storage/test_container_sync_middleware.py
@@ -14,6 +14,7 @@
 
 from tempest.api.object_storage import test_container_sync
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -37,7 +38,7 @@
         cls.cluster_name = CONF.object_storage.cluster_name
 
     @test.attr(type='slow')
-    @test.idempotent_id('ea4645a1-d147-4976-82f7-e5a7a3065f80')
+    @decorators.idempotent_id('ea4645a1-d147-4976-82f7-e5a7a3065f80')
     @test.requires_ext(extension='container_sync', service='object')
     def test_container_synchronization(self):
         def make_headers(cont, cont_client):
diff --git a/tempest/api/object_storage/test_crossdomain.py b/tempest/api/object_storage/test_crossdomain.py
index 18dc254..c47aa93 100644
--- a/tempest/api/object_storage/test_crossdomain.py
+++ b/tempest/api/object_storage/test_crossdomain.py
@@ -14,6 +14,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -36,7 +37,7 @@
         # Turning http://.../v1/foobar into http://.../
         self.account_client.skip_path()
 
-    @test.idempotent_id('d1b8b031-b622-4010-82f9-ff78a9e915c7')
+    @decorators.idempotent_id('d1b8b031-b622-4010-82f9-ff78a9e915c7')
     @test.requires_ext(extension='crossdomain', service='object')
     def test_get_crossdomain_policy(self):
         resp, body = self.account_client.get("crossdomain.xml", {})
diff --git a/tempest/api/object_storage/test_healthcheck.py b/tempest/api/object_storage/test_healthcheck.py
index 104253a..a186f9e 100644
--- a/tempest/api/object_storage/test_healthcheck.py
+++ b/tempest/api/object_storage/test_healthcheck.py
@@ -15,7 +15,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
-from tempest import test
+from tempest.lib import decorators
 
 
 class HealthcheckTest(base.BaseObjectTest):
@@ -25,7 +25,7 @@
         # Turning http://.../v1/foobar into http://.../
         self.account_client.skip_path()
 
-    @test.idempotent_id('db5723b1-f25c-49a9-bfeb-7b5640caf337')
+    @decorators.idempotent_id('db5723b1-f25c-49a9-bfeb-7b5640caf337')
     def test_get_healthcheck(self):
 
         resp, _ = self.account_client.get("healthcheck", {})
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index 11acb31..7768d23 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -16,8 +16,8 @@
 import time
 
 from tempest.api.object_storage import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 
 class ObjectExpiryTest(base.BaseObjectTest):
@@ -81,14 +81,14 @@
                           self.container_name,
                           self.object_name)
 
-    @test.idempotent_id('fb024a42-37f3-4ba5-9684-4f40a7910b41')
+    @decorators.idempotent_id('fb024a42-37f3-4ba5-9684-4f40a7910b41')
     def test_get_object_after_expiry_time(self):
         # the 10s is important, because the get calls can take 3s each
         # some times
         metadata = {'X-Delete-After': '10'}
         self._test_object_expiry(metadata)
 
-    @test.idempotent_id('e592f18d-679c-48fe-9e36-4be5f47102c5')
+    @decorators.idempotent_id('e592f18d-679c-48fe-9e36-4be5f47102c5')
     def test_get_object_at_expiry_time(self):
         metadata = {'X-Delete-At': str(int(time.time()) + 10)}
         self._test_object_expiry(metadata)
diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py
index 0a87a64..2829ac7 100644
--- a/tempest/api/object_storage/test_object_formpost.py
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -20,6 +20,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -104,7 +105,7 @@
         content_type = 'multipart/form-data; boundary=%s' % boundary
         return body, content_type
 
-    @test.idempotent_id('80fac02b-6e54-4f7b-be0d-a965b5cbef76')
+    @decorators.idempotent_id('80fac02b-6e54-4f7b-be0d-a965b5cbef76')
     @test.requires_ext(extension='formpost', service='object')
     def test_post_object_using_form(self):
         body, content_type = self.get_multipart_form()
diff --git a/tempest/api/object_storage/test_object_formpost_negative.py b/tempest/api/object_storage/test_object_formpost_negative.py
index f193111..2174940 100644
--- a/tempest/api/object_storage/test_object_formpost_negative.py
+++ b/tempest/api/object_storage/test_object_formpost_negative.py
@@ -20,6 +20,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -105,7 +106,7 @@
         content_type = 'multipart/form-data; boundary=%s' % boundary
         return body, content_type
 
-    @test.idempotent_id('d3fb3c4d-e627-48ce-9379-a1631f21336d')
+    @decorators.idempotent_id('d3fb3c4d-e627-48ce-9379-a1631f21336d')
     @test.requires_ext(extension='formpost', service='object')
     @test.attr(type=['negative'])
     def test_post_object_using_form_expired(self):
@@ -122,7 +123,7 @@
             url, body, headers=headers)
         self.assertIn('FormPost: Form Expired', str(exc))
 
-    @test.idempotent_id('b277257f-113c-4499-b8d1-5fead79f7360')
+    @decorators.idempotent_id('b277257f-113c-4499-b8d1-5fead79f7360')
     @test.requires_ext(extension='formpost', service='object')
     def test_post_object_using_form_invalid_signature(self):
         self.key = "Wrong"
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 7716bdb..58fd822 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -23,6 +23,7 @@
 from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -75,7 +76,7 @@
                 self.assertNotIn('x-object-meta-' + meta_key, resp)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('5b4ce26f-3545-46c9-a2ba-5754358a4c62')
+    @decorators.idempotent_id('5b4ce26f-3545-46c9-a2ba-5754358a4c62')
     def test_create_object(self):
         # create object
         object_name = data_utils.rand_name(name='TestObject')
@@ -94,7 +95,7 @@
                                                 object_name)
         self.assertEqual(data, body)
 
-    @test.idempotent_id('5daebb1d-f0d5-4dc9-b541-69672eff00b0')
+    @decorators.idempotent_id('5daebb1d-f0d5-4dc9-b541-69672eff00b0')
     def test_create_object_with_content_disposition(self):
         # create object with content_disposition
         object_name = data_utils.rand_name(name='TestObject')
@@ -116,7 +117,7 @@
         self.assertEqual(resp['content-disposition'], 'inline')
         self.assertEqual(body, data)
 
-    @test.idempotent_id('605f8317-f945-4bee-ae91-013f1da8f0a0')
+    @decorators.idempotent_id('605f8317-f945-4bee-ae91-013f1da8f0a0')
     def test_create_object_with_content_encoding(self):
         # create object with content_encoding
         object_name = data_utils.rand_name(name='TestObject')
@@ -143,7 +144,7 @@
             metadata=metadata)
         self.assertEqual(body, data_before)
 
-    @test.idempotent_id('73820093-0503-40b1-a478-edf0e69c7d1f')
+    @decorators.idempotent_id('73820093-0503-40b1-a478-edf0e69c7d1f')
     def test_create_object_with_etag(self):
         # create object with etag
         object_name = data_utils.rand_name(name='TestObject')
@@ -162,7 +163,7 @@
                                                 object_name)
         self.assertEqual(data, body)
 
-    @test.idempotent_id('84dafe57-9666-4f6d-84c8-0814d37923b8')
+    @decorators.idempotent_id('84dafe57-9666-4f6d-84c8-0814d37923b8')
     def test_create_object_with_expect_continue(self):
         # create object with expect_continue
 
@@ -179,7 +180,7 @@
                                                 object_name)
         self.assertEqual(data, body)
 
-    @test.idempotent_id('4f84422a-e2f2-4403-b601-726a4220b54e')
+    @decorators.idempotent_id('4f84422a-e2f2-4403-b601-726a4220b54e')
     def test_create_object_with_transfer_encoding(self):
         # create object with transfer_encoding
         object_name = data_utils.rand_name(name='TestObject')
@@ -196,7 +197,7 @@
                                                 object_name)
         self.assertEqual(data, body)
 
-    @test.idempotent_id('0f3d62a6-47e3-4554-b0e5-1a5dc372d501')
+    @decorators.idempotent_id('0f3d62a6-47e3-4554-b0e5-1a5dc372d501')
     def test_create_object_with_x_fresh_metadata(self):
         # create object with x_fresh_metadata
         object_name_base = data_utils.rand_name(name='TestObject')
@@ -222,7 +223,7 @@
         self.assertNotIn('x-object-meta-test-meta', resp)
         self.assertEqual(data, body)
 
-    @test.idempotent_id('1c7ed3e4-2099-406b-b843-5301d4811baf')
+    @decorators.idempotent_id('1c7ed3e4-2099-406b-b843-5301d4811baf')
     def test_create_object_with_x_object_meta(self):
         # create object with object_meta
         object_name = data_utils.rand_name(name='TestObject')
@@ -241,7 +242,7 @@
         self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
         self.assertEqual(data, body)
 
-    @test.idempotent_id('e4183917-33db-4153-85cc-4dacbb938865')
+    @decorators.idempotent_id('e4183917-33db-4153-85cc-4dacbb938865')
     def test_create_object_with_x_object_metakey(self):
         # create object with the blank value of metadata
         object_name = data_utils.rand_name(name='TestObject')
@@ -260,7 +261,7 @@
         self.assertEqual(resp['x-object-meta-test-meta'], '')
         self.assertEqual(data, body)
 
-    @test.idempotent_id('ce798afc-b278-45de-a5ce-2ea124b98b99')
+    @decorators.idempotent_id('ce798afc-b278-45de-a5ce-2ea124b98b99')
     def test_create_object_with_x_remove_object_meta(self):
         # create object with x_remove_object_meta
         object_name = data_utils.rand_name(name='TestObject')
@@ -283,7 +284,7 @@
         self.assertNotIn('x-object-meta-test-meta', resp)
         self.assertEqual(data, body)
 
-    @test.idempotent_id('ad21e342-7916-4f9e-ab62-a1f885f2aaf9')
+    @decorators.idempotent_id('ad21e342-7916-4f9e-ab62-a1f885f2aaf9')
     def test_create_object_with_x_remove_object_metakey(self):
         # create object with the blank value of remove metadata
         object_name = data_utils.rand_name(name='TestObject')
@@ -306,7 +307,7 @@
         self.assertNotIn('x-object-meta-test-meta', resp)
         self.assertEqual(data, body)
 
-    @test.idempotent_id('17738d45-03bd-4d45-9e0b-7b2f58f98687')
+    @decorators.idempotent_id('17738d45-03bd-4d45-9e0b-7b2f58f98687')
     def test_delete_object(self):
         # create object
         object_name = data_utils.rand_name(name='TestObject')
@@ -319,7 +320,7 @@
         self.assertHeaders(resp, 'Object', 'DELETE')
 
     @test.attr(type='smoke')
-    @test.idempotent_id('7a94c25d-66e6-434c-9c38-97d4e2c29945')
+    @decorators.idempotent_id('7a94c25d-66e6-434c-9c38-97d4e2c29945')
     def test_update_object_metadata(self):
         # update object metadata
         object_name, _ = self.create_object(self.container_name)
@@ -338,7 +339,7 @@
         self.assertIn('x-object-meta-test-meta', resp)
         self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
 
-    @test.idempotent_id('48650ed0-c189-4e1e-ad6b-1d4770c6e134')
+    @decorators.idempotent_id('48650ed0-c189-4e1e-ad6b-1d4770c6e134')
     def test_update_object_metadata_with_remove_metadata(self):
         # update object metadata with remove metadata
         object_name = data_utils.rand_name(name='TestObject')
@@ -362,7 +363,7 @@
             object_name)
         self.assertNotIn('x-object-meta-test-meta1', resp)
 
-    @test.idempotent_id('f726174b-2ded-4708-bff7-729d12ce1f84')
+    @decorators.idempotent_id('f726174b-2ded-4708-bff7-729d12ce1f84')
     def test_update_object_metadata_with_create_and_remove_metadata(self):
         # creation and deletion of metadata with one request
         object_name = data_utils.rand_name(name='TestObject')
@@ -389,7 +390,7 @@
         self.assertIn('x-object-meta-test-meta2', resp)
         self.assertEqual(resp['x-object-meta-test-meta2'], 'Meta2')
 
-    @test.idempotent_id('08854588-6449-4bb7-8cca-f2e1040f5e6f')
+    @decorators.idempotent_id('08854588-6449-4bb7-8cca-f2e1040f5e6f')
     def test_update_object_metadata_with_x_object_manifest(self):
         # update object metadata with x_object_manifest
 
@@ -416,7 +417,7 @@
         self.assertIn('x-object-manifest', resp)
         self.assertNotEqual(len(resp['x-object-manifest']), 0)
 
-    @test.idempotent_id('0dbbe89c-6811-4d84-a2df-eca2bdd40c0e')
+    @decorators.idempotent_id('0dbbe89c-6811-4d84-a2df-eca2bdd40c0e')
     def test_update_object_metadata_with_x_object_metakey(self):
         # update object metadata with a blank value of metadata
         object_name, _ = self.create_object(self.container_name)
@@ -435,7 +436,7 @@
         self.assertIn('x-object-meta-test-meta', resp)
         self.assertEqual(resp['x-object-meta-test-meta'], '')
 
-    @test.idempotent_id('9a88dca4-b684-425b-806f-306cd0e57e42')
+    @decorators.idempotent_id('9a88dca4-b684-425b-806f-306cd0e57e42')
     def test_update_object_metadata_with_x_remove_object_metakey(self):
         # update object metadata with a blank value of remove metadata
         object_name = data_utils.rand_name(name='TestObject')
@@ -460,7 +461,7 @@
         self.assertNotIn('x-object-meta-test-meta', resp)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('9a447cf6-de06-48de-8226-a8c6ed31caf2')
+    @decorators.idempotent_id('9a447cf6-de06-48de-8226-a8c6ed31caf2')
     def test_list_object_metadata(self):
         # get object metadata
         object_name = data_utils.rand_name(name='TestObject')
@@ -478,7 +479,7 @@
         self.assertIn('x-object-meta-test-meta', resp)
         self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
 
-    @test.idempotent_id('170fb90e-f5c3-4b1f-ae1b-a18810821172')
+    @decorators.idempotent_id('170fb90e-f5c3-4b1f-ae1b-a18810821172')
     def test_list_no_object_metadata(self):
         # get empty list of object metadata
         object_name, _ = self.create_object(self.container_name)
@@ -489,7 +490,7 @@
         self.assertHeaders(resp, 'Object', 'HEAD')
         self.assertNotIn('x-object-meta-', str(resp))
 
-    @test.idempotent_id('23a3674c-d6de-46c3-86af-ff92bfc8a3da')
+    @decorators.idempotent_id('23a3674c-d6de-46c3-86af-ff92bfc8a3da')
     def test_list_object_metadata_with_x_object_manifest(self):
         # get object metadata with x_object_manifest
 
@@ -530,7 +531,7 @@
                          '%s/%s' % (self.container_name, object_name))
 
     @test.attr(type='smoke')
-    @test.idempotent_id('02610ba7-86b7-4272-9ed8-aa8d417cb3cd')
+    @decorators.idempotent_id('02610ba7-86b7-4272-9ed8-aa8d417cb3cd')
     def test_get_object(self):
         # retrieve object's data (in response body)
 
@@ -543,7 +544,7 @@
 
         self.assertEqual(body, data)
 
-    @test.idempotent_id('005f9bf6-e06d-41ec-968e-96c78e0b1d82')
+    @decorators.idempotent_id('005f9bf6-e06d-41ec-968e-96c78e0b1d82')
     def test_get_object_with_metadata(self):
         # get object with metadata
         object_name = data_utils.rand_name(name='TestObject')
@@ -562,7 +563,7 @@
         self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
         self.assertEqual(body, data)
 
-    @test.idempotent_id('05a1890e-7db9-4a6c-90a8-ce998a2bddfa')
+    @decorators.idempotent_id('05a1890e-7db9-4a6c-90a8-ce998a2bddfa')
     def test_get_object_with_range(self):
         # get object with range
         object_name = data_utils.rand_name(name='TestObject')
@@ -580,7 +581,7 @@
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, data[rand_num - 3: rand_num])
 
-    @test.idempotent_id('11b4515b-7ba7-4ca8-8838-357ded86fc10')
+    @decorators.idempotent_id('11b4515b-7ba7-4ca8-8838-357ded86fc10')
     def test_get_object_with_x_object_manifest(self):
         # get object with x_object_manifest
 
@@ -623,7 +624,7 @@
 
         self.assertEqual(''.join(data_segments), body.decode())
 
-    @test.idempotent_id('c05b4013-e4de-47af-be84-e598062b16fc')
+    @decorators.idempotent_id('c05b4013-e4de-47af-be84-e598062b16fc')
     def test_get_object_with_if_match(self):
         # get object with if_match
         object_name = data_utils.rand_name(name='TestObject')
@@ -643,7 +644,7 @@
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, data)
 
-    @test.idempotent_id('be133639-e5d2-4313-9b1f-2d59fc054a16')
+    @decorators.idempotent_id('be133639-e5d2-4313-9b1f-2d59fc054a16')
     def test_get_object_with_if_modified_since(self):
         # get object with if_modified_since
         object_name = data_utils.rand_name(name='TestObject')
@@ -663,7 +664,7 @@
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, data)
 
-    @test.idempotent_id('641500d5-1612-4042-a04d-01fc4528bc30')
+    @decorators.idempotent_id('641500d5-1612-4042-a04d-01fc4528bc30')
     def test_get_object_with_if_none_match(self):
         # get object with if_none_match
         object_name = data_utils.rand_name(name='TestObject')
@@ -685,7 +686,7 @@
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, data)
 
-    @test.idempotent_id('0aa1201c-10aa-467a-bee7-63cbdd463152')
+    @decorators.idempotent_id('0aa1201c-10aa-467a-bee7-63cbdd463152')
     def test_get_object_with_if_unmodified_since(self):
         # get object with if_unmodified_since
         object_name, data = self.create_object(self.container_name)
@@ -700,7 +701,7 @@
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, data)
 
-    @test.idempotent_id('94587078-475f-48f9-a40f-389c246e31cd')
+    @decorators.idempotent_id('94587078-475f-48f9-a40f-389c246e31cd')
     def test_get_object_with_x_newest(self):
         # get object with x_newest
         object_name, data = self.create_object(self.container_name)
@@ -713,7 +714,7 @@
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, data)
 
-    @test.idempotent_id('1a9ab572-1b66-4981-8c21-416e2a5e6011')
+    @decorators.idempotent_id('1a9ab572-1b66-4981-8c21-416e2a5e6011')
     def test_copy_object_in_same_container(self):
         # create source object
         src_object_name = data_utils.rand_name(name='SrcObject')
@@ -737,7 +738,7 @@
                                                    dst_object_name)
         self.assertEqual(body, src_data)
 
-    @test.idempotent_id('2248abba-415d-410b-9c30-22dff9cd6e67')
+    @decorators.idempotent_id('2248abba-415d-410b-9c30-22dff9cd6e67')
     def test_copy_object_to_itself(self):
         # change the content type of an existing object
 
@@ -758,7 +759,7 @@
                                                           object_name)
         self.assertEqual(resp['content-type'], metadata['content-type'])
 
-    @test.idempotent_id('06f90388-2d0e-40aa-934c-e9a8833e958a')
+    @decorators.idempotent_id('06f90388-2d0e-40aa-934c-e9a8833e958a')
     def test_copy_object_2d_way(self):
         # create source object
         src_object_name = data_utils.rand_name(name='SrcObject')
@@ -782,7 +783,7 @@
         # check data
         self._check_copied_obj(dst_object_name, src_data)
 
-    @test.idempotent_id('aa467252-44f3-472a-b5ae-5b57c3c9c147')
+    @decorators.idempotent_id('aa467252-44f3-472a-b5ae-5b57c3c9c147')
     def test_copy_object_across_containers(self):
         # create a container to use as a source container
         src_container_name = data_utils.rand_name(name='TestSourceContainer')
@@ -821,7 +822,7 @@
         self.assertIn(actual_meta_key, resp)
         self.assertEqual(resp[actual_meta_key], meta_value)
 
-    @test.idempotent_id('5a9e2cc6-85b6-46fc-916d-0cbb7a88e5fd')
+    @decorators.idempotent_id('5a9e2cc6-85b6-46fc-916d-0cbb7a88e5fd')
     def test_copy_object_with_x_fresh_metadata(self):
         # create source object
         metadata = {'x-object-meta-src': 'src_value'}
@@ -842,7 +843,7 @@
         # check that destination object does NOT have any object-meta
         self._check_copied_obj(dst_object_name, data, not_in_meta=["src"])
 
-    @test.idempotent_id('a28a8b99-e701-4d7e-9d84-3b66f121460b')
+    @decorators.idempotent_id('a28a8b99-e701-4d7e-9d84-3b66f121460b')
     def test_copy_object_with_x_object_metakey(self):
         # create source object
         metadata = {'x-object-meta-src': 'src_value'}
@@ -865,7 +866,7 @@
         # check destination object
         self._check_copied_obj(dst_obj_name, data, in_meta=["test", "src"])
 
-    @test.idempotent_id('edabedca-24c3-4322-9b70-d6d9f942a074')
+    @decorators.idempotent_id('edabedca-24c3-4322-9b70-d6d9f942a074')
     def test_copy_object_with_x_object_meta(self):
         # create source object
         metadata = {'x-object-meta-src': 'src_value'}
@@ -888,7 +889,7 @@
         # check destination object
         self._check_copied_obj(dst_obj_name, data, in_meta=["test", "src"])
 
-    @test.idempotent_id('e3e6a64a-9f50-4955-b987-6ce6767c97fb')
+    @decorators.idempotent_id('e3e6a64a-9f50-4955-b987-6ce6767c97fb')
     def test_object_upload_in_segments(self):
         # create object
         object_name = data_utils.rand_name(name='LObject')
@@ -930,7 +931,7 @@
             self.container_name, object_name)
         self.assertEqual(''.join(data_segments), body.decode())
 
-    @test.idempotent_id('50d01f12-526f-4360-9ac2-75dd508d7b68')
+    @decorators.idempotent_id('50d01f12-526f-4360-9ac2-75dd508d7b68')
     def test_get_object_if_different(self):
         # http://en.wikipedia.org/wiki/HTTP_ETag
         # Make a conditional request for an object using the If-None-Match
@@ -984,7 +985,7 @@
         self.delete_containers([self.container_name])
         super(PublicObjectTest, self).tearDown()
 
-    @test.idempotent_id('07c9cf95-c0d4-4b49-b9c8-0ef2c9b27193')
+    @decorators.idempotent_id('07c9cf95-c0d4-4b49-b9c8-0ef2c9b27193')
     def test_access_public_container_object_without_using_creds(self):
         # make container public-readable and access an object in it object
         # anonymously, without using credentials
@@ -1021,7 +1022,7 @@
 
         self.assertEqual(body, data)
 
-    @test.idempotent_id('54e2a2fe-42dc-491b-8270-8e4217dd4cdc')
+    @decorators.idempotent_id('54e2a2fe-42dc-491b-8270-8e4217dd4cdc')
     def test_access_public_object_with_another_user_creds(self):
         # make container public-readable and access an object in it using
         # another user's credentials
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index f9c1148..8ed9bf8 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -20,6 +20,7 @@
 from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest import test
 
 # Each segment, except for the final one, must be at least 1 megabyte
@@ -105,7 +106,7 @@
         resp['etag'] = resp['etag'].strip('"')
         self.assertHeaders(resp, 'Object', method)
 
-    @test.idempotent_id('2c3f24a6-36e8-4711-9aa2-800ee1fc7b5b')
+    @decorators.idempotent_id('2c3f24a6-36e8-4711-9aa2-800ee1fc7b5b')
     @test.requires_ext(extension='slo', service='object')
     def test_upload_manifest(self):
         # create static large object from multipart manifest
@@ -120,7 +121,7 @@
 
         self._assertHeadersSLO(resp, 'PUT')
 
-    @test.idempotent_id('e69ad766-e1aa-44a2-bdd2-bf62c09c1456')
+    @decorators.idempotent_id('e69ad766-e1aa-44a2-bdd2-bf62c09c1456')
     @test.requires_ext(extension='slo', service='object')
     def test_list_large_object_metadata(self):
         # list static large object metadata using multipart manifest
@@ -132,7 +133,7 @@
 
         self._assertHeadersSLO(resp, 'HEAD')
 
-    @test.idempotent_id('49bc49bc-dd1b-4c0f-904e-d9f10b830ee8')
+    @decorators.idempotent_id('49bc49bc-dd1b-4c0f-904e-d9f10b830ee8')
     @test.requires_ext(extension='slo', service='object')
     def test_retrieve_large_object(self):
         # list static large object using multipart manifest
@@ -147,7 +148,7 @@
         sum_data = self.content + self.content
         self.assertEqual(body, sum_data)
 
-    @test.idempotent_id('87b6dfa1-abe9-404d-8bf0-6c3751e6aa77')
+    @decorators.idempotent_id('87b6dfa1-abe9-404d-8bf0-6c3751e6aa77')
     @test.requires_ext(extension='slo', service='object')
     def test_delete_large_object(self):
         # delete static large object using multipart manifest
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index bd0d213..5e3c9f7 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -20,6 +20,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -85,7 +86,7 @@
 
         return url
 
-    @test.idempotent_id('f91c96d4-1230-4bba-8eb9-84476d18d991')
+    @decorators.idempotent_id('f91c96d4-1230-4bba-8eb9-84476d18d991')
     @test.requires_ext(extension='tempurl', service='object')
     def test_get_object_using_temp_url(self):
         expires = self._get_expiry_date()
@@ -104,7 +105,7 @@
         resp, body = self.object_client.head(url)
         self.assertHeaders(resp, 'Object', 'HEAD')
 
-    @test.idempotent_id('671f9583-86bd-4128-a034-be282a68c5d8')
+    @decorators.idempotent_id('671f9583-86bd-4128-a034-be282a68c5d8')
     @test.requires_ext(extension='tempurl', service='object')
     def test_get_object_using_temp_url_key_2(self):
         key2 = 'Meta2-'
@@ -128,7 +129,7 @@
         resp, body = self.object_client.get(url)
         self.assertEqual(body, self.content)
 
-    @test.idempotent_id('9b08dade-3571-4152-8a4f-a4f2a873a735')
+    @decorators.idempotent_id('9b08dade-3571-4152-8a4f-a4f2a873a735')
     @test.requires_ext(extension='tempurl', service='object')
     def test_put_object_using_temp_url(self):
         new_data = data_utils.random_bytes(size=len(self.object_name))
@@ -154,7 +155,7 @@
         _, body = self.object_client.get(url)
         self.assertEqual(body, new_data)
 
-    @test.idempotent_id('249a0111-5ad3-4534-86a7-1993d55f9185')
+    @decorators.idempotent_id('249a0111-5ad3-4534-86a7-1993d55f9185')
     @test.requires_ext(extension='tempurl', service='object')
     def test_head_object_using_temp_url(self):
         expires = self._get_expiry_date()
@@ -168,7 +169,7 @@
         resp, body = self.object_client.head(url)
         self.assertHeaders(resp, 'Object', 'HEAD')
 
-    @test.idempotent_id('9d9cfd90-708b-465d-802c-e4a8090b823d')
+    @decorators.idempotent_id('9d9cfd90-708b-465d-802c-e4a8090b823d')
     @test.requires_ext(extension='tempurl', service='object')
     def test_get_object_using_temp_url_with_inline_query_parameter(self):
         expires = self._get_expiry_date()
diff --git a/tempest/api/object_storage/test_object_temp_url_negative.py b/tempest/api/object_storage/test_object_temp_url_negative.py
index df7a7f6..d0e0935 100644
--- a/tempest/api/object_storage/test_object_temp_url_negative.py
+++ b/tempest/api/object_storage/test_object_temp_url_negative.py
@@ -20,6 +20,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -91,7 +92,7 @@
         return url
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5a583aca-c804-41ba-9d9a-e7be132bdf0b')
+    @decorators.idempotent_id('5a583aca-c804-41ba-9d9a-e7be132bdf0b')
     @test.requires_ext(extension='tempurl', service='object')
     def test_get_object_after_expiration_time(self):
 
diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py
index 6d064a2..1b12dac 100644
--- a/tempest/api/object_storage/test_object_version.py
+++ b/tempest/api/object_storage/test_object_version.py
@@ -18,7 +18,7 @@
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -44,7 +44,7 @@
         header_value = resp.get('x-versions-location', 'Missing Header')
         self.assertEqual(header_value, versioned)
 
-    @test.idempotent_id('a151e158-dcbf-4a1f-a1e7-46cd65895a6f')
+    @decorators.idempotent_id('a151e158-dcbf-4a1f-a1e7-46cd65895a6f')
     @testtools.skipIf(
         not CONF.object_storage_feature_enabled.object_versioning,
         'Object-versioning is disabled')
diff --git a/tempest/api/orchestration/stacks/test_environment.py b/tempest/api/orchestration/stacks/test_environment.py
index f2ffbd7..0a9b3e5 100644
--- a/tempest/api/orchestration/stacks/test_environment.py
+++ b/tempest/api/orchestration/stacks/test_environment.py
@@ -12,12 +12,12 @@
 
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class StackEnvironmentTest(base.BaseOrchestrationTest):
 
-    @test.idempotent_id('37d4346b-1abd-4442-b7b1-2a4e5749a1e3')
+    @decorators.idempotent_id('37d4346b-1abd-4442-b7b1-2a4e5749a1e3')
     def test_environment_parameter(self):
         """Test passing a stack parameter via the environment."""
         stack_name = data_utils.rand_name('heat')
@@ -34,7 +34,7 @@
         random_value = self.get_stack_output(stack_identifier, 'random_value')
         self.assertEqual(20, len(random_value))
 
-    @test.idempotent_id('73bce717-ad22-4853-bbef-6ed89b632701')
+    @decorators.idempotent_id('73bce717-ad22-4853-bbef-6ed89b632701')
     def test_environment_provider_resource(self):
         """Test passing resource_registry defining a provider resource."""
         stack_name = data_utils.rand_name('heat')
@@ -63,7 +63,7 @@
             'random_length']['default']
         self.assertEqual(expected_length, len(random_value))
 
-    @test.idempotent_id('9d682e5a-f4bb-47d5-8472-9d3cacb855df')
+    @decorators.idempotent_id('9d682e5a-f4bb-47d5-8472-9d3cacb855df')
     def test_files_provider_resource(self):
         """Test untyped defining of a provider resource via "files"."""
         # It's also possible to specify the filename directly in the template.
diff --git a/tempest/api/orchestration/stacks/test_limits.py b/tempest/api/orchestration/stacks/test_limits.py
index d85aa96..b079435 100644
--- a/tempest/api/orchestration/stacks/test_limits.py
+++ b/tempest/api/orchestration/stacks/test_limits.py
@@ -13,15 +13,15 @@
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 CONF = config.CONF
 
 
 class TestServerStackLimits(base.BaseOrchestrationTest):
 
-    @test.idempotent_id('ec9bed71-c460-45c9-ab98-295caa9fd76b')
+    @decorators.idempotent_id('ec9bed71-c460-45c9-ab98-295caa9fd76b')
     def test_exceed_max_template_size_fails(self):
         stack_name = data_utils.rand_name('heat')
         fill = 'A' * CONF.orchestration.max_template_size
@@ -34,7 +34,7 @@
                                stack_name, template)
         self.assertIn('exceeds maximum allowed size', str(ex))
 
-    @test.idempotent_id('d1b83e73-7cad-4a22-9839-036548c5387c')
+    @decorators.idempotent_id('d1b83e73-7cad-4a22-9839-036548c5387c')
     def test_exceed_max_resources_per_stack(self):
         stack_name = data_utils.rand_name('heat')
         # Create a big template, one resource more than the limit
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index 5d680d2..3a52108 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -16,6 +16,7 @@
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions
 from tempest import test
 
@@ -94,7 +95,7 @@
         for resource in resources:
             cls.test_resources[resource['logical_resource_id']] = resource
 
-    @test.idempotent_id('f9e2664c-bc44-4eef-98b6-495e4f9d74b3')
+    @decorators.idempotent_id('f9e2664c-bc44-4eef-98b6-495e4f9d74b3')
     def test_created_resources(self):
         """Verifies created neutron resources."""
         resources = [('Network', self.neutron_basic_template['resources'][
@@ -112,7 +113,7 @@
             self.assertEqual(resource_type, resource['resource_type'])
             self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
 
-    @test.idempotent_id('c572b915-edb1-4e90-b196-c7199a6848c0')
+    @decorators.idempotent_id('c572b915-edb1-4e90-b196-c7199a6848c0')
     @test.services('network')
     def test_created_network(self):
         """Verifies created network."""
@@ -124,7 +125,7 @@
         self.assertEqual(self.neutron_basic_template['resources'][
             'Network']['properties']['name'], network['name'])
 
-    @test.idempotent_id('e8f84b96-f9d7-4684-ad5f-340203e9f2c2')
+    @decorators.idempotent_id('e8f84b96-f9d7-4684-ad5f-340203e9f2c2')
     @test.services('network')
     def test_created_subnet(self):
         """Verifies created subnet."""
@@ -142,7 +143,7 @@
             'Subnet']['properties']['ip_version'], subnet['ip_version'])
         self.assertEqual(str(self.subnet_cidr), subnet['cidr'])
 
-    @test.idempotent_id('96af4c7f-5069-44bc-bdcf-c0390f8a67d1')
+    @decorators.idempotent_id('96af4c7f-5069-44bc-bdcf-c0390f8a67d1')
     @test.services('network')
     def test_created_router(self):
         """Verifies created router."""
@@ -155,7 +156,7 @@
                          router['external_gateway_info']['network_id'])
         self.assertEqual(True, router['admin_state_up'])
 
-    @test.idempotent_id('89f605bd-153e-43ee-a0ed-9919b63423c5')
+    @decorators.idempotent_id('89f605bd-153e-43ee-a0ed-9919b63423c5')
     @test.services('network')
     def test_created_router_interface(self):
         """Verifies created router interface."""
@@ -178,7 +179,7 @@
         self.assertEqual(str(self.subnet_cidr.iter_hosts().next()),
                          router_interface_ip)
 
-    @test.idempotent_id('75d85316-4ac2-4c0e-a1a9-edd2148fc10e')
+    @decorators.idempotent_id('75d85316-4ac2-4c0e-a1a9-edd2148fc10e')
     @test.services('compute', 'network')
     def test_created_server(self):
         """Verifies created sever."""
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
index 4ead084..f106349 100644
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ b/tempest/api/orchestration/stacks/test_non_empty_stack.py
@@ -13,7 +13,7 @@
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -49,14 +49,14 @@
             self.assertEqual(expected_num, len(stacks))
         return stacks
 
-    @test.idempotent_id('065c652a-720d-4760-9132-06aedeb8e3ab')
+    @decorators.idempotent_id('065c652a-720d-4760-9132-06aedeb8e3ab')
     def test_stack_list(self):
         """Created stack should be in the list of existing stacks."""
         stacks = self._list_stacks()
         stacks_names = map(lambda stack: stack['stack_name'], stacks)
         self.assertIn(self.stack_name, stacks_names)
 
-    @test.idempotent_id('992f96e3-41ee-4ff6-91c7-bcfb670c0919')
+    @decorators.idempotent_id('992f96e3-41ee-4ff6-91c7-bcfb670c0919')
     def test_stack_show(self):
         """Getting details about created stack should be possible."""
         stack = self.client.show_stack(self.stack_name)['stack']
@@ -75,7 +75,7 @@
         self.assertEqual(self.stack_id, stack['id'])
         self.assertEqual('fluffy', stack['outputs'][0]['output_key'])
 
-    @test.idempotent_id('fe719f7a-305a-44d8-bbb5-c91e93d9da17')
+    @decorators.idempotent_id('fe719f7a-305a-44d8-bbb5-c91e93d9da17')
     def test_suspend_resume_stack(self):
         """Suspend and resume a stack."""
         self.client.suspend_stack(self.stack_identifier)
@@ -85,13 +85,13 @@
         self.client.wait_for_stack_status(self.stack_identifier,
                                           'RESUME_COMPLETE')
 
-    @test.idempotent_id('c951d55e-7cce-4c1f-83a0-bad735437fa6')
+    @decorators.idempotent_id('c951d55e-7cce-4c1f-83a0-bad735437fa6')
     def test_list_resources(self):
         """Get list of created resources for the stack should be possible."""
         resources = self.list_resources(self.stack_identifier)
         self.assertEqual({self.resource_name: self.resource_type}, resources)
 
-    @test.idempotent_id('2aba03b3-392f-4237-900b-1f5a5e9bd962')
+    @decorators.idempotent_id('2aba03b3-392f-4237-900b-1f5a5e9bd962')
     def test_show_resource(self):
         """Getting details about created resource should be possible."""
         resource = self.client.show_resource(self.stack_identifier,
@@ -105,7 +105,7 @@
         self.assertEqual(self.resource_name, resource['logical_resource_id'])
         self.assertEqual(self.resource_type, resource['resource_type'])
 
-    @test.idempotent_id('898070a9-eba5-4fae-b7d6-cf3ffa03090f')
+    @decorators.idempotent_id('898070a9-eba5-4fae-b7d6-cf3ffa03090f')
     def test_resource_metadata(self):
         """Getting metadata for created resources should be possible."""
         metadata = self.client.show_resource_metadata(
@@ -114,7 +114,7 @@
         self.assertIsInstance(metadata, dict)
         self.assertEqual(['Tom', 'Stinky'], metadata.get('kittens', None))
 
-    @test.idempotent_id('46567533-0a7f-483b-8942-fa19e0f17839')
+    @decorators.idempotent_id('46567533-0a7f-483b-8942-fa19e0f17839')
     def test_list_events(self):
         """Getting list of created events for the stack should be possible."""
         events = self.client.list_events(self.stack_identifier)['events']
@@ -129,7 +129,7 @@
         self.assertIn('CREATE_IN_PROGRESS', resource_statuses)
         self.assertIn('CREATE_COMPLETE', resource_statuses)
 
-    @test.idempotent_id('92465723-1673-400a-909d-4773757a3f21')
+    @decorators.idempotent_id('92465723-1673-400a-909d-4773757a3f21')
     def test_show_event(self):
         """Getting details about an event should be possible."""
         events = self.client.list_resource_events(self.stack_identifier,
diff --git a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
index 16d8180..4d1db6d 100644
--- a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
+++ b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
@@ -12,7 +12,7 @@
 
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class NovaKeyPairResourcesYAMLTest(base.BaseOrchestrationTest):
@@ -43,7 +43,7 @@
         for resource in resources:
             cls.test_resources[resource['logical_resource_id']] = resource
 
-    @test.idempotent_id('b476eac2-a302-4815-961f-18c410a2a537')
+    @decorators.idempotent_id('b476eac2-a302-4815-961f-18c410a2a537')
     def test_created_resources(self):
         """Verifies created keypair resource."""
 
@@ -63,7 +63,7 @@
             self.assertEqual(resource_type, resource['resource_type'])
             self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
 
-    @test.idempotent_id('8d77dec7-91fd-45a6-943d-5abd45e338a4')
+    @decorators.idempotent_id('8d77dec7-91fd-45a6-943d-5abd45e338a4')
     def test_stack_keypairs_output(self):
         stack = self.client.show_stack(self.stack_name)['stack']
         self.assertIsInstance(stack, dict)
diff --git a/tempest/api/orchestration/stacks/test_resource_types.py b/tempest/api/orchestration/stacks/test_resource_types.py
index 8cf40de..63376d5 100644
--- a/tempest/api/orchestration/stacks/test_resource_types.py
+++ b/tempest/api/orchestration/stacks/test_resource_types.py
@@ -11,13 +11,14 @@
 #    under the License.
 
 from tempest.api.orchestration import base
+from tempest.lib import decorators
 from tempest import test
 
 
 class ResourceTypesTest(base.BaseOrchestrationTest):
 
     @test.attr(type='smoke')
-    @test.idempotent_id('7123d082-3577-4a30-8f00-f805327c4ffd')
+    @decorators.idempotent_id('7123d082-3577-4a30-8f00-f805327c4ffd')
     def test_resource_type_list(self):
         """Verify it is possible to list resource types."""
         resource_types = self.client.list_resource_types()['resource_types']
@@ -25,7 +26,7 @@
         self.assertIn('OS::Nova::Server', resource_types)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('0e85a483-828b-4a28-a0e3-f0a21809192b')
+    @decorators.idempotent_id('0e85a483-828b-4a28-a0e3-f0a21809192b')
     def test_resource_type_show(self):
         """Verify it is possible to get schema about resource types."""
         resource_types = self.client.list_resource_types()['resource_types']
@@ -38,7 +39,7 @@
             self.assertEqual(resource_type, type_schema['resource_type'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('8401821d-65fe-4d43-9fa3-57d5ce3a35c7')
+    @decorators.idempotent_id('8401821d-65fe-4d43-9fa3-57d5ce3a35c7')
     def test_resource_type_template(self):
         """Verify it is possible to get template about resource types."""
         type_template = self.client.show_resource_type_template(
diff --git a/tempest/api/orchestration/stacks/test_soft_conf.py b/tempest/api/orchestration/stacks/test_soft_conf.py
index b660f6e..89b10cc 100644
--- a/tempest/api/orchestration/stacks/test_soft_conf.py
+++ b/tempest/api/orchestration/stacks/test_soft_conf.py
@@ -12,6 +12,7 @@
 
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -75,7 +76,7 @@
             lib_exc.NotFound, self.client.show_software_config, config_id)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('136162ed-9445-4b9c-b7fc-306af8b5da99')
+    @decorators.idempotent_id('136162ed-9445-4b9c-b7fc-306af8b5da99')
     def test_get_software_config(self):
         """Testing software config get."""
         for conf in self.configs:
@@ -83,7 +84,7 @@
             self._validate_config(conf, api_config)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('1275c835-c967-4a2c-8d5d-ad533447ed91')
+    @decorators.idempotent_id('1275c835-c967-4a2c-8d5d-ad533447ed91')
     def test_get_deployment_list(self):
         """Getting a list of all deployments"""
         deploy_list = self.client.list_software_deployments()
@@ -92,7 +93,7 @@
         self.assertIn(self.deployment_id, deploy_ids)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('fe7cd9f9-54b1-429c-a3b7-7df8451db913')
+    @decorators.idempotent_id('fe7cd9f9-54b1-429c-a3b7-7df8451db913')
     def test_get_deployment_metadata(self):
         """Testing deployment metadata get"""
         metadata = self.client.show_software_deployment_metadata(
@@ -110,7 +111,7 @@
                          deployment['software_deployment']['config_id'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('f29d21f3-ed75-47cf-8cdc-ef1bdeb4c674')
+    @decorators.idempotent_id('f29d21f3-ed75-47cf-8cdc-ef1bdeb4c674')
     def test_software_deployment_create_validate(self):
         """Testing software deployment was created as expected."""
         # Asserting that all fields were created
@@ -123,7 +124,7 @@
                                   self.status_reason, self.configs[0]['id'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('2ac43ab3-34f2-415d-be2e-eabb4d14ee32')
+    @decorators.idempotent_id('2ac43ab3-34f2-415d-be2e-eabb4d14ee32')
     def test_software_deployment_update_no_metadata_change(self):
         """Testing software deployment update without metadata change."""
         metadata = self.client.show_software_deployment_metadata(
@@ -149,7 +150,7 @@
                 test_metadata['metadata'][0][key])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('92c48944-d79d-4595-a840-8e1a581c1a72')
+    @decorators.idempotent_id('92c48944-d79d-4595-a840-8e1a581c1a72')
     def test_software_deployment_update_with_metadata_change(self):
         """Testing software deployment update with metadata change."""
         metadata = self.client.show_software_deployment_metadata(
diff --git a/tempest/api/orchestration/stacks/test_stacks.py b/tempest/api/orchestration/stacks/test_stacks.py
index f13a2d9..7b5f161 100644
--- a/tempest/api/orchestration/stacks/test_stacks.py
+++ b/tempest/api/orchestration/stacks/test_stacks.py
@@ -12,6 +12,7 @@
 
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -19,13 +20,13 @@
     empty_template = "HeatTemplateFormatVersion: '2012-12-12'\n"
 
     @test.attr(type='smoke')
-    @test.idempotent_id('d35d628c-07f6-4674-85a1-74db9919e986')
+    @decorators.idempotent_id('d35d628c-07f6-4674-85a1-74db9919e986')
     def test_stack_list_responds(self):
         stacks = self.client.list_stacks()['stacks']
         self.assertIsInstance(stacks, list)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('10498bd5-a83e-4b62-a817-ce24afe938fe')
+    @decorators.idempotent_id('10498bd5-a83e-4b62-a817-ce24afe938fe')
     def test_stack_crud_no_resources(self):
         stack_name = data_utils.rand_name('heat')
 
diff --git a/tempest/api/orchestration/stacks/test_swift_resources.py b/tempest/api/orchestration/stacks/test_swift_resources.py
index 3672526..505abe7 100644
--- a/tempest/api/orchestration/stacks/test_swift_resources.py
+++ b/tempest/api/orchestration/stacks/test_swift_resources.py
@@ -15,6 +15,7 @@
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -59,7 +60,7 @@
         for resource in resources:
             cls.test_resources[resource['logical_resource_id']] = resource
 
-    @test.idempotent_id('1a6fe69e-4be4-4990-9a7a-84b6f18019cb')
+    @decorators.idempotent_id('1a6fe69e-4be4-4990-9a7a-84b6f18019cb')
     def test_created_resources(self):
         """Created stack should be in the list of existing stacks."""
         swift_basic_template = self.load_template('swift_basic')
@@ -74,7 +75,7 @@
             self.assertEqual(resource_name, resource['logical_resource_id'])
             self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
 
-    @test.idempotent_id('bd438b18-5494-4d5a-9ce6-d2a942ec5060')
+    @decorators.idempotent_id('bd438b18-5494-4d5a-9ce6-d2a942ec5060')
     @test.services('object_storage')
     def test_created_containers(self):
         params = {'format': 'json'}
@@ -84,7 +85,7 @@
                               if cont['name'].startswith(self.stack_name)]
         self.assertEqual(2, len(created_containers))
 
-    @test.idempotent_id('73d0c093-9922-44a0-8b1d-1fc092dee367')
+    @decorators.idempotent_id('73d0c093-9922-44a0-8b1d-1fc092dee367')
     @test.services('object_storage')
     def test_acl(self):
         acl_headers = ('x-container-meta-web-index', 'x-container-read')
@@ -102,7 +103,7 @@
         for h in acl_headers:
             self.assertIn(h, headers)
 
-    @test.idempotent_id('fda06135-6777-4594-aefa-0f6107169698')
+    @decorators.idempotent_id('fda06135-6777-4594-aefa-0f6107169698')
     @test.services('object_storage')
     def test_metadata(self):
         swift_basic_template = self.load_template('swift_basic')
diff --git a/tempest/api/orchestration/stacks/test_templates.py b/tempest/api/orchestration/stacks/test_templates.py
index 9154175..21548a0 100644
--- a/tempest/api/orchestration/stacks/test_templates.py
+++ b/tempest/api/orchestration/stacks/test_templates.py
@@ -12,7 +12,7 @@
 
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class TemplateYAMLTestJSON(base.BaseOrchestrationTest):
@@ -35,12 +35,12 @@
         cls.stack_id = cls.stack_identifier.split('/')[1]
         cls.parameters = {}
 
-    @test.idempotent_id('47430699-c368-495e-a1db-64c26fd967d7')
+    @decorators.idempotent_id('47430699-c368-495e-a1db-64c26fd967d7')
     def test_show_template(self):
         """Getting template used to create the stack."""
         self.client.show_template(self.stack_identifier)
 
-    @test.idempotent_id('ed53debe-8727-46c5-ab58-eba6090ec4de')
+    @decorators.idempotent_id('ed53debe-8727-46c5-ab58-eba6090ec4de')
     def test_validate_template(self):
         """Validating template passing it content."""
         self.client.validate_template(self.template,
diff --git a/tempest/api/orchestration/stacks/test_templates_negative.py b/tempest/api/orchestration/stacks/test_templates_negative.py
index f8245c1..a90abe2 100644
--- a/tempest/api/orchestration/stacks/test_templates_negative.py
+++ b/tempest/api/orchestration/stacks/test_templates_negative.py
@@ -13,6 +13,7 @@
 #    under the License.
 
 from tempest.api.orchestration import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -35,7 +36,7 @@
         cls.parameters = {}
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5586cbca-ddc4-4152-9db8-fa1ce5fc1876')
+    @decorators.idempotent_id('5586cbca-ddc4-4152-9db8-fa1ce5fc1876')
     def test_validate_template_url(self):
         """Validating template passing url to it."""
         self.assertRaises(lib_exc.BadRequest,
diff --git a/tempest/api/orchestration/stacks/test_volumes.py b/tempest/api/orchestration/stacks/test_volumes.py
index a5aaf6e..d34eb89 100644
--- a/tempest/api/orchestration/stacks/test_volumes.py
+++ b/tempest/api/orchestration/stacks/test_volumes.py
@@ -13,6 +13,7 @@
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -58,7 +59,7 @@
         self.assertEqual(template['resources']['volume']['properties'][
             'name'], self.get_stack_output(stack_identifier, 'display_name'))
 
-    @test.idempotent_id('c3243329-7bdd-4730-b402-4d19d50c41d8')
+    @decorators.idempotent_id('c3243329-7bdd-4730-b402-4d19d50c41d8')
     @test.services('volume')
     def test_cinder_volume_create_delete(self):
         """Create and delete a volume via OS::Cinder::Volume."""
@@ -92,7 +93,7 @@
         self.volumes_client.delete_volume(volume_id)
         self.volumes_client.wait_for_resource_deletion(volume_id)
 
-    @test.idempotent_id('ea8b3a46-b932-4c18-907a-fe23f00b33f8')
+    @decorators.idempotent_id('ea8b3a46-b932-4c18-907a-fe23f00b33f8')
     @test.services('volume')
     def test_cinder_volume_create_delete_retain(self):
         """Ensure the 'Retain' deletion policy is respected."""
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 5703313..72d71c7 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -15,7 +15,7 @@
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -93,24 +93,24 @@
 
         super(VolumeMultiBackendV2Test, cls).resource_cleanup()
 
-    @test.idempotent_id('c1a41f3f-9dad-493e-9f09-3ff197d477cc')
+    @decorators.idempotent_id('c1a41f3f-9dad-493e-9f09-3ff197d477cc')
     def test_backend_name_reporting(self):
         # get volume id which created by type without prefix
         for volume_id in self.volume_id_list_without_prefix:
             self._test_backend_name_reporting_by_volume_id(volume_id)
 
-    @test.idempotent_id('f38e647f-ab42-4a31-a2e7-ca86a6485215')
+    @decorators.idempotent_id('f38e647f-ab42-4a31-a2e7-ca86a6485215')
     def test_backend_name_reporting_with_prefix(self):
         # get volume id which created by type with prefix
         for volume_id in self.volume_id_list_with_prefix:
             self._test_backend_name_reporting_by_volume_id(volume_id)
 
-    @test.idempotent_id('46435ab1-a0af-4401-8373-f14e66b0dd58')
+    @decorators.idempotent_id('46435ab1-a0af-4401-8373-f14e66b0dd58')
     def test_backend_name_distinction(self):
         # get volume ids which created by type without prefix
         self._test_backend_name_distinction(self.volume_id_list_without_prefix)
 
-    @test.idempotent_id('4236305b-b65a-4bfc-a9d2-69cb5b2bf2ed')
+    @decorators.idempotent_id('4236305b-b65a-4bfc-a9d2-69cb5b2bf2ed')
     def test_backend_name_distinction_with_prefix(self):
         # get volume ids which created by type without prefix
         self._test_backend_name_distinction(self.volume_id_list_with_prefix)
diff --git a/tempest/api/volume/admin/test_qos.py b/tempest/api/volume/admin/test_qos.py
index 9275d2b..e1cfb30 100644
--- a/tempest/api/volume/admin/test_qos.py
+++ b/tempest/api/volume/admin/test_qos.py
@@ -15,7 +15,7 @@
 from tempest.api.volume import base
 from tempest.common.utils import data_utils as utils
 from tempest.common import waiters
-from tempest import test
+from tempest.lib import decorators
 
 
 class QosSpecsV2TestJSON(base.BaseVolumeAdminTest):
@@ -55,7 +55,7 @@
         self.admin_volume_qos_client.associate_qos(
             self.created_qos['id'], vol_type_id)
 
-    @test.idempotent_id('7e15f883-4bef-49a9-95eb-f94209a1ced1')
+    @decorators.idempotent_id('7e15f883-4bef-49a9-95eb-f94209a1ced1')
     def test_create_delete_qos_with_front_end_consumer(self):
         """Tests the creation and deletion of QoS specs
 
@@ -63,7 +63,7 @@
         """
         self._create_delete_test_qos_with_given_consumer('front-end')
 
-    @test.idempotent_id('b115cded-8f58-4ee4-aab5-9192cfada08f')
+    @decorators.idempotent_id('b115cded-8f58-4ee4-aab5-9192cfada08f')
     def test_create_delete_qos_with_back_end_consumer(self):
         """Tests the creation and deletion of QoS specs
 
@@ -71,7 +71,7 @@
         """
         self._create_delete_test_qos_with_given_consumer('back-end')
 
-    @test.idempotent_id('f88d65eb-ea0d-487d-af8d-71f4011575a4')
+    @decorators.idempotent_id('f88d65eb-ea0d-487d-af8d-71f4011575a4')
     def test_create_delete_qos_with_both_consumer(self):
         """Tests the creation and deletion of QoS specs
 
@@ -79,7 +79,7 @@
         """
         self._create_delete_test_qos_with_given_consumer('both')
 
-    @test.idempotent_id('7aa214cc-ac1a-4397-931f-3bb2e83bb0fd')
+    @decorators.idempotent_id('7aa214cc-ac1a-4397-931f-3bb2e83bb0fd')
     def test_get_qos(self):
         """Tests the detail of a given qos-specs"""
         body = self.admin_volume_qos_client.show_qos(
@@ -87,13 +87,13 @@
         self.assertEqual(self.qos_name, body['name'])
         self.assertEqual(self.qos_consumer, body['consumer'])
 
-    @test.idempotent_id('75e04226-bcf7-4595-a34b-fdf0736f38fc')
+    @decorators.idempotent_id('75e04226-bcf7-4595-a34b-fdf0736f38fc')
     def test_list_qos(self):
         """Tests the list of all qos-specs"""
         body = self.admin_volume_qos_client.list_qos()['qos_specs']
         self.assertIn(self.created_qos, body)
 
-    @test.idempotent_id('ed00fd85-4494-45f2-8ceb-9e2048919aed')
+    @decorators.idempotent_id('ed00fd85-4494-45f2-8ceb-9e2048919aed')
     def test_set_unset_qos_key(self):
         """Test the addition of a specs key to qos-specs"""
         args = {'iops_bytes': '500'}
@@ -117,7 +117,7 @@
             self.created_qos['id'])['qos_specs']
         self.assertNotIn(keys[0], body['specs'])
 
-    @test.idempotent_id('1dd93c76-6420-485d-a771-874044c416ac')
+    @decorators.idempotent_id('1dd93c76-6420-485d-a771-874044c416ac')
     def test_associate_disassociate_qos(self):
         """Test the following operations :
 
diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py
index 29a161b..e1c9492 100644
--- a/tempest/api/volume/admin/test_snapshots_actions.py
+++ b/tempest/api/volume/admin/test_snapshots_actions.py
@@ -15,7 +15,7 @@
 
 from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -59,7 +59,7 @@
     def _get_progress_alias(self):
         return 'os-extended-snapshot-attributes:progress'
 
-    @test.idempotent_id('3e13ca2f-48ea-49f3-ae1a-488e9180d535')
+    @decorators.idempotent_id('3e13ca2f-48ea-49f3-ae1a-488e9180d535')
     def test_reset_snapshot_status(self):
         # Reset snapshot status to creating
         status = 'creating'
@@ -69,7 +69,7 @@
             self.snapshot['id'])['snapshot']
         self.assertEqual(status, snapshot_get['status'])
 
-    @test.idempotent_id('41288afd-d463-485e-8f6e-4eea159413eb')
+    @decorators.idempotent_id('41288afd-d463-485e-8f6e-4eea159413eb')
     def test_update_snapshot_status(self):
         # Reset snapshot status to creating
         status = 'creating'
@@ -88,22 +88,22 @@
         self.assertEqual(status, snapshot_get['status'])
         self.assertEqual(progress, snapshot_get[progress_alias])
 
-    @test.idempotent_id('05f711b6-e629-4895-8103-7ca069f2073a')
+    @decorators.idempotent_id('05f711b6-e629-4895-8103-7ca069f2073a')
     def test_snapshot_force_delete_when_snapshot_is_creating(self):
         # test force delete when status of snapshot is creating
         self._create_reset_and_force_delete_temp_snapshot('creating')
 
-    @test.idempotent_id('92ce8597-b992-43a1-8868-6316b22a969e')
+    @decorators.idempotent_id('92ce8597-b992-43a1-8868-6316b22a969e')
     def test_snapshot_force_delete_when_snapshot_is_deleting(self):
         # test force delete when status of snapshot is deleting
         self._create_reset_and_force_delete_temp_snapshot('deleting')
 
-    @test.idempotent_id('645a4a67-a1eb-4e8e-a547-600abac1525d')
+    @decorators.idempotent_id('645a4a67-a1eb-4e8e-a547-600abac1525d')
     def test_snapshot_force_delete_when_snapshot_is_error(self):
         # test force delete when status of snapshot is error
         self._create_reset_and_force_delete_temp_snapshot('error')
 
-    @test.idempotent_id('bf89080f-8129-465e-9327-b2f922666ba5')
+    @decorators.idempotent_id('bf89080f-8129-465e-9327-b2f922666ba5')
     def test_snapshot_force_delete_when_snapshot_is_error_deleting(self):
         # test force delete when status of snapshot is error_deleting
         self._create_reset_and_force_delete_temp_snapshot('error_deleting')
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index f6de9a6..73c927a 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -14,12 +14,12 @@
 #    under the License.
 
 from tempest.api.volume import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class VolumeHostsAdminV2TestsJSON(base.BaseVolumeAdminTest):
 
-    @test.idempotent_id('d5f3efa2-6684-4190-9ced-1c2f526352ad')
+    @decorators.idempotent_id('d5f3efa2-6684-4190-9ced-1c2f526352ad')
     def test_list_hosts(self):
         hosts = self.admin_hosts_client.list_hosts()['hosts']
         self.assertGreaterEqual(len(hosts), 2, "No. of hosts are < 2,"
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index 7d8c94d..5a83ae3 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -15,7 +15,7 @@
 from tempest.api.volume import base
 from tempest.common.utils import data_utils
 from tempest.common import waiters
-from tempest import test
+from tempest.lib import decorators
 
 QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes', 'backups']
 QUOTA_USAGE_KEYS = ['reserved', 'limit', 'in_use']
@@ -32,21 +32,21 @@
         cls.demo_tenant_id = cls.os.credentials.tenant_id
         cls.alt_client = cls.os_alt.volumes_client
 
-    @test.idempotent_id('59eada70-403c-4cef-a2a3-a8ce2f1b07a0')
+    @decorators.idempotent_id('59eada70-403c-4cef-a2a3-a8ce2f1b07a0')
     def test_list_quotas(self):
         quotas = (self.admin_quotas_client.show_quota_set(self.demo_tenant_id)
                   ['quota_set'])
         for key in QUOTA_KEYS:
             self.assertIn(key, quotas)
 
-    @test.idempotent_id('2be020a2-5fdd-423d-8d35-a7ffbc36e9f7')
+    @decorators.idempotent_id('2be020a2-5fdd-423d-8d35-a7ffbc36e9f7')
     def test_list_default_quotas(self):
         quotas = self.admin_quotas_client.show_default_quota_set(
             self.demo_tenant_id)['quota_set']
         for key in QUOTA_KEYS:
             self.assertIn(key, quotas)
 
-    @test.idempotent_id('3d45c99e-cc42-4424-a56e-5cbd212b63a6')
+    @decorators.idempotent_id('3d45c99e-cc42-4424-a56e-5cbd212b63a6')
     def test_update_all_quota_resources_for_tenant(self):
         # Admin can update all the resource quota limits for a tenant
         default_quota_set = self.admin_quotas_client.show_default_quota_set(
@@ -71,7 +71,7 @@
         # would be no other values in there.
         self.assertDictContainsSubset(new_quota_set, quota_set)
 
-    @test.idempotent_id('18c51ae9-cb03-48fc-b234-14a19374dbed')
+    @decorators.idempotent_id('18c51ae9-cb03-48fc-b234-14a19374dbed')
     def test_show_quota_usage(self):
         quota_usage = self.admin_quotas_client.show_quota_set(
             self.os_adm.credentials.tenant_id,
@@ -81,7 +81,7 @@
             for usage_key in QUOTA_USAGE_KEYS:
                 self.assertIn(usage_key, quota_usage[key])
 
-    @test.idempotent_id('ae8b6091-48ad-4bfa-a188-bbf5cc02115f')
+    @decorators.idempotent_id('ae8b6091-48ad-4bfa-a188-bbf5cc02115f')
     def test_quota_usage(self):
         quota_usage = self.admin_quotas_client.show_quota_set(
             self.demo_tenant_id, params={'usage': True})['quota_set']
@@ -100,7 +100,7 @@
                          volume["size"],
                          new_quota_usage['gigabytes']['in_use'])
 
-    @test.idempotent_id('874b35a9-51f1-4258-bec5-cd561b6690d3')
+    @decorators.idempotent_id('874b35a9-51f1-4258-bec5-cd561b6690d3')
     def test_delete_quota(self):
         # Admin can delete the resource quota set for a project
         project_name = data_utils.rand_name('quota_tenant')
@@ -121,7 +121,7 @@
                          ['quota_set'])
         self.assertEqual(volume_default, quota_set_new['volumes'])
 
-    @test.idempotent_id('8911036f-9d54-4720-80cc-a1c9796a8805')
+    @decorators.idempotent_id('8911036f-9d54-4720-80cc-a1c9796a8805')
     def test_quota_usage_after_volume_transfer(self):
         # Create a volume for transfer
         volume = self.create_volume()
diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py
index c19b1c4..8170626 100644
--- a/tempest/api/volume/admin/test_volume_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_quotas_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.volume import base
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -46,14 +47,14 @@
         cls.volume = cls.create_volume()
 
     @test.attr(type='negative')
-    @test.idempotent_id('bf544854-d62a-47f2-a681-90f7a47d86b6')
+    @decorators.idempotent_id('bf544854-d62a-47f2-a681-90f7a47d86b6')
     def test_quota_volumes(self):
         self.assertRaises(lib_exc.OverLimit,
                           self.volumes_client.create_volume,
                           size=CONF.volume.volume_size)
 
     @test.attr(type='negative')
-    @test.idempotent_id('2dc27eee-8659-4298-b900-169d71a91374')
+    @decorators.idempotent_id('2dc27eee-8659-4298-b900-169d71a91374')
     def test_quota_volume_gigabytes(self):
         # NOTE(gfidente): quota set needs to be changed for this test
         # or we may be limited by the volumes or snaps quota number, not by
diff --git a/tempest/api/volume/admin/test_volume_retype_with_migration.py b/tempest/api/volume/admin/test_volume_retype_with_migration.py
index 8a69ea3..dc509de 100644
--- a/tempest/api/volume/admin/test_volume_retype_with_migration.py
+++ b/tempest/api/volume/admin/test_volume_retype_with_migration.py
@@ -16,7 +16,7 @@
 from tempest.api.volume import base
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -75,7 +75,7 @@
 
         super(VolumeRetypeWithMigrationV2Test, cls).resource_cleanup()
 
-    @test.idempotent_id('a1a41f3f-9dad-493e-9f09-3ff197d477cd')
+    @decorators.idempotent_id('a1a41f3f-9dad-493e-9f09-3ff197d477cd')
     def test_available_volume_retype_with_migration(self):
 
         keys_with_no_change = ('id', 'size', 'description', 'name', 'user_id',
diff --git a/tempest/api/volume/admin/test_volume_services.py b/tempest/api/volume/admin/test_volume_services.py
index 165874b..97a352b 100644
--- a/tempest/api/volume/admin/test_volume_services.py
+++ b/tempest/api/volume/admin/test_volume_services.py
@@ -14,7 +14,7 @@
 #    under the License.
 from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 
 CONF = config.CONF
@@ -43,13 +43,13 @@
         cls.host_name = _get_host(cls.services[0]['host'])
         cls.binary_name = cls.services[0]['binary']
 
-    @test.idempotent_id('e0218299-0a59-4f43-8b2b-f1c035b3d26d')
+    @decorators.idempotent_id('e0218299-0a59-4f43-8b2b-f1c035b3d26d')
     def test_list_services(self):
         services = (self.admin_volume_services_client.list_services()
                     ['services'])
         self.assertNotEqual(0, len(services))
 
-    @test.idempotent_id('63a3e1ca-37ee-4983-826d-83276a370d25')
+    @decorators.idempotent_id('63a3e1ca-37ee-4983-826d-83276a370d25')
     def test_get_service_by_service_binary_name(self):
         services = (self.admin_volume_services_client.list_services(
             binary=self.binary_name)['services'])
@@ -57,7 +57,7 @@
         for service in services:
             self.assertEqual(self.binary_name, service['binary'])
 
-    @test.idempotent_id('178710e4-7596-4e08-9333-745cb8bc4f8d')
+    @decorators.idempotent_id('178710e4-7596-4e08-9333-745cb8bc4f8d')
     def test_get_service_by_host_name(self):
         services_on_host = [service for service in self.services if
                             _get_host(service['host']) == self.host_name]
@@ -73,7 +73,7 @@
         # on order.
         self.assertEqual(sorted(s1), sorted(s2))
 
-    @test.idempotent_id('ffa6167c-4497-4944-a464-226bbdb53908')
+    @decorators.idempotent_id('ffa6167c-4497-4944-a464-226bbdb53908')
     def test_get_service_by_service_and_host_name(self):
 
         services = (self.admin_volume_services_client.list_services(
diff --git a/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py b/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py
index 09af7fe..90a0022 100644
--- a/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.volume import base
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -54,14 +55,14 @@
         cls.snapshot = cls.create_snapshot(volume_id=cls.volume['id'])
 
     @test.attr(type='negative')
-    @test.idempotent_id('02bbf63f-6c05-4357-9d98-2926a94064ff')
+    @decorators.idempotent_id('02bbf63f-6c05-4357-9d98-2926a94064ff')
     def test_quota_volume_snapshots(self):
         self.assertRaises(lib_exc.OverLimit,
                           self.snapshots_client.create_snapshot,
                           volume_id=self.volume['id'])
 
     @test.attr(type='negative')
-    @test.idempotent_id('c99a1ca9-6cdf-498d-9fdf-25832babef27')
+    @decorators.idempotent_id('c99a1ca9-6cdf-498d-9fdf-25832babef27')
     def test_quota_volume_gigabytes_snapshots(self):
         self.addCleanup(self.admin_quotas_client.update_quota_set,
                         self.demo_tenant_id,
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 16be463..7938604 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -17,21 +17,21 @@
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
 
 class VolumeTypesV2Test(base.BaseVolumeAdminTest):
 
-    @test.idempotent_id('9d9b28e3-1b2e-4483-a2cc-24aa0ea1de54')
+    @decorators.idempotent_id('9d9b28e3-1b2e-4483-a2cc-24aa0ea1de54')
     def test_volume_type_list(self):
         # List volume types.
         body = \
             self.admin_volume_types_client.list_volume_types()['volume_types']
         self.assertIsInstance(body, list)
 
-    @test.idempotent_id('c03cc62c-f4e9-4623-91ec-64ce2f9c1260')
+    @decorators.idempotent_id('c03cc62c-f4e9-4623-91ec-64ce2f9c1260')
     def test_volume_crud_with_volume_type_and_extra_specs(self):
         # Create/update/get/delete volume with volume_type and extra spec.
         volume_types = list()
@@ -81,7 +81,7 @@
                          'The fetched Volume is different '
                          'from the created Volume')
 
-    @test.idempotent_id('4e955c3b-49db-4515-9590-0c99f8e471ad')
+    @decorators.idempotent_id('4e955c3b-49db-4515-9590-0c99f8e471ad')
     def test_volume_type_create_get_delete(self):
         # Create/get volume type.
         name = data_utils.rand_name(self.__class__.__name__ + '-volume-type')
@@ -90,8 +90,11 @@
         vendor = CONF.volume.vendor_name
         extra_specs = {"storage_protocol": proto,
                        "vendor_name": vendor}
-        body = self.create_volume_type(description=description, name=name,
-                                       extra_specs=extra_specs)
+        params = {'name': name,
+                  'description': description,
+                  'extra_specs': extra_specs,
+                  'os-volume-type-access:is_public': True}
+        body = self.create_volume_type(**params)
         self.assertIn('name', body)
         self.assertEqual(name, body['name'],
                          "The created volume_type name is not equal "
@@ -112,8 +115,14 @@
         self.assertEqual(extra_specs, fetched_volume_type['extra_specs'],
                          'The fetched Volume_type is different '
                          'from the created Volume_type')
+        self.assertEqual(description, fetched_volume_type['description'])
+        self.assertEqual(body['is_public'],
+                         fetched_volume_type['is_public'])
+        self.assertEqual(
+            body['os-volume-type-access:is_public'],
+            fetched_volume_type['os-volume-type-access:is_public'])
 
-    @test.idempotent_id('7830abd0-ff99-4793-a265-405684a54d46')
+    @decorators.idempotent_id('7830abd0-ff99-4793-a265-405684a54d46')
     def test_volume_type_encryption_create_get_delete(self):
         # Create/get/delete encryption type.
         provider = "LuksEncryptor"
@@ -153,7 +162,7 @@
             self.admin_encryption_types_client.show_encryption_type(type_id))
         self.assertEmpty(deleted_encryption_type)
 
-    @test.idempotent_id('cf9f07c6-db9e-4462-a243-5933ad65e9c8')
+    @decorators.idempotent_id('cf9f07c6-db9e-4462-a243-5933ad65e9c8')
     def test_volume_type_update(self):
         # Create volume type
         volume_type = self.create_volume_type()
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs.py b/tempest/api/volume/admin/test_volume_types_extra_specs.py
index fdff2df..1729d06 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest.api.volume import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 
 class VolumeTypesExtraSpecsV2Test(base.BaseVolumeAdminTest):
@@ -25,7 +25,7 @@
         super(VolumeTypesExtraSpecsV2Test, cls).resource_setup()
         cls.volume_type = cls.create_volume_type()
 
-    @test.idempotent_id('b42923e9-0452-4945-be5b-d362ae533e60')
+    @decorators.idempotent_id('b42923e9-0452-4945-be5b-d362ae533e60')
     def test_volume_type_extra_specs_list(self):
         # List Volume types extra specs.
         extra_specs = {"spec1": "val1"}
@@ -38,7 +38,7 @@
         self.assertIsInstance(body, dict)
         self.assertIn('spec1', body)
 
-    @test.idempotent_id('0806db36-b4a0-47a1-b6f3-c2e7f194d017')
+    @decorators.idempotent_id('0806db36-b4a0-47a1-b6f3-c2e7f194d017')
     def test_volume_type_extra_specs_update(self):
         # Update volume type extra specs
         extra_specs = {"spec2": "val1"}
@@ -54,7 +54,7 @@
         self.assertEqual(extra_spec[spec_key], body[spec_key],
                          "Volume type extra spec incorrectly updated")
 
-    @test.idempotent_id('d4772798-601f-408a-b2a5-29e8a59d1220')
+    @decorators.idempotent_id('d4772798-601f-408a-b2a5-29e8a59d1220')
     def test_volume_type_extra_spec_create_get_delete(self):
         # Create/Get/Delete volume type extra spec.
         spec_key = "spec3"
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
index 8040322..933b6ad 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
@@ -15,8 +15,8 @@
 
 from tempest.api.volume import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 
 class ExtraSpecsNegativeV2Test(base.BaseVolumeAdminTest):
@@ -27,7 +27,7 @@
         cls.extra_specs = {"spec1": "val1"}
         cls.volume_type = cls.create_volume_type(extra_specs=cls.extra_specs)
 
-    @test.idempotent_id('08961d20-5cbb-4910-ac0f-89ad6dbb2da1')
+    @decorators.idempotent_id('08961d20-5cbb-4910-ac0f-89ad6dbb2da1')
     def test_update_no_body(self):
         # Should not update volume type extra specs with no body
         self.assertRaises(
@@ -35,7 +35,7 @@
             self.admin_volume_types_client.update_volume_type_extra_specs,
             self.volume_type['id'], "spec1", None)
 
-    @test.idempotent_id('25e5a0ee-89b3-4c53-8310-236f76c75365')
+    @decorators.idempotent_id('25e5a0ee-89b3-4c53-8310-236f76c75365')
     def test_update_nonexistent_extra_spec_id(self):
         # Should not update volume type extra specs with nonexistent id.
         extra_spec = {"spec1": "val2"}
@@ -45,7 +45,7 @@
             self.volume_type['id'], data_utils.rand_uuid(),
             extra_spec)
 
-    @test.idempotent_id('9bf7a657-b011-4aec-866d-81c496fbe5c8')
+    @decorators.idempotent_id('9bf7a657-b011-4aec-866d-81c496fbe5c8')
     def test_update_none_extra_spec_id(self):
         # Should not update volume type extra specs with none id.
         extra_spec = {"spec1": "val2"}
@@ -54,7 +54,7 @@
             self.admin_volume_types_client.update_volume_type_extra_specs,
             self.volume_type['id'], None, extra_spec)
 
-    @test.idempotent_id('a77dfda2-9100-448e-9076-ed1711f4bdfc')
+    @decorators.idempotent_id('a77dfda2-9100-448e-9076-ed1711f4bdfc')
     def test_update_multiple_extra_spec(self):
         # Should not update volume type extra specs with multiple specs as
             # body.
@@ -65,7 +65,7 @@
             self.volume_type['id'], list(extra_spec)[0],
             extra_spec)
 
-    @test.idempotent_id('49d5472c-a53d-4eab-a4d3-450c4db1c545')
+    @decorators.idempotent_id('49d5472c-a53d-4eab-a4d3-450c4db1c545')
     def test_create_nonexistent_type_id(self):
         # Should not create volume type extra spec for nonexistent volume
             # type id.
@@ -75,7 +75,7 @@
             self.admin_volume_types_client.create_volume_type_extra_specs,
             data_utils.rand_uuid(), extra_specs)
 
-    @test.idempotent_id('c821bdc8-43a4-4bf4-86c8-82f3858d5f7d')
+    @decorators.idempotent_id('c821bdc8-43a4-4bf4-86c8-82f3858d5f7d')
     def test_create_none_body(self):
         # Should not create volume type extra spec for none POST body.
         self.assertRaises(
@@ -83,7 +83,7 @@
             self.admin_volume_types_client.create_volume_type_extra_specs,
             self.volume_type['id'], None)
 
-    @test.idempotent_id('bc772c71-1ed4-4716-b945-8b5ed0f15e87')
+    @decorators.idempotent_id('bc772c71-1ed4-4716-b945-8b5ed0f15e87')
     def test_create_invalid_body(self):
         # Should not create volume type extra spec for invalid POST body.
         self.assertRaises(
@@ -91,7 +91,7 @@
             self.admin_volume_types_client.create_volume_type_extra_specs,
             self.volume_type['id'], extra_specs=['invalid'])
 
-    @test.idempotent_id('031cda8b-7d23-4246-8bf6-bbe73fd67074')
+    @decorators.idempotent_id('031cda8b-7d23-4246-8bf6-bbe73fd67074')
     def test_delete_nonexistent_volume_type_id(self):
         # Should not delete volume type extra spec for nonexistent
         # type id.
@@ -100,7 +100,7 @@
             self.admin_volume_types_client.delete_volume_type_extra_specs,
             data_utils.rand_uuid(), "spec1")
 
-    @test.idempotent_id('dee5cf0c-cdd6-4353-b70c-e847050d71fb')
+    @decorators.idempotent_id('dee5cf0c-cdd6-4353-b70c-e847050d71fb')
     def test_list_nonexistent_volume_type_id(self):
         # Should not list volume type extra spec for nonexistent type id.
         self.assertRaises(
@@ -108,7 +108,7 @@
             self.admin_volume_types_client.list_volume_types_extra_specs,
             data_utils.rand_uuid())
 
-    @test.idempotent_id('9f402cbd-1838-4eb4-9554-126a6b1908c9')
+    @decorators.idempotent_id('9f402cbd-1838-4eb4-9554-126a6b1908c9')
     def test_get_nonexistent_volume_type_id(self):
         # Should not get volume type extra spec for nonexistent type id.
         self.assertRaises(
@@ -116,7 +116,7 @@
             self.admin_volume_types_client.show_volume_type_extra_specs,
             data_utils.rand_uuid(), "spec1")
 
-    @test.idempotent_id('c881797d-12ff-4f1a-b09d-9f6212159753')
+    @decorators.idempotent_id('c881797d-12ff-4f1a-b09d-9f6212159753')
     def test_get_nonexistent_extra_spec_id(self):
         # Should not get volume type extra spec for nonexistent extra spec
             # id.
diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py
index 5332f1e..b278127 100644
--- a/tempest/api/volume/admin/test_volume_types_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_negative.py
@@ -15,13 +15,13 @@
 
 from tempest.api.volume import base
 from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 
 class VolumeTypesNegativeV2Test(base.BaseVolumeAdminTest):
 
-    @test.idempotent_id('b48c98f2-e662-4885-9b71-032256906314')
+    @decorators.idempotent_id('b48c98f2-e662-4885-9b71-032256906314')
     def test_create_with_nonexistent_volume_type(self):
         # Should not be able to create volume with nonexistent volume_type.
         self.name_field = self.special_fields['name_field']
@@ -30,28 +30,28 @@
         self.assertRaises(lib_exc.NotFound,
                           self.volumes_client.create_volume, **params)
 
-    @test.idempotent_id('878b4e57-faa2-4659-b0d1-ce740a06ae81')
+    @decorators.idempotent_id('878b4e57-faa2-4659-b0d1-ce740a06ae81')
     def test_create_with_empty_name(self):
         # Should not be able to create volume type with an empty name.
         self.assertRaises(
             lib_exc.BadRequest,
             self.admin_volume_types_client.create_volume_type, name='')
 
-    @test.idempotent_id('994610d6-0476-4018-a644-a2602ef5d4aa')
+    @decorators.idempotent_id('994610d6-0476-4018-a644-a2602ef5d4aa')
     def test_get_nonexistent_type_id(self):
         # Should not be able to get volume type with nonexistent type id.
         self.assertRaises(lib_exc.NotFound,
                           self.admin_volume_types_client.show_volume_type,
                           data_utils.rand_uuid())
 
-    @test.idempotent_id('6b3926d2-7d73-4896-bc3d-e42dfd11a9f6')
+    @decorators.idempotent_id('6b3926d2-7d73-4896-bc3d-e42dfd11a9f6')
     def test_delete_nonexistent_type_id(self):
         # Should not be able to delete volume type with nonexistent type id.
         self.assertRaises(lib_exc.NotFound,
                           self.admin_volume_types_client.delete_volume_type,
                           data_utils.rand_uuid())
 
-    @test.idempotent_id('8c09f849-f225-4d78-ba87-bffd9a5e0c6f')
+    @decorators.idempotent_id('8c09f849-f225-4d78-ba87-bffd9a5e0c6f')
     def test_create_volume_with_private_volume_type(self):
         # Should not be able to create volume with private volume type.
         params = {'os-volume-type-access:is_public': False}
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index a63cbf0..693ffe7 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.api.volume import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class VolumesActionsV2Test(base.BaseVolumeAdminTest):
@@ -28,7 +28,7 @@
         self.admin_volume_client.force_delete_volume(temp_volume['id'])
         self.volumes_client.wait_for_resource_deletion(temp_volume['id'])
 
-    @test.idempotent_id('d063f96e-a2e0-4f34-8b8a-395c42de1845')
+    @decorators.idempotent_id('d063f96e-a2e0-4f34-8b8a-395c42de1845')
     def test_volume_reset_status(self):
         # test volume reset status : available->error->available
         volume = self.create_volume()
@@ -39,17 +39,17 @@
                 volume['id'])['volume']
             self.assertEqual(status, volume_get['status'])
 
-    @test.idempotent_id('21737d5a-92f2-46d7-b009-a0cc0ee7a570')
+    @decorators.idempotent_id('21737d5a-92f2-46d7-b009-a0cc0ee7a570')
     def test_volume_force_delete_when_volume_is_creating(self):
         # test force delete when status of volume is creating
         self._create_reset_and_force_delete_temp_volume('creating')
 
-    @test.idempotent_id('db8d607a-aa2e-4beb-b51d-d4005c232011')
+    @decorators.idempotent_id('db8d607a-aa2e-4beb-b51d-d4005c232011')
     def test_volume_force_delete_when_volume_is_attaching(self):
         # test force delete when status of volume is attaching
         self._create_reset_and_force_delete_temp_volume('attaching')
 
-    @test.idempotent_id('3e33a8a8-afd4-4d64-a86b-c27a185c5a4a')
+    @decorators.idempotent_id('3e33a8a8-afd4-4d64-a86b-c27a185c5a4a')
     def test_volume_force_delete_when_volume_is_error(self):
         # test force delete when status of volume is error
         self._create_reset_and_force_delete_temp_volume('error')
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index 61d4ba7..04d27ea 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -20,7 +20,7 @@
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -49,7 +49,7 @@
         backup.update(changes)
         return self._encode_backup(backup)
 
-    @test.idempotent_id('a99c54a1-dd80-4724-8a13-13bf58d4068d')
+    @decorators.idempotent_id('a99c54a1-dd80-4724-8a13-13bf58d4068d')
     def test_volume_backup_export_import(self):
         """Test backup export import functionality.
 
@@ -117,7 +117,7 @@
         waiters.wait_for_backup_status(self.admin_backups_client,
                                        import_backup['id'], 'available')
 
-    @test.idempotent_id('47a35425-a891-4e13-961c-c45deea21e94')
+    @decorators.idempotent_id('47a35425-a891-4e13-961c-c45deea21e94')
     def test_volume_backup_reset_status(self):
         # Create a volume
         volume = self.create_volume()
diff --git a/tempest/api/volume/admin/v2/test_backends_capabilities.py b/tempest/api/volume/admin/v2/test_backends_capabilities.py
index 9751845..1060f2b 100644
--- a/tempest/api/volume/admin/v2/test_backends_capabilities.py
+++ b/tempest/api/volume/admin/v2/test_backends_capabilities.py
@@ -16,7 +16,7 @@
 import operator
 
 from tempest.api.volume import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class BackendsCapabilitiesAdminV2TestsJSON(base.BaseVolumeAdminTest):
@@ -41,7 +41,7 @@
             cls.admin_scheduler_stats_client.list_pools()['pools']
         ]
 
-    @test.idempotent_id('3750af44-5ea2-4cd4-bc3e-56e7e6caf854')
+    @decorators.idempotent_id('3750af44-5ea2-4cd4-bc3e-56e7e6caf854')
     def test_get_capabilities_backend(self):
         # Test backend properties
         backend = self.admin_capabilities_client.show_backend_capabilities(
@@ -51,7 +51,7 @@
         for key in self.CAPABILITIES:
             self.assertIn(key, backend)
 
-    @test.idempotent_id('a9035743-d46a-47c5-9cb7-3c80ea16dea0')
+    @decorators.idempotent_id('a9035743-d46a-47c5-9cb7-3c80ea16dea0')
     def test_compare_volume_stats_values(self):
         # Test values comparison between show_backend_capabilities
         # to show_pools
diff --git a/tempest/api/volume/admin/v2/test_snapshot_manage.py b/tempest/api/volume/admin/v2/test_snapshot_manage.py
index 6a3f9ee..1114924 100644
--- a/tempest/api/volume/admin/v2/test_snapshot_manage.py
+++ b/tempest/api/volume/admin/v2/test_snapshot_manage.py
@@ -18,7 +18,7 @@
 from tempest.api.volume import base
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -31,7 +31,7 @@
      managed by Cinder from a storage back end to Cinder
     """
 
-    @test.idempotent_id('0132f42d-0147-4b45-8501-cc504bbf7810')
+    @decorators.idempotent_id('0132f42d-0147-4b45-8501-cc504bbf7810')
     @testtools.skipUnless(CONF.volume_feature_enabled.manage_snapshot,
                           "Manage snapshot tests are disabled")
     def test_unmanage_manage_snapshot(self):
diff --git a/tempest/api/volume/admin/v2/test_volume_pools.py b/tempest/api/volume/admin/v2/test_volume_pools.py
index 8544a6a..91d092d 100644
--- a/tempest/api/volume/admin/v2/test_volume_pools.py
+++ b/tempest/api/volume/admin/v2/test_volume_pools.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.api.volume import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class VolumePoolsAdminV2TestsJSON(base.BaseVolumeAdminTest):
@@ -33,10 +33,10 @@
         self.assertIn(volume_info['os-vol-host-attr:host'],
                       [pool['name'] for pool in cinder_pools])
 
-    @test.idempotent_id('0248a46c-e226-4933-be10-ad6fca8227e7')
+    @decorators.idempotent_id('0248a46c-e226-4933-be10-ad6fca8227e7')
     def test_get_pools_without_details(self):
         self._assert_host_volume_in_pools()
 
-    @test.idempotent_id('d4bb61f7-762d-4437-b8a4-5785759a0ced')
+    @decorators.idempotent_id('d4bb61f7-762d-4437-b8a4-5785759a0ced')
     def test_get_pools_with_details(self):
         self._assert_host_volume_in_pools(with_detail=True)
diff --git a/tempest/api/volume/admin/v2/test_volume_type_access.py b/tempest/api/volume/admin/v2/test_volume_type_access.py
index 80dbf12..b60b33b 100644
--- a/tempest/api/volume/admin/v2/test_volume_type_access.py
+++ b/tempest/api/volume/admin/v2/test_volume_type_access.py
@@ -17,8 +17,8 @@
 
 from tempest.api.volume import base
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 CONF = config.CONF
 
@@ -32,7 +32,7 @@
         super(VolumeTypesAccessV2Test, cls).setup_clients()
         cls.alt_client = cls.os_alt.volumes_client
 
-    @test.idempotent_id('d4dd0027-835f-4554-a6e5-50903fb79184')
+    @decorators.idempotent_id('d4dd0027-835f-4554-a6e5-50903fb79184')
     def test_volume_type_access_add(self):
         # Creating a NON public volume type
         params = {'os-volume-type-access:is_public': False}
@@ -55,7 +55,7 @@
         # Validating the created volume is based on the volume type
         self.assertEqual(volume_type['name'], volume['volume_type'])
 
-    @test.idempotent_id('5220eb28-a435-43ce-baaf-ed46f0e95159')
+    @decorators.idempotent_id('5220eb28-a435-43ce-baaf-ed46f0e95159')
     def test_volume_type_access_list(self):
         # Creating a NON public volume type
         params = {'os-volume-type-access:is_public': False}
diff --git a/tempest/api/volume/admin/v2/test_volumes_list.py b/tempest/api/volume/admin/v2/test_volumes_list.py
index fd36d0a..b0a37fb 100644
--- a/tempest/api/volume/admin/v2/test_volumes_list.py
+++ b/tempest/api/volume/admin/v2/test_volumes_list.py
@@ -18,7 +18,7 @@
 from tempest.api.volume import base
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -39,7 +39,7 @@
                 volume['id'])['volume']
             cls.volume_list.append(volume_details)
 
-    @test.idempotent_id('5866286f-3290-4cfd-a414-088aa6cdc469')
+    @decorators.idempotent_id('5866286f-3290-4cfd-a414-088aa6cdc469')
     def test_volume_list_param_tenant(self):
         # Test to list volumes from single tenant
         # Create a volume in admin tenant
diff --git a/tempest/api/volume/admin/v3/test_user_messages.py b/tempest/api/volume/admin/v3/test_user_messages.py
index 257a434..ed85d4d 100755
--- a/tempest/api/volume/admin/v3/test_user_messages.py
+++ b/tempest/api/volume/admin/v3/test_user_messages.py
@@ -16,7 +16,7 @@
 from tempest.api.volume.v3 import base
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -60,7 +60,7 @@
                                          'volume %s' % volume['id'])
         return message_id
 
-    @test.idempotent_id('50f29e6e-f363-42e1-8ad1-f67ae7fd4d5a')
+    @decorators.idempotent_id('50f29e6e-f363-42e1-8ad1-f67ae7fd4d5a')
     def test_list_messages(self):
         self._create_user_message()
         messages = self.messages_client.list_messages()['messages']
@@ -70,7 +70,7 @@
                 self.assertIn(key, message.keys(),
                               'Missing expected key %s' % key)
 
-    @test.idempotent_id('55a4a61e-c7b2-4ba0-a05d-b914bdef3070')
+    @decorators.idempotent_id('55a4a61e-c7b2-4ba0-a05d-b914bdef3070')
     def test_show_message(self):
         message_id = self._create_user_message()
         self.addCleanup(self.messages_client.delete_message, message_id)
@@ -80,7 +80,7 @@
         for key in MESSAGE_KEYS:
             self.assertIn(key, message.keys(), 'Missing expected key %s' % key)
 
-    @test.idempotent_id('c6eb6901-cdcc-490f-b735-4fe251842aed')
+    @decorators.idempotent_id('c6eb6901-cdcc-490f-b735-4fe251842aed')
     def test_delete_message(self):
         message_id = self._create_user_message()
         self.messages_client.delete_message(message_id)
diff --git a/tempest/api/volume/test_availability_zone.py b/tempest/api/volume/test_availability_zone.py
index ae4b8f9..25fe5ad 100644
--- a/tempest/api/volume/test_availability_zone.py
+++ b/tempest/api/volume/test_availability_zone.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.api.volume import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class AvailabilityZoneV2TestJSON(base.BaseVolumeTest):
@@ -25,7 +25,7 @@
         super(AvailabilityZoneV2TestJSON, cls).setup_clients()
         cls.client = cls.availability_zone_client
 
-    @test.idempotent_id('01f1ae88-eba9-4c6b-a011-6f7ace06b725')
+    @decorators.idempotent_id('01f1ae88-eba9-4c6b-a011-6f7ace06b725')
     def test_get_availability_zone_list(self):
         # List of availability zone
         availability_zone = (self.client.list_availability_zones()
diff --git a/tempest/api/volume/test_extensions.py b/tempest/api/volume/test_extensions.py
index f044124..ca86748 100644
--- a/tempest/api/volume/test_extensions.py
+++ b/tempest/api/volume/test_extensions.py
@@ -17,7 +17,7 @@
 
 from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -27,7 +27,7 @@
 
 class ExtensionsV2TestJSON(base.BaseVolumeTest):
 
-    @test.idempotent_id('94607eb0-43a5-47ca-82aa-736b41bd2e2c')
+    @decorators.idempotent_id('94607eb0-43a5-47ca-82aa-736b41bd2e2c')
     def test_list_extensions(self):
         # List of all extensions
         extensions = (self.volumes_extension_client.list_extensions()
diff --git a/tempest/api/volume/test_snapshot_metadata.py b/tempest/api/volume/test_snapshot_metadata.py
index d0fa07e..d5ad8d2 100644
--- a/tempest/api/volume/test_snapshot_metadata.py
+++ b/tempest/api/volume/test_snapshot_metadata.py
@@ -17,7 +17,7 @@
 
 from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -43,7 +43,7 @@
             self.snapshot['id'], metadata={})
         super(SnapshotV2MetadataTestJSON, self).tearDown()
 
-    @test.idempotent_id('a2f20f99-e363-4584-be97-bc33afb1a56c')
+    @decorators.idempotent_id('a2f20f99-e363-4584-be97-bc33afb1a56c')
     def test_crud_snapshot_metadata(self):
         # Create metadata for the snapshot
         metadata = {"key1": "value1",
@@ -78,7 +78,7 @@
                         'Delete one item metadata of the snapshot failed')
         self.assertNotIn("key3", body)
 
-    @test.idempotent_id('e8ff85c5-8f97-477f-806a-3ac364a949ed')
+    @decorators.idempotent_id('e8ff85c5-8f97-477f-806a-3ac364a949ed')
     def test_update_snapshot_metadata_item(self):
         # Update metadata item for the snapshot
         metadata = {"key1": "value1",
diff --git a/tempest/api/volume/test_volume_absolute_limits.py b/tempest/api/volume/test_volume_absolute_limits.py
index 35e0d56..36445b9 100644
--- a/tempest/api/volume/test_volume_absolute_limits.py
+++ b/tempest/api/volume/test_volume_absolute_limits.py
@@ -15,7 +15,7 @@
 
 from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 
 CONF = config.CONF
@@ -32,7 +32,7 @@
         # Create a shared volume for tests
         cls.volume = cls.create_volume()
 
-    @test.idempotent_id('8e943f53-e9d6-4272-b2e9-adcf2f7c29ad')
+    @decorators.idempotent_id('8e943f53-e9d6-4272-b2e9-adcf2f7c29ad')
     def test_get_volume_absolute_limits(self):
         # get volume limit for a tenant
         absolute_limits = \
diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py
index c125bb8..9e7b0a7 100644
--- a/tempest/api/volume/test_volume_metadata.py
+++ b/tempest/api/volume/test_volume_metadata.py
@@ -16,7 +16,7 @@
 from testtools import matchers
 
 from tempest.api.volume import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class VolumesV2MetadataTest(base.BaseVolumeTest):
@@ -32,7 +32,7 @@
         self.volumes_client.update_volume_metadata(self.volume['id'], {})
         super(VolumesV2MetadataTest, self).tearDown()
 
-    @test.idempotent_id('6f5b125b-f664-44bf-910f-751591fe5769')
+    @decorators.idempotent_id('6f5b125b-f664-44bf-910f-751591fe5769')
     def test_crud_volume_metadata(self):
         # Create metadata for the volume
         metadata = {"key1": "value1",
@@ -67,7 +67,7 @@
         self.assertThat(body.items(), matchers.ContainsAll(expected.items()),
                         'Delete one item metadata of the volume failed')
 
-    @test.idempotent_id('862261c5-8df4-475a-8c21-946e50e36a20')
+    @decorators.idempotent_id('862261c5-8df4-475a-8c21-946e50e36a20')
     def test_update_volume_metadata_item(self):
         # Update metadata item for the volume
         metadata = {"key1": "value1",
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index a8889e0..8d94cd2 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -17,7 +17,7 @@
 
 from tempest.api.volume import base
 from tempest.common import waiters
-from tempest import test
+from tempest.lib import decorators
 
 
 class VolumesV2TransfersTest(base.BaseVolumeTest):
@@ -33,7 +33,7 @@
         cls.alt_tenant_id = cls.alt_client.tenant_id
         cls.adm_client = cls.os_adm.volumes_client
 
-    @test.idempotent_id('4d75b645-a478-48b1-97c8-503f64242f1a')
+    @decorators.idempotent_id('4d75b645-a478-48b1-97c8-503f64242f1a')
     def test_create_get_list_accept_volume_transfer(self):
         # Create a volume first
         volume = self.create_volume()
@@ -62,7 +62,7 @@
         waiters.wait_for_volume_status(self.alt_client,
                                        volume['id'], 'available')
 
-    @test.idempotent_id('ab526943-b725-4c07-b875-8e8ef87a2c30')
+    @decorators.idempotent_id('ab526943-b725-4c07-b875-8e8ef87a2c30')
     def test_create_list_delete_volume_transfer(self):
         # Create a volume first
         volume = self.create_volume()
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index d8d6b9a..c0cc74d 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -18,6 +18,7 @@
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions
 from tempest import test
 
@@ -48,7 +49,7 @@
         # Create a test shared volume for attach/detach tests
         cls.volume = cls.create_volume()
 
-    @test.idempotent_id('fff42874-7db5-4487-a8e1-ddda5fb5288d')
+    @decorators.idempotent_id('fff42874-7db5-4487-a8e1-ddda5fb5288d')
     @test.attr(type='smoke')
     @test.services('compute')
     def test_attach_detach_volume_to_instance(self):
@@ -65,7 +66,7 @@
         waiters.wait_for_volume_status(self.client,
                                        self.volume['id'], 'available')
 
-    @test.idempotent_id('63e21b4c-0a0c-41f6-bfc3-7c2816815599')
+    @decorators.idempotent_id('63e21b4c-0a0c-41f6-bfc3-7c2816815599')
     def test_volume_bootable(self):
         # Verify that a volume bootable flag is retrieved
         for bool_bootable in [True, False]:
@@ -80,7 +81,7 @@
             self.assertEqual(str(bool_bootable).lower(),
                              fetched_volume['bootable'])
 
-    @test.idempotent_id('9516a2c8-9135-488c-8dd6-5677a7e5f371')
+    @decorators.idempotent_id('9516a2c8-9135-488c-8dd6-5677a7e5f371')
     @test.services('compute')
     def test_get_volume_attachment(self):
         # Create a server
@@ -107,7 +108,7 @@
         self.assertEqual(self.volume['id'], attachment['id'])
         self.assertEqual(self.volume['id'], attachment['volume_id'])
 
-    @test.idempotent_id('d8f1ca95-3d5b-44a3-b8ca-909691c9532d')
+    @decorators.idempotent_id('d8f1ca95-3d5b-44a3-b8ca-909691c9532d')
     @test.services('image')
     def test_volume_upload(self):
         # NOTE(gfidente): the volume uploaded in Glance comes from setUpClass,
@@ -126,7 +127,7 @@
         waiters.wait_for_volume_status(self.client,
                                        self.volume['id'], 'available')
 
-    @test.idempotent_id('92c4ef64-51b2-40c0-9f7e-4749fbaaba33')
+    @decorators.idempotent_id('92c4ef64-51b2-40c0-9f7e-4749fbaaba33')
     def test_reserve_unreserve_volume(self):
         # Mark volume as reserved.
         body = self.client.reserve_volume(self.volume['id'])
@@ -139,7 +140,7 @@
         body = self.client.show_volume(self.volume['id'])['volume']
         self.assertIn('available', body['status'])
 
-    @test.idempotent_id('fff74e1e-5bd3-4b33-9ea9-24c103bc3f59')
+    @decorators.idempotent_id('fff74e1e-5bd3-4b33-9ea9-24c103bc3f59')
     def test_volume_readonly_update(self):
         for readonly in [True, False]:
             # Update volume readonly
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 6dcde08..939f1ac 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -17,6 +17,7 @@
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -46,7 +47,7 @@
                                        'available')
         return restored_volume
 
-    @test.idempotent_id('a66eb488-8ee1-47d4-8e9f-575a095728c6')
+    @decorators.idempotent_id('a66eb488-8ee1-47d4-8e9f-575a095728c6')
     def test_volume_backup_create_get_detailed_list_restore_delete(self):
         # Create backup
         volume = self.create_volume()
@@ -75,7 +76,7 @@
 
         self.restore_backup(backup['id'])
 
-    @test.idempotent_id('07af8f6d-80af-44c9-a5dc-c8427b1b62e6')
+    @decorators.idempotent_id('07af8f6d-80af-44c9-a5dc-c8427b1b62e6')
     @test.services('compute')
     def test_backup_create_attached_volume(self):
         """Test backup create using force flag.
@@ -97,7 +98,7 @@
                                     name=backup_name, force=True)
         self.assertEqual(backup_name, backup['name'])
 
-    @test.idempotent_id('2a8ba340-dff2-4511-9db7-646f07156b15')
+    @decorators.idempotent_id('2a8ba340-dff2-4511-9db7-646f07156b15')
     def test_bootable_volume_backup_and_restore(self):
         # Create volume from image
         img_uuid = CONF.compute.image_ref
diff --git a/tempest/api/volume/test_volumes_clone.py b/tempest/api/volume/test_volumes_clone.py
index 2cedb4e..79a1a0a 100644
--- a/tempest/api/volume/test_volumes_clone.py
+++ b/tempest/api/volume/test_volumes_clone.py
@@ -15,7 +15,7 @@
 
 from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 
 CONF = config.CONF
@@ -29,7 +29,7 @@
         if not CONF.volume_feature_enabled.clone:
             raise cls.skipException("Cinder volume clones are disabled")
 
-    @test.idempotent_id('9adae371-a257-43a5-9555-dc7c88e66e0e')
+    @decorators.idempotent_id('9adae371-a257-43a5-9555-dc7c88e66e0e')
     def test_create_from_volume(self):
         # Creates a volume from another volume passing a size different from
         # the source volume.
@@ -45,7 +45,7 @@
         self.assertEqual(volume['source_volid'], src_vol['id'])
         self.assertEqual(int(volume['size']), src_size + 1)
 
-    @test.idempotent_id('cbbcd7c6-5a6c-481a-97ac-ca55ab715d16')
+    @decorators.idempotent_id('cbbcd7c6-5a6c-481a-97ac-ca55ab715d16')
     def test_create_from_bootable_volume(self):
         # Create volume from image
         img_uuid = CONF.compute.image_ref
diff --git a/tempest/api/volume/test_volumes_clone_negative.py b/tempest/api/volume/test_volumes_clone_negative.py
index 5c54e1e..fa827cd 100644
--- a/tempest/api/volume/test_volumes_clone_negative.py
+++ b/tempest/api/volume/test_volumes_clone_negative.py
@@ -15,9 +15,8 @@
 
 from tempest.api.volume import base
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions
-from tempest import test
-
 
 CONF = config.CONF
 
@@ -30,7 +29,7 @@
         if not CONF.volume_feature_enabled.clone:
             raise cls.skipException("Cinder volume clones are disabled")
 
-    @test.idempotent_id('9adae371-a257-43a5-459a-dc7c88e66e0e')
+    @decorators.idempotent_id('9adae371-a257-43a5-459a-dc7c88e66e0e')
     def test_create_from_volume_decreasing_size(self):
         # Creates a volume from another volume passing a size different from
         # the source volume.
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index c3d6dbb..20118df 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -15,12 +15,12 @@
 
 from tempest.api.volume import base
 from tempest.common import waiters
-from tempest import test
+from tempest.lib import decorators
 
 
 class VolumesV2ExtendTest(base.BaseVolumeTest):
 
-    @test.idempotent_id('9a36df71-a257-43a5-9555-dc7c88e66e0e')
+    @decorators.idempotent_id('9a36df71-a257-43a5-9555-dc7c88e66e0e')
     def test_volume_extend(self):
         # Extend Volume Test.
         self.volume = self.create_volume()
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 65e461c..d1a1c2f 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -20,6 +20,7 @@
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -118,12 +119,12 @@
             self.assertEqual('false', updated_volume['bootable'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('27fb0e9f-fb64-41dd-8bdb-1ffa762f0d51')
+    @decorators.idempotent_id('27fb0e9f-fb64-41dd-8bdb-1ffa762f0d51')
     def test_volume_create_get_update_delete(self):
         self._volume_create_get_update_delete(size=CONF.volume.volume_size)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('54a01030-c7fc-447c-86ee-c1182beae638')
+    @decorators.idempotent_id('54a01030-c7fc-447c-86ee-c1182beae638')
     @test.services('image')
     def test_volume_create_get_update_delete_from_image(self):
         image = self.compute_images_client.show_image(
@@ -133,7 +134,7 @@
         self._volume_create_get_update_delete(
             imageRef=CONF.compute.image_ref, size=disk_size)
 
-    @test.idempotent_id('3f591b4a-7dc6-444c-bd51-77469506b3a1')
+    @decorators.idempotent_id('3f591b4a-7dc6-444c-bd51-77469506b3a1')
     @testtools.skipUnless(CONF.volume_feature_enabled.clone,
                           'Cinder volume clones are disabled')
     def test_volume_create_get_update_delete_as_clone(self):
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 5e3f49f..d1da95d 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -19,6 +19,7 @@
 
 from tempest.api.volume import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -95,7 +96,7 @@
                         self.assertEqual(params[key], volume[key], msg)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('0b6ddd39-b948-471f-8038-4787978747c4')
+    @decorators.idempotent_id('0b6ddd39-b948-471f-8038-4787978747c4')
     def test_volume_list(self):
         # Get a list of Volumes
         # Fetch all volumes
@@ -103,14 +104,14 @@
         self.assertVolumesIn(fetched_list, self.volume_list,
                              fields=self.VOLUME_FIELDS)
 
-    @test.idempotent_id('adcbb5a7-5ad8-4b61-bd10-5380e111a877')
+    @decorators.idempotent_id('adcbb5a7-5ad8-4b61-bd10-5380e111a877')
     def test_volume_list_with_details(self):
         # Get a list of Volumes with details
         # Fetch all Volumes
         fetched_list = self.volumes_client.list_volumes(detail=True)['volumes']
         self.assertVolumesIn(fetched_list, self.volume_list)
 
-    @test.idempotent_id('a28e8da4-0b56-472f-87a8-0f4d3f819c02')
+    @decorators.idempotent_id('a28e8da4-0b56-472f-87a8-0f4d3f819c02')
     def test_volume_list_by_name(self):
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
         params = {self.name: volume[self.name]}
@@ -120,7 +121,7 @@
         self.assertEqual(fetched_vol[0][self.name],
                          volume[self.name])
 
-    @test.idempotent_id('2de3a6d4-12aa-403b-a8f2-fdeb42a89623')
+    @decorators.idempotent_id('2de3a6d4-12aa-403b-a8f2-fdeb42a89623')
     def test_volume_list_details_by_name(self):
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
         params = {self.name: volume[self.name]}
@@ -130,7 +131,7 @@
         self.assertEqual(fetched_vol[0][self.name],
                          volume[self.name])
 
-    @test.idempotent_id('39654e13-734c-4dab-95ce-7613bf8407ce')
+    @decorators.idempotent_id('39654e13-734c-4dab-95ce-7613bf8407ce')
     def test_volumes_list_by_status(self):
         params = {'status': 'available'}
         fetched_list = self.volumes_client.list_volumes(
@@ -139,7 +140,7 @@
         self.assertVolumesIn(fetched_list, self.volume_list,
                              fields=self.VOLUME_FIELDS)
 
-    @test.idempotent_id('2943f712-71ec-482a-bf49-d5ca06216b9f')
+    @decorators.idempotent_id('2943f712-71ec-482a-bf49-d5ca06216b9f')
     def test_volumes_list_details_by_status(self):
         params = {'status': 'available'}
         fetched_list = self.volumes_client.list_volumes(
@@ -148,7 +149,7 @@
             self.assertEqual('available', volume['status'])
         self.assertVolumesIn(fetched_list, self.volume_list)
 
-    @test.idempotent_id('2016a942-3020-40d7-95ce-7613bf8407ce')
+    @decorators.idempotent_id('2016a942-3020-40d7-95ce-7613bf8407ce')
     def test_volumes_list_by_bootable(self):
         """Check out volumes.
 
@@ -162,7 +163,7 @@
         self.assertVolumesIn(fetched_list, self.volume_list,
                              fields=self.VOLUME_FIELDS)
 
-    @test.idempotent_id('2016a939-72ec-482a-bf49-d5ca06216b9f')
+    @decorators.idempotent_id('2016a939-72ec-482a-bf49-d5ca06216b9f')
     def test_volumes_list_details_by_bootable(self):
         params = {'bootable': 'false'}
         fetched_list = self.volumes_client.list_volumes(
@@ -171,7 +172,7 @@
             self.assertEqual('false', volume['bootable'])
         self.assertVolumesIn(fetched_list, self.volume_list)
 
-    @test.idempotent_id('c0cfa863-3020-40d7-b587-e35f597d5d87')
+    @decorators.idempotent_id('c0cfa863-3020-40d7-b587-e35f597d5d87')
     def test_volumes_list_by_availability_zone(self):
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
         zone = volume['availability_zone']
@@ -182,7 +183,7 @@
         self.assertVolumesIn(fetched_list, self.volume_list,
                              fields=self.VOLUME_FIELDS)
 
-    @test.idempotent_id('e1b80d13-94f0-4ba2-a40e-386af29f8db1')
+    @decorators.idempotent_id('e1b80d13-94f0-4ba2-a40e-386af29f8db1')
     def test_volumes_list_details_by_availability_zone(self):
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
         zone = volume['availability_zone']
@@ -193,19 +194,19 @@
             self.assertEqual(zone, volume['availability_zone'])
         self.assertVolumesIn(fetched_list, self.volume_list)
 
-    @test.idempotent_id('b5ebea1b-0603-40a0-bb41-15fcd0a53214')
+    @decorators.idempotent_id('b5ebea1b-0603-40a0-bb41-15fcd0a53214')
     def test_volume_list_with_param_metadata(self):
         # Test to list volumes when metadata param is given
         params = {'metadata': self.metadata}
         self._list_by_param_value_and_assert(params)
 
-    @test.idempotent_id('1ca92d3c-4a8e-4b43-93f5-e4c7fb3b291d')
+    @decorators.idempotent_id('1ca92d3c-4a8e-4b43-93f5-e4c7fb3b291d')
     def test_volume_list_with_detail_param_metadata(self):
         # Test to list volumes details when metadata param is given
         params = {'metadata': self.metadata}
         self._list_by_param_value_and_assert(params, with_detail=True)
 
-    @test.idempotent_id('777c87c1-2fc4-4883-8b8e-5c0b951d1ec8')
+    @decorators.idempotent_id('777c87c1-2fc4-4883-8b8e-5c0b951d1ec8')
     def test_volume_list_param_display_name_and_status(self):
         # Test to list volume when display name and status param is given
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
@@ -213,7 +214,7 @@
                   'status': 'available'}
         self._list_by_param_value_and_assert(params)
 
-    @test.idempotent_id('856ab8ca-6009-4c37-b691-be1065528ad4')
+    @decorators.idempotent_id('856ab8ca-6009-4c37-b691-be1065528ad4')
     def test_volume_list_with_detail_param_display_name_and_status(self):
         # Test to list volume when name and status param is given
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index bcdbd22..0a095a9 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.volume import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -32,150 +33,146 @@
         cls.mountpoint = "/dev/vdc"
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f131c586-9448-44a4-a8b0-54ca838aa43e')
+    @decorators.idempotent_id('f131c586-9448-44a4-a8b0-54ca838aa43e')
     def test_volume_get_nonexistent_volume_id(self):
         # Should not be able to get a non-existent volume
         self.assertRaises(lib_exc.NotFound, self.volumes_client.show_volume,
                           data_utils.rand_uuid())
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('555efa6e-efcd-44ef-8a3b-4a7ca4837a29')
+    @decorators.idempotent_id('555efa6e-efcd-44ef-8a3b-4a7ca4837a29')
     def test_volume_delete_nonexistent_volume_id(self):
         # Should not be able to delete a non-existent Volume
         self.assertRaises(lib_exc.NotFound, self.volumes_client.delete_volume,
                           data_utils.rand_uuid())
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('1ed83a8a-682d-4dfb-a30e-ee63ffd6c049')
+    @decorators.idempotent_id('1ed83a8a-682d-4dfb-a30e-ee63ffd6c049')
     def test_create_volume_with_invalid_size(self):
         # Should not be able to create volume with invalid size
         # in request
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
-        metadata = {'Type': 'work'}
+        params = {self.name_field: v_name}
         self.assertRaises(lib_exc.BadRequest,
                           self.volumes_client.create_volume,
-                          size='#$%', display_name=v_name, metadata=metadata)
+                          size='#$%', params=params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9387686f-334f-4d31-a439-33494b9e2683')
+    @decorators.idempotent_id('9387686f-334f-4d31-a439-33494b9e2683')
     def test_create_volume_without_passing_size(self):
         # Should not be able to create volume without passing size
         # in request
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
-        metadata = {'Type': 'work'}
+        params = {self.name_field: v_name}
         self.assertRaises(lib_exc.BadRequest,
                           self.volumes_client.create_volume,
-                          size='', display_name=v_name, metadata=metadata)
+                          size='', params=params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('41331caa-eaf4-4001-869d-bc18c1869360')
+    @decorators.idempotent_id('41331caa-eaf4-4001-869d-bc18c1869360')
     def test_create_volume_with_size_zero(self):
         # Should not be able to create volume with size zero
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
-        metadata = {'Type': 'work'}
+        params = {self.name_field: v_name}
         self.assertRaises(lib_exc.BadRequest,
                           self.volumes_client.create_volume,
-                          size='0', display_name=v_name, metadata=metadata)
+                          size='0', params=params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('8b472729-9eba-446e-a83b-916bdb34bef7')
+    @decorators.idempotent_id('8b472729-9eba-446e-a83b-916bdb34bef7')
     def test_create_volume_with_size_negative(self):
         # Should not be able to create volume with size negative
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
-        metadata = {'Type': 'work'}
+        params = {self.name_field: v_name}
         self.assertRaises(lib_exc.BadRequest,
                           self.volumes_client.create_volume,
-                          size='-1', display_name=v_name, metadata=metadata)
+                          size='-1', params=params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('10254ed8-3849-454e-862e-3ab8e6aa01d2')
+    @decorators.idempotent_id('10254ed8-3849-454e-862e-3ab8e6aa01d2')
     def test_create_volume_with_nonexistent_volume_type(self):
         # Should not be able to create volume with non-existent volume type
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
-        metadata = {'Type': 'work'}
+        params = {self.name_field: v_name}
         self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
                           size='1', volume_type=data_utils.rand_uuid(),
-                          display_name=v_name, metadata=metadata)
+                          params=params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0c36f6ae-4604-4017-b0a9-34fdc63096f9')
+    @decorators.idempotent_id('0c36f6ae-4604-4017-b0a9-34fdc63096f9')
     def test_create_volume_with_nonexistent_snapshot_id(self):
         # Should not be able to create volume with non-existent snapshot
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
-        metadata = {'Type': 'work'}
+        params = {self.name_field: v_name}
         self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
                           size='1', snapshot_id=data_utils.rand_uuid(),
-                          display_name=v_name, metadata=metadata)
+                          params=params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('47c73e08-4be8-45bb-bfdf-0c4e79b88344')
+    @decorators.idempotent_id('47c73e08-4be8-45bb-bfdf-0c4e79b88344')
     def test_create_volume_with_nonexistent_source_volid(self):
         # Should not be able to create volume with non-existent source volume
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
-        metadata = {'Type': 'work'}
+        params = {self.name_field: v_name}
         self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
                           size='1', source_volid=data_utils.rand_uuid(),
-                          display_name=v_name, metadata=metadata)
+                          params=params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0186422c-999a-480e-a026-6a665744c30c')
+    @decorators.idempotent_id('0186422c-999a-480e-a026-6a665744c30c')
     def test_update_volume_with_nonexistent_volume_id(self):
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
-        metadata = {'Type': 'work'}
+        params = {self.name_field: v_name}
         self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
-                          volume_id=data_utils.rand_uuid(),
-                          display_name=v_name,
-                          metadata=metadata)
+                          volume_id=data_utils.rand_uuid(), params=params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e66e40d6-65e6-4e75-bdc7-636792fa152d')
+    @decorators.idempotent_id('e66e40d6-65e6-4e75-bdc7-636792fa152d')
     def test_update_volume_with_invalid_volume_id(self):
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
-        metadata = {'Type': 'work'}
+        params = {self.name_field: v_name}
         self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
                           volume_id=data_utils.rand_name('invalid'),
-                          display_name=v_name,
-                          metadata=metadata)
+                          params=params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('72aeca85-57a5-4c1f-9057-f320f9ea575b')
+    @decorators.idempotent_id('72aeca85-57a5-4c1f-9057-f320f9ea575b')
     def test_update_volume_with_empty_volume_id(self):
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
-        metadata = {'Type': 'work'}
+        params = {self.name_field: v_name}
         self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
-                          volume_id='', display_name=v_name,
-                          metadata=metadata)
+                          volume_id='', params=params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('30799cfd-7ee4-446c-b66c-45b383ed211b')
+    @decorators.idempotent_id('30799cfd-7ee4-446c-b66c-45b383ed211b')
     def test_get_invalid_volume_id(self):
         # Should not be able to get volume with invalid id
         self.assertRaises(lib_exc.NotFound, self.volumes_client.show_volume,
                           data_utils.rand_name('invalid'))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('c6c3db06-29ad-4e91-beb0-2ab195fe49e3')
+    @decorators.idempotent_id('c6c3db06-29ad-4e91-beb0-2ab195fe49e3')
     def test_get_volume_without_passing_volume_id(self):
         # Should not be able to get volume when empty ID is passed
         self.assertRaises(lib_exc.NotFound,
                           self.volumes_client.show_volume, '')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('1f035827-7c32-4019-9240-b4ec2dbd9dfd')
+    @decorators.idempotent_id('1f035827-7c32-4019-9240-b4ec2dbd9dfd')
     def test_delete_invalid_volume_id(self):
         # Should not be able to delete volume when invalid ID is passed
         self.assertRaises(lib_exc.NotFound, self.volumes_client.delete_volume,
                           data_utils.rand_name('invalid'))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('441a1550-5d44-4b30-af0f-a6d402f52026')
+    @decorators.idempotent_id('441a1550-5d44-4b30-af0f-a6d402f52026')
     def test_delete_volume_without_passing_volume_id(self):
         # Should not be able to delete volume when empty ID is passed
         self.assertRaises(lib_exc.NotFound,
                           self.volumes_client.delete_volume, '')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f5e56b0a-5d02-43c1-a2a7-c9b792c2e3f6')
+    @decorators.idempotent_id('f5e56b0a-5d02-43c1-a2a7-c9b792c2e3f6')
     @test.services('compute')
     def test_attach_volumes_with_nonexistent_volume_id(self):
         server = self.create_server(wait_until='ACTIVE')
@@ -187,14 +184,14 @@
                           mountpoint=self.mountpoint)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9f9c24e4-011d-46b5-b992-952140ce237a')
+    @decorators.idempotent_id('9f9c24e4-011d-46b5-b992-952140ce237a')
     def test_detach_volumes_with_invalid_volume_id(self):
         self.assertRaises(lib_exc.NotFound,
                           self.volumes_client.detach_volume,
                           'xxx')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e0c75c74-ee34-41a9-9288-2a2051452854')
+    @decorators.idempotent_id('e0c75c74-ee34-41a9-9288-2a2051452854')
     def test_volume_extend_with_size_smaller_than_original_size(self):
         # Extend volume with smaller size than original size.
         extend_size = 0
@@ -203,7 +200,7 @@
                           self.volume['id'], new_size=extend_size)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5d0b480d-e833-439f-8a5a-96ad2ed6f22f')
+    @decorators.idempotent_id('5d0b480d-e833-439f-8a5a-96ad2ed6f22f')
     def test_volume_extend_with_non_number_size(self):
         # Extend volume when size is non number.
         extend_size = 'abc'
@@ -212,7 +209,7 @@
                           self.volume['id'], new_size=extend_size)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('355218f1-8991-400a-a6bb-971239287d92')
+    @decorators.idempotent_id('355218f1-8991-400a-a6bb-971239287d92')
     def test_volume_extend_with_None_size(self):
         # Extend volume with None size.
         extend_size = None
@@ -221,7 +218,7 @@
                           self.volume['id'], new_size=extend_size)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('8f05a943-013c-4063-ac71-7baf561e82eb')
+    @decorators.idempotent_id('8f05a943-013c-4063-ac71-7baf561e82eb')
     def test_volume_extend_with_nonexistent_volume_id(self):
         # Extend volume size when volume is nonexistent.
         extend_size = int(self.volume['size']) + 1
@@ -229,7 +226,7 @@
                           data_utils.rand_uuid(), new_size=extend_size)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('aff8ba64-6d6f-4f2e-bc33-41a08ee9f115')
+    @decorators.idempotent_id('aff8ba64-6d6f-4f2e-bc33-41a08ee9f115')
     def test_volume_extend_without_passing_volume_id(self):
         # Extend volume size when passing volume id is None.
         extend_size = int(self.volume['size']) + 1
@@ -237,21 +234,21 @@
                           None, new_size=extend_size)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ac6084c0-0546-45f9-b284-38a367e0e0e2')
+    @decorators.idempotent_id('ac6084c0-0546-45f9-b284-38a367e0e0e2')
     def test_reserve_volume_with_nonexistent_volume_id(self):
         self.assertRaises(lib_exc.NotFound,
                           self.volumes_client.reserve_volume,
                           data_utils.rand_uuid())
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('eb467654-3dc1-4a72-9b46-47c29d22654c')
+    @decorators.idempotent_id('eb467654-3dc1-4a72-9b46-47c29d22654c')
     def test_unreserve_volume_with_nonexistent_volume_id(self):
         self.assertRaises(lib_exc.NotFound,
                           self.volumes_client.unreserve_volume,
                           data_utils.rand_uuid())
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('449c4ed2-ecdd-47bb-98dc-072aeccf158c')
+    @decorators.idempotent_id('449c4ed2-ecdd-47bb-98dc-072aeccf158c')
     def test_reserve_volume_with_negative_volume_status(self):
         # Mark volume as reserved.
         self.volumes_client.reserve_volume(self.volume['id'])
@@ -263,7 +260,7 @@
         self.volumes_client.unreserve_volume(self.volume['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0f4aa809-8c7b-418f-8fb3-84c7a5dfc52f')
+    @decorators.idempotent_id('0f4aa809-8c7b-418f-8fb3-84c7a5dfc52f')
     def test_list_volumes_with_nonexistent_name(self):
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
         params = {self.name_field: v_name}
@@ -272,7 +269,7 @@
         self.assertEqual(0, len(fetched_volume))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9ca17820-a0e7-4cbd-a7fa-f4468735e359')
+    @decorators.idempotent_id('9ca17820-a0e7-4cbd-a7fa-f4468735e359')
     def test_list_volumes_detail_with_nonexistent_name(self):
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
         params = {self.name_field: v_name}
@@ -282,7 +279,7 @@
         self.assertEqual(0, len(fetched_volume))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('143b279b-7522-466b-81be-34a87d564a7c')
+    @decorators.idempotent_id('143b279b-7522-466b-81be-34a87d564a7c')
     def test_list_volumes_with_invalid_status(self):
         params = {'status': 'null'}
         fetched_volume = self.volumes_client.list_volumes(
@@ -290,7 +287,7 @@
         self.assertEqual(0, len(fetched_volume))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ba94b27b-be3f-496c-a00e-0283b373fa75')
+    @decorators.idempotent_id('ba94b27b-be3f-496c-a00e-0283b373fa75')
     def test_list_volumes_detail_with_invalid_status(self):
         params = {'status': 'null'}
         fetched_volume = \
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 6f85891..f1ca722 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -13,6 +13,7 @@
 from tempest.api.volume import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -39,7 +40,7 @@
         self.snapshots_client.wait_for_resource_deletion(snapshot['id'])
         self.snapshots.remove(snapshot)
 
-    @test.idempotent_id('b467b54c-07a4-446d-a1cf-651dedcc3ff1')
+    @decorators.idempotent_id('b467b54c-07a4-446d-a1cf-651dedcc3ff1')
     @test.services('compute')
     def test_snapshot_create_with_volume_in_use(self):
         # Create a snapshot when volume status is in-use
@@ -53,7 +54,7 @@
         # Delete the snapshot
         self.cleanup_snapshot(snapshot)
 
-    @test.idempotent_id('8567b54c-4455-446d-a1cf-651ddeaa3ff2')
+    @decorators.idempotent_id('8567b54c-4455-446d-a1cf-651ddeaa3ff2')
     @test.services('compute')
     def test_snapshot_delete_with_volume_in_use(self):
         # Create a test instance
@@ -71,7 +72,7 @@
         self.cleanup_snapshot(snapshot3)
         self.cleanup_snapshot(snapshot2)
 
-    @test.idempotent_id('5210a1de-85a0-11e6-bb21-641c676a5d61')
+    @decorators.idempotent_id('5210a1de-85a0-11e6-bb21-641c676a5d61')
     @test.services('compute')
     def test_snapshot_create_offline_delete_online(self):
 
@@ -92,7 +93,7 @@
         self.cleanup_snapshot(snapshot1)
         self.cleanup_snapshot(snapshot2)
 
-    @test.idempotent_id('2a8abbe4-d871-46db-b049-c41f5af8216e')
+    @decorators.idempotent_id('2a8abbe4-d871-46db-b049-c41f5af8216e')
     def test_snapshot_create_get_list_update_delete(self):
         # Create a snapshot
         snapshot = self.create_snapshot(self.volume_origin['id'])
@@ -130,7 +131,7 @@
         # Delete the snapshot
         self.cleanup_snapshot(snapshot)
 
-    @test.idempotent_id('677863d1-3142-456d-b6ac-9924f667a7f4')
+    @decorators.idempotent_id('677863d1-3142-456d-b6ac-9924f667a7f4')
     def test_volume_from_snapshot(self):
         # Creates a volume a snapshot passing a size different from the source
         src_size = CONF.volume.volume_size
diff --git a/tempest/api/volume/test_volumes_snapshots_list.py b/tempest/api/volume/test_volumes_snapshots_list.py
index b831252..ff390ea 100644
--- a/tempest/api/volume/test_volumes_snapshots_list.py
+++ b/tempest/api/volume/test_volumes_snapshots_list.py
@@ -13,7 +13,6 @@
 from tempest.api.volume import base
 from tempest import config
 from tempest.lib import decorators
-from tempest import test
 
 CONF = config.CONF
 
@@ -56,7 +55,7 @@
         # Validating filtered snapshots length equals to expected_elements
         self.assertEqual(expected_elements, len(fetched_snap_list))
 
-    @test.idempotent_id('59f41f43-aebf-48a9-ab5d-d76340fab32b')
+    @decorators.idempotent_id('59f41f43-aebf-48a9-ab5d-d76340fab32b')
     def test_snapshots_list_with_params(self):
         """list snapshots with params."""
         # Verify list snapshots by display_name filter
@@ -72,7 +71,7 @@
                   self.name_field: self.snapshot[self.name_field]}
         self._list_by_param_values_and_assert(**params)
 
-    @test.idempotent_id('220a1022-1fcd-4a74-a7bd-6b859156cda2')
+    @decorators.idempotent_id('220a1022-1fcd-4a74-a7bd-6b859156cda2')
     def test_snapshots_list_details_with_params(self):
         """list snapshot details with params."""
         # Verify list snapshot details by display_name filter
@@ -86,12 +85,12 @@
                   self.name_field: self.snapshot[self.name_field]}
         self._list_by_param_values_and_assert(with_detail=True, **params)
 
-    @test.idempotent_id('db4d8e0a-7a2e-41cc-a712-961f6844e896')
+    @decorators.idempotent_id('db4d8e0a-7a2e-41cc-a712-961f6844e896')
     def test_snapshot_list_param_limit(self):
         # List returns limited elements
         self._list_snapshots_by_param_limit(limit=1, expected_elements=1)
 
-    @test.idempotent_id('a1427f61-420e-48a5-b6e3-0b394fa95400')
+    @decorators.idempotent_id('a1427f61-420e-48a5-b6e3-0b394fa95400')
     def test_snapshot_list_param_limit_equals_infinite(self):
         # List returns all elements when request limit exceeded
         # snapshots number
@@ -100,7 +99,7 @@
                                             expected_elements=len(snap_list))
 
     @decorators.skip_because(bug='1540893')
-    @test.idempotent_id('e3b44b7f-ae87-45b5-8a8c-66110eb24d0a')
+    @decorators.idempotent_id('e3b44b7f-ae87-45b5-8a8c-66110eb24d0a')
     def test_snapshot_list_param_limit_equals_zero(self):
         # List returns zero elements
         self._list_snapshots_by_param_limit(limit=0, expected_elements=0)
diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py
index 1f5bb0d..1e68848 100644
--- a/tempest/api/volume/test_volumes_snapshots_negative.py
+++ b/tempest/api/volume/test_volumes_snapshots_negative.py
@@ -13,6 +13,7 @@
 from tempest.api.volume import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -28,7 +29,7 @@
             raise cls.skipException("Cinder volume snapshots are disabled")
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e3e466af-70ab-4f4b-a967-ab04e3532ea7')
+    @decorators.idempotent_id('e3e466af-70ab-4f4b-a967-ab04e3532ea7')
     def test_create_snapshot_with_nonexistent_volume_id(self):
         # Create a snapshot with nonexistent volume id
         s_name = data_utils.rand_name(self.__class__.__name__ + '-snap')
@@ -38,7 +39,7 @@
                           display_name=s_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('bb9da53e-d335-4309-9c15-7e76fd5e4d6d')
+    @decorators.idempotent_id('bb9da53e-d335-4309-9c15-7e76fd5e4d6d')
     def test_create_snapshot_without_passing_volume_id(self):
         # Create a snapshot without passing volume id
         s_name = data_utils.rand_name(self.__class__.__name__ + '-snap')
@@ -46,7 +47,7 @@
                           self.snapshots_client.create_snapshot,
                           volume_id=None, display_name=s_name)
 
-    @test.idempotent_id('677863d1-34f9-456d-b6ac-9924f667a7f4')
+    @decorators.idempotent_id('677863d1-34f9-456d-b6ac-9924f667a7f4')
     def test_volume_from_snapshot_decreasing_size(self):
         # Creates a volume a snapshot passing a size different from the source
         src_size = CONF.volume.volume_size + 1
diff --git a/tempest/api/volume/v2/test_image_metadata.py b/tempest/api/volume/v2/test_image_metadata.py
index 1e7bb30..9c082b3 100644
--- a/tempest/api/volume/v2/test_image_metadata.py
+++ b/tempest/api/volume/v2/test_image_metadata.py
@@ -17,6 +17,7 @@
 
 from tempest.api.volume import base
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -30,7 +31,7 @@
         # Create a volume from image ID
         cls.volume = cls.create_volume(imageRef=CONF.compute.image_ref)
 
-    @test.idempotent_id('03efff0b-5c75-4822-8f10-8789ac15b13e')
+    @decorators.idempotent_id('03efff0b-5c75-4822-8f10-8789ac15b13e')
     @test.services('image')
     def test_update_image_metadata(self):
         # Update image metadata
diff --git a/tempest/api/volume/v2/test_volumes_list.py b/tempest/api/volume/v2/test_volumes_list.py
index 28ba941..9b17515 100644
--- a/tempest/api/volume/v2/test_volumes_list.py
+++ b/tempest/api/volume/v2/test_volumes_list.py
@@ -19,7 +19,6 @@
 
 from tempest.api.volume import base
 from tempest.lib import decorators
-from tempest import test
 
 
 class VolumesV2ListTestJSON(base.BaseVolumeTest):
@@ -46,7 +45,7 @@
             volume = cls.create_volume(metadata=cls.metadata)
             cls.volume_id_list.append(volume['id'])
 
-    @test.idempotent_id('2a7064eb-b9c3-429b-b888-33928fc5edd3')
+    @decorators.idempotent_id('2a7064eb-b9c3-429b-b888-33928fc5edd3')
     def test_volume_list_details_with_multiple_params(self):
         # List volumes detail using combined condition
         def _list_details_with_multiple_params(limit=2,
@@ -169,15 +168,15 @@
                                  'missing ids %s' % remaining)
                 break
 
-    @test.idempotent_id('e9138a2c-f67b-4796-8efa-635c196d01de')
+    @decorators.idempotent_id('e9138a2c-f67b-4796-8efa-635c196d01de')
     def test_volume_list_details_pagination(self):
         self._test_pagination('volumes', ids=self.volume_id_list, detail=True)
 
-    @test.idempotent_id('af55e775-8e4b-4feb-8719-215c43b0238c')
+    @decorators.idempotent_id('af55e775-8e4b-4feb-8719-215c43b0238c')
     def test_volume_list_pagination(self):
         self._test_pagination('volumes', ids=self.volume_id_list, detail=False)
 
-    @test.idempotent_id('46eff077-100b-427f-914e-3db2abcdb7e2')
+    @decorators.idempotent_id('46eff077-100b-427f-914e-3db2abcdb7e2')
     @decorators.skip_because(bug='1572765')
     def test_volume_list_with_detail_param_marker(self):
         # Choosing a random volume from a list of volumes for 'marker'
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index 8303caf..865db39 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -26,14 +26,15 @@
 LOG = logging.getLogger(__name__)
 
 
+def _get_task_state(body):
+    return body.get('OS-EXT-STS:task_state', None)
+
+
 # NOTE(afazekas): This function needs to know a token and a subject.
 def wait_for_server_status(client, server_id, status, ready_wait=True,
                            extra_timeout=0, raise_on_error=True):
     """Waits for a server to reach a given status."""
 
-    def _get_task_state(body):
-        return body.get('OS-EXT-STS:task_state', None)
-
     # NOTE(afazekas): UNKNOWN status possible on ERROR
     # or in a very early stage.
     body = client.show_server(server_id)['server']
@@ -99,21 +100,33 @@
 
 def wait_for_server_termination(client, server_id, ignore_error=False):
     """Waits for server to reach termination."""
+    try:
+        body = client.show_server(server_id)['server']
+    except lib_exc.NotFound:
+        return
+    old_status = server_status = body['status']
+    old_task_state = task_state = _get_task_state(body)
     start_time = int(time.time())
     while True:
+        time.sleep(client.build_interval)
         try:
             body = client.show_server(server_id)['server']
         except lib_exc.NotFound:
             return
-
         server_status = body['status']
+        task_state = _get_task_state(body)
+        if (server_status != old_status) or (task_state != old_task_state):
+            LOG.info('State transition "%s" ==> "%s" after %d second wait',
+                     '/'.join((old_status, str(old_task_state))),
+                     '/'.join((server_status, str(task_state))),
+                     time.time() - start_time)
         if server_status == 'ERROR' and not ignore_error:
             raise exceptions.BuildErrorException(server_id=server_id)
 
         if int(time.time()) - start_time >= client.build_timeout:
             raise lib_exc.TimeoutException
-
-        time.sleep(client.build_interval)
+        old_status = server_status
+        old_task_state = task_state
 
 
 def wait_for_image_status(client, image_id, status):
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 43f919a..45bbc11 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -25,6 +25,10 @@
     message = "Server %(server_id)s failed to build and is in ERROR status"
 
 
+class SnapshotNotFoundException(exceptions.TempestException):
+    message = "Server snapshot image %(image_id)s not found."
+
+
 class ImageKilledException(exceptions.TempestException):
     message = "Image %(image_id)s 'killed' while waiting for '%(status)s'"
 
diff --git a/tempest/lib/api_schema/response/compute/v2_1/availability_zone.py b/tempest/lib/api_schema/response/compute/v2_1/availability_zone.py
index f7b77a1..0dc28c3 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/availability_zone.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/availability_zone.py
@@ -51,7 +51,7 @@
 }
 
 detail = {
-    'type': 'object',
+    'type': ['object', 'null'],
     'patternProperties': {
         # NOTE: Here is for a hostname
         '^[a-zA-Z0-9-_.]+$': {
diff --git a/tempest/lib/services/identity/v3/roles_client.py b/tempest/lib/services/identity/v3/roles_client.py
index f1339dd..0df23ce 100644
--- a/tempest/lib/services/identity/v3/roles_client.py
+++ b/tempest/lib/services/identity/v3/roles_client.py
@@ -190,3 +190,40 @@
                                (domain_id, group_id, role_id))
         self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp)
+
+    def create_role_inference_rule(self, prior_role, implies_role):
+        """Create a role inference rule."""
+        resp, body = self.put('roles/%s/implies/%s' %
+                              (prior_role, implies_role), None)
+        self.expected_success(201, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_role_inference_rule(self, prior_role, implies_role):
+        """Get a role inference rule."""
+        resp, body = self.get('roles/%s/implies/%s' %
+                              (prior_role, implies_role))
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_role_inferences_rules(self, prior_role):
+        """List the inferences rules from a role."""
+        resp, body = self.get('roles/%s/implies' % prior_role)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_role_inference_rule(self, prior_role, implies_role):
+        """Check a role inference rule."""
+        resp, body = self.head('roles/%s/implies/%s' %
+                               (prior_role, implies_role))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def delete_role_inference_rule(self, prior_role, implies_role):
+        """Delete a role inference rule."""
+        resp, body = self.delete('roles/%s/implies/%s' %
+                                 (prior_role, implies_role))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 076ac81..6014c8c 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -117,7 +117,7 @@
         return body['keypair']
 
     def create_server(self, name=None, image_id=None, flavor=None,
-                      validatable=False, wait_until=None,
+                      validatable=False, wait_until='ACTIVE',
                       clients=None, **kwargs):
         """Wrapper utility that returns a test server.
 
@@ -708,13 +708,11 @@
             raise cls.skipException('Neutron not available')
 
     def _create_network(self, networks_client=None,
-                        routers_client=None, tenant_id=None,
+                        tenant_id=None,
                         namestart='network-smoke-',
                         port_security_enabled=True):
         if not networks_client:
             networks_client = self.networks_client
-        if not routers_client:
-            routers_client = self.routers_client
         if not tenant_id:
             tenant_id = networks_client.tenant_id
         name = data_utils.rand_name(namestart)
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 8de3561..50fe9c8 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -15,6 +15,7 @@
 
 from tempest.common import tempest_fixtures as fixtures
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -95,7 +96,7 @@
         self.assertEqual(aggregate['availability_zone'], availability_zone)
         return aggregate
 
-    @test.idempotent_id('cb2b4c4f-0c7c-4164-bdde-6285b302a081')
+    @decorators.idempotent_id('cb2b4c4f-0c7c-4164-bdde-6285b302a081')
     @test.services('compute')
     def test_aggregate_basic_ops(self):
         self.useFixture(fixtures.LockFixture('availability_zone'))
diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py
index 1659ebe..da29485 100644
--- a/tempest/scenario/test_encrypted_cinder_volumes.py
+++ b/tempest/scenario/test_encrypted_cinder_volumes.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest import config
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -45,9 +46,7 @@
         image = self.glance_image_create()
         keypair = self.create_keypair()
 
-        return self.create_server(image_id=image,
-                                  key_name=keypair['name'],
-                                  wait_until='ACTIVE')
+        return self.create_server(image_id=image, key_name=keypair['name'])
 
     def create_encrypted_volume(self, encryption_provider, volume_type):
         volume_type = self.create_volume_type(name=volume_type)
@@ -62,7 +61,7 @@
         attached_volume = self.nova_volume_attach(server, volume)
         self.nova_volume_detach(server, attached_volume)
 
-    @test.idempotent_id('79165fb4-5534-4b9d-8429-97ccffb8f86e')
+    @decorators.idempotent_id('79165fb4-5534-4b9d-8429-97ccffb8f86e')
     @test.services('compute', 'volume', 'image')
     def test_encrypted_cinder_volumes_luks(self):
         server = self.launch_instance()
@@ -71,7 +70,7 @@
                                               volume_type='luks')
         self.attach_detach_volume(server, volume)
 
-    @test.idempotent_id('cbc752ed-b716-4717-910f-956cce965722')
+    @decorators.idempotent_id('cbc752ed-b716-4717-910f-956cce965722')
     @test.services('compute', 'volume', 'image')
     def test_encrypted_cinder_volumes_cryptsetup(self):
         server = self.launch_instance()
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index c454ae2..738ed61 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -17,6 +17,7 @@
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions
 from tempest.scenario import manager
 from tempest import test
@@ -97,15 +98,13 @@
                         address['addr'] == floating_ip['ip']):
                     return address
 
-    @test.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8')
+    @decorators.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8')
     @test.services('compute', 'volume', 'image', 'network')
     def test_minimum_basic_scenario(self):
         image = self.glance_image_create()
         keypair = self.create_keypair()
 
-        server = self.create_server(image_id=image,
-                                    key_name=keypair['name'],
-                                    wait_until='ACTIVE')
+        server = self.create_server(image_id=image, key_name=keypair['name'])
         servers = self.servers_client.list_servers()['servers']
         self.assertIn(server['id'], [x['id'] for x in servers])
 
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index 1279484..f8e7742 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -17,6 +17,7 @@
 
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -64,8 +65,7 @@
         server = self.create_server(
             networks=[{'uuid': network['id']}],
             key_name=keypair['name'],
-            security_groups=security_groups,
-            wait_until='ACTIVE')
+            security_groups=security_groups)
         return server
 
     def _setup_network(self, server, keypair):
@@ -104,7 +104,7 @@
         body = self.admin_servers_client.show_server(server_id)['server']
         return body['OS-EXT-SRV-ATTR:host']
 
-    @test.idempotent_id('61f1aa9a-1573-410e-9054-afa557cab021')
+    @decorators.idempotent_id('61f1aa9a-1573-410e-9054-afa557cab021')
     @test.services('compute', 'network')
     def test_server_connectivity_stop_start(self):
         keypair = self.create_keypair()
@@ -119,7 +119,7 @@
         self._wait_server_status_and_check_network_connectivity(
             server, keypair, floating_ip)
 
-    @test.idempotent_id('7b6860c2-afa3-4846-9522-adeb38dfbe08')
+    @decorators.idempotent_id('7b6860c2-afa3-4846-9522-adeb38dfbe08')
     @test.services('compute', 'network')
     def test_server_connectivity_reboot(self):
         keypair = self.create_keypair()
@@ -129,7 +129,7 @@
         self._wait_server_status_and_check_network_connectivity(
             server, keypair, floating_ip)
 
-    @test.idempotent_id('88a529c2-1daa-4c85-9aec-d541ba3eb699')
+    @decorators.idempotent_id('88a529c2-1daa-4c85-9aec-d541ba3eb699')
     @test.services('compute', 'network')
     def test_server_connectivity_rebuild(self):
         keypair = self.create_keypair()
@@ -141,7 +141,7 @@
         self._wait_server_status_and_check_network_connectivity(
             server, keypair, floating_ip)
 
-    @test.idempotent_id('2b2642db-6568-4b35-b812-eceed3fa20ce')
+    @decorators.idempotent_id('2b2642db-6568-4b35-b812-eceed3fa20ce')
     @testtools.skipUnless(CONF.compute_feature_enabled.pause,
                           'Pause is not available.')
     @test.services('compute', 'network')
@@ -158,7 +158,7 @@
         self._wait_server_status_and_check_network_connectivity(
             server, keypair, floating_ip)
 
-    @test.idempotent_id('5cdf9499-541d-4923-804e-b9a60620a7f0')
+    @decorators.idempotent_id('5cdf9499-541d-4923-804e-b9a60620a7f0')
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
                           'Suspend is not available.')
     @test.services('compute', 'network')
@@ -175,7 +175,7 @@
         self._wait_server_status_and_check_network_connectivity(
             server, keypair, floating_ip)
 
-    @test.idempotent_id('719eb59d-2f42-4b66-b8b1-bb1254473967')
+    @decorators.idempotent_id('719eb59d-2f42-4b66-b8b1-bb1254473967')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize is not available.')
     @test.services('compute', 'network')
@@ -195,7 +195,7 @@
         self._wait_server_status_and_check_network_connectivity(
             server, keypair, floating_ip)
 
-    @test.idempotent_id('a4858f6c-401e-4155-9a49-d5cd053d1a2f')
+    @decorators.idempotent_id('a4858f6c-401e-4155-9a49-d5cd053d1a2f')
     @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
                           'Cold migration is not available.')
     @testtools.skipUnless(CONF.compute.min_compute_nodes > 1,
@@ -220,7 +220,7 @@
 
         self.assertNotEqual(src_host, dst_host)
 
-    @test.idempotent_id('25b188d7-0183-4b1e-a11d-15840c8e2fd6')
+    @decorators.idempotent_id('25b188d7-0183-4b1e-a11d-15840c8e2fd6')
     @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
                           'Cold migration is not available.')
     @testtools.skipUnless(CONF.compute.min_compute_nodes > 1,
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index f9aa3e7..e6a5f51 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -160,8 +160,7 @@
         server = self.create_server(
             networks=[network],
             key_name=keypair['name'],
-            security_groups=security_groups,
-            wait_until='ACTIVE')
+            security_groups=security_groups)
         self.servers.append(server)
         return server
 
@@ -354,7 +353,7 @@
                 raise
 
     @test.attr(type='smoke')
-    @test.idempotent_id('f323b3ba-82f8-4db7-8ea6-6a895869ec49')
+    @decorators.idempotent_id('f323b3ba-82f8-4db7-8ea6-6a895869ec49')
     @test.services('compute', 'network')
     def test_network_basic_ops(self):
         """Basic network operation test
@@ -406,7 +405,7 @@
                                                msg="after re-associate "
                                                    "floating ip")
 
-    @test.idempotent_id('b158ea55-472e-4086-8fa9-c64ac0c6c1d0')
+    @decorators.idempotent_id('b158ea55-472e-4086-8fa9-c64ac0c6c1d0')
     @testtools.skipUnless(test.is_extension_enabled('net-mtu', 'network'),
                           'No way to calculate MTU for networks')
     @test.services('compute', 'network')
@@ -416,7 +415,7 @@
         self.check_public_network_connectivity(
             should_connect=True, mtu=self.network['mtu'])
 
-    @test.idempotent_id('1546850e-fbaa-42f5-8b5f-03d8a6a95f15')
+    @decorators.idempotent_id('1546850e-fbaa-42f5-8b5f-03d8a6a95f15')
     @testtools.skipIf(CONF.network.shared_physical_network,
                       'Connectivity can only be tested when in a '
                       'multitenant network environment')
@@ -469,7 +468,7 @@
         self._check_network_internal_connectivity(network=self.new_net,
                                                   should_connect=True)
 
-    @test.idempotent_id('c5adff73-e961-41f1-b4a9-343614f18cfa')
+    @decorators.idempotent_id('c5adff73-e961-41f1-b4a9-343614f18cfa')
     @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
                           'NIC hotplug not available')
     @testtools.skipIf(CONF.network.port_vnic_type in ['direct', 'macvtap'],
@@ -492,7 +491,7 @@
         self._hotplug_server()
         self._check_network_internal_connectivity(network=self.new_net)
 
-    @test.idempotent_id('04b9fe4e-85e8-4aea-b937-ea93885ac59f')
+    @decorators.idempotent_id('04b9fe4e-85e8-4aea-b937-ea93885ac59f')
     @testtools.skipIf(CONF.network.shared_physical_network,
                       'Router state can be altered only with multitenant '
                       'networks capabilities')
@@ -524,7 +523,7 @@
             should_connect=True, msg="after updating "
             "admin_state_up of router to True")
 
-    @test.idempotent_id('d8bb918e-e2df-48b2-97cd-b73c95450980')
+    @decorators.idempotent_id('d8bb918e-e2df-48b2-97cd-b73c95450980')
     @testtools.skipIf(CONF.network.shared_physical_network,
                       'network isolation not available')
     @testtools.skipUnless(CONF.scenario.dhcp_client,
@@ -607,7 +606,7 @@
                         msg="DHCP renewal failed to fetch "
                             "new DNS nameservers")
 
-    @test.idempotent_id('f5dfcc22-45fd-409f-954c-5bd500d7890b')
+    @decorators.idempotent_id('f5dfcc22-45fd-409f-954c-5bd500d7890b')
     @testtools.skipUnless(CONF.network_feature_enabled.port_admin_state_change,
                           "Changing a port's admin state is not supported "
                           "by the test environment")
@@ -654,7 +653,7 @@
         self._check_remote_connectivity(ssh_client, dest=server_pip,
                                         should_succeed=True)
 
-    @test.idempotent_id('759462e1-8535-46b0-ab3a-33aa45c55aaa')
+    @decorators.idempotent_id('759462e1-8535-46b0-ab3a-33aa45c55aaa')
     @test.services('compute', 'network')
     def test_preserve_preexisting_port(self):
         """Test preserve pre-existing port
@@ -705,7 +704,7 @@
         self.assertEqual(port['id'], port_list[0]['id'])
 
     @test.requires_ext(service='network', extension='l3_agent_scheduler')
-    @test.idempotent_id('2e788c46-fb3f-4ac9-8f82-0561555bea73')
+    @decorators.idempotent_id('2e788c46-fb3f-4ac9-8f82-0561555bea73')
     @test.services('compute', 'network')
     def test_router_rescheduling(self):
         """Tests that router can be removed from agent and add to a new agent.
@@ -782,7 +781,7 @@
     @test.requires_ext(service='network', extension='port-security')
     @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
                           'NIC hotplug not available')
-    @test.idempotent_id('7c0bb1a2-d053-49a4-98f9-ca1a1d849f63')
+    @decorators.idempotent_id('7c0bb1a2-d053-49a4-98f9-ca1a1d849f63')
     @test.services('compute', 'network')
     def test_port_security_macspoofing_port(self):
         """Tests port_security extension enforces mac spoofing
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 7acf107..2d6ea75 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -16,10 +16,10 @@
 
 from tempest import config
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
-
 CONF = config.CONF
 
 
@@ -126,8 +126,7 @@
         srv = self.create_server(
             key_name=self.keypair['name'],
             security_groups=[{'name': self.sec_grp['name']}],
-            networks=[{'uuid': n['id']} for n in networks],
-            wait_until='ACTIVE')
+            networks=[{'uuid': n['id']} for n in networks])
         fip = self.create_floating_ip(thing=srv)
         ips = self.define_server_ips(srv=srv)
         ssh = self.get_remote_client(
@@ -211,48 +210,48 @@
         )
 
     @test.attr(type='slow')
-    @test.idempotent_id('2c92df61-29f0-4eaa-bee3-7c65bef62a43')
+    @decorators.idempotent_id('2c92df61-29f0-4eaa-bee3-7c65bef62a43')
     @test.services('compute', 'network')
     def test_slaac_from_os(self):
         self._prepare_and_test(address6_mode='slaac')
 
     @test.attr(type='slow')
-    @test.idempotent_id('d7e1f858-187c-45a6-89c9-bdafde619a9f')
+    @decorators.idempotent_id('d7e1f858-187c-45a6-89c9-bdafde619a9f')
     @test.services('compute', 'network')
     def test_dhcp6_stateless_from_os(self):
         self._prepare_and_test(address6_mode='dhcpv6-stateless')
 
     @test.attr(type='slow')
-    @test.idempotent_id('7ab23f41-833b-4a16-a7c9-5b42fe6d4123')
+    @decorators.idempotent_id('7ab23f41-833b-4a16-a7c9-5b42fe6d4123')
     @test.services('compute', 'network')
     def test_multi_prefix_dhcpv6_stateless(self):
         self._prepare_and_test(address6_mode='dhcpv6-stateless', n_subnets6=2)
 
     @test.attr(type='slow')
-    @test.idempotent_id('dec222b1-180c-4098-b8c5-cc1b8342d611')
+    @decorators.idempotent_id('dec222b1-180c-4098-b8c5-cc1b8342d611')
     @test.services('compute', 'network')
     def test_multi_prefix_slaac(self):
         self._prepare_and_test(address6_mode='slaac', n_subnets6=2)
 
     @test.attr(type='slow')
-    @test.idempotent_id('b6399d76-4438-4658-bcf5-0d6c8584fde2')
+    @decorators.idempotent_id('b6399d76-4438-4658-bcf5-0d6c8584fde2')
     @test.services('compute', 'network')
     def test_dualnet_slaac_from_os(self):
         self._prepare_and_test(address6_mode='slaac', dualnet=True)
 
     @test.attr(type='slow')
-    @test.idempotent_id('76f26acd-9688-42b4-bc3e-cd134c4cb09e')
+    @decorators.idempotent_id('76f26acd-9688-42b4-bc3e-cd134c4cb09e')
     @test.services('compute', 'network')
     def test_dualnet_dhcp6_stateless_from_os(self):
         self._prepare_and_test(address6_mode='dhcpv6-stateless', dualnet=True)
 
-    @test.idempotent_id('cf1c4425-766b-45b8-be35-e2959728eb00')
+    @decorators.idempotent_id('cf1c4425-766b-45b8-be35-e2959728eb00')
     @test.services('compute', 'network')
     def test_dualnet_multi_prefix_dhcpv6_stateless(self):
         self._prepare_and_test(address6_mode='dhcpv6-stateless', n_subnets6=2,
                                dualnet=True)
 
-    @test.idempotent_id('9178ad42-10e4-47e9-8987-e02b170cc5cd')
+    @decorators.idempotent_id('9178ad42-10e4-47e9-8987-e02b170cc5cd')
     @test.services('compute', 'network')
     def test_dualnet_multi_prefix_slaac(self):
         self._prepare_and_test(address6_mode='slaac', n_subnets6=2,
diff --git a/tempest/scenario/test_object_storage_basic_ops.py b/tempest/scenario/test_object_storage_basic_ops.py
index 1d2b2b6..c989e01 100644
--- a/tempest/scenario/test_object_storage_basic_ops.py
+++ b/tempest/scenario/test_object_storage_basic_ops.py
@@ -13,12 +13,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
 
 class TestObjectStorageBasicOps(manager.ObjectStorageScenarioTest):
-    @test.idempotent_id('b920faf1-7b8a-4657-b9fe-9c4512bfb381')
+    @decorators.idempotent_id('b920faf1-7b8a-4657-b9fe-9c4512bfb381')
     @test.services('object_storage')
     def test_swift_basic_ops(self):
         """Test swift basic ops.
@@ -44,7 +45,7 @@
                                               not_present_obj=[obj_name])
         self.delete_container(container_name)
 
-    @test.idempotent_id('916c7111-cb1f-44b2-816d-8f760e4ea910')
+    @decorators.idempotent_id('916c7111-cb1f-44b2-816d-8f760e4ea910')
     @test.services('object_storage')
     def test_swift_acl_anonymous_download(self):
         """This test will cover below steps:
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index f8c5c0a..fda407c 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -18,6 +18,7 @@
 from tempest.common.utils import data_utils
 from tempest.common.utils import net_info
 from tempest import config
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -262,7 +263,6 @@
             networks=[{'uuid': tenant.network["id"]}],
             key_name=tenant.keypair['name'],
             security_groups=security_groups_names,
-            wait_until='ACTIVE',
             clients=tenant.manager,
             **kwargs)
         if 'security_groups' in server:
@@ -459,7 +459,7 @@
         subnet_id = tenant.subnet['id']
         self.assertIn((subnet_id, server_ip, mac_addr), port_detail_list)
 
-    @test.idempotent_id('e79f879e-debb-440c-a7e4-efeda05b6848')
+    @decorators.idempotent_id('e79f879e-debb-440c-a7e4-efeda05b6848')
     @test.services('compute', 'network')
     def test_cross_tenant_traffic(self):
         if not self.credentials_provider.is_multi_tenant():
@@ -480,7 +480,7 @@
                 self._log_console_output(servers=tenant.servers)
             raise
 
-    @test.idempotent_id('63163892-bbf6-4249-aa12-d5ea1f8f421b')
+    @decorators.idempotent_id('63163892-bbf6-4249-aa12-d5ea1f8f421b')
     @test.services('compute', 'network')
     def test_in_tenant_traffic(self):
         try:
@@ -494,7 +494,7 @@
                 self._log_console_output(servers=tenant.servers)
             raise
 
-    @test.idempotent_id('f4d556d7-1526-42ad-bafb-6bebf48568f6')
+    @decorators.idempotent_id('f4d556d7-1526-42ad-bafb-6bebf48568f6')
     @test.services('compute', 'network')
     def test_port_update_new_security_group(self):
         """Verifies the traffic after updating the vm port
@@ -547,7 +547,7 @@
                 self._log_console_output(servers=tenant.servers)
             raise
 
-    @test.idempotent_id('d2f77418-fcc4-439d-b935-72eca704e293')
+    @decorators.idempotent_id('d2f77418-fcc4-439d-b935-72eca704e293')
     @test.services('compute', 'network')
     def test_multiple_security_groups(self):
         """Verify multiple security groups and checks that rules
@@ -580,7 +580,7 @@
                                    should_connect=True)
 
     @test.requires_ext(service='network', extension='port-security')
-    @test.idempotent_id('7c811dcc-263b-49a3-92d2-1b4d8405f50c')
+    @decorators.idempotent_id('7c811dcc-263b-49a3-92d2-1b4d8405f50c')
     @test.services('compute', 'network')
     def test_port_security_disable_security_group(self):
         """Verify the default security group rules is disabled."""
@@ -619,7 +619,7 @@
             raise
 
     @test.requires_ext(service='network', extension='port-security')
-    @test.idempotent_id('13ccf253-e5ad-424b-9c4a-97b88a026699')
+    @decorators.idempotent_id('13ccf253-e5ad-424b-9c4a-97b88a026699')
     @testtools.skipUnless(
         CONF.compute_feature_enabled.allow_port_security_disabled,
         'Port security must be enabled.')
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index 504d72b..4d9e59c 100644
--- a/tempest/scenario/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -18,6 +18,7 @@
 
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -47,13 +48,13 @@
         cls.set_network_resources()
         super(TestServerAdvancedOps, cls).setup_credentials()
 
-    @test.idempotent_id('e6c28180-7454-4b59-b188-0257af08a63b')
+    @decorators.idempotent_id('e6c28180-7454-4b59-b188-0257af08a63b')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize is not available.')
     @test.services('compute', 'volume')
     def test_resize_volume_backed_server_confirm(self):
         # We create an instance for use in this test
-        instance = self.create_server(wait_until='ACTIVE', volume_backed=True)
+        instance = self.create_server(volume_backed=True)
         instance_id = instance['id']
         resize_flavor = CONF.compute.flavor_ref_alt
         LOG.debug("Resizing instance %s from flavor %s to flavor %s",
@@ -68,13 +69,13 @@
         waiters.wait_for_server_status(self.servers_client, instance_id,
                                        'ACTIVE')
 
-    @test.idempotent_id('949da7d5-72c8-4808-8802-e3d70df98e2c')
+    @decorators.idempotent_id('949da7d5-72c8-4808-8802-e3d70df98e2c')
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
                           'Suspend is not available.')
     @test.services('compute')
     def test_server_sequence_suspend_resume(self):
         # We create an instance for use in this test
-        instance = self.create_server(wait_until='ACTIVE')
+        instance = self.create_server()
         instance_id = instance['id']
         LOG.debug("Suspending instance %s. Current status: %s",
                   instance_id, instance['status'])
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 4a938f9..8a3b70d 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -20,6 +20,7 @@
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions
 from tempest.scenario import manager
 from tempest import test
@@ -124,7 +125,7 @@
             # TODO(clarkb) construct network_data from known network
             # instance info and do direct comparison.
 
-    @test.idempotent_id('7fff3fb3-91d8-4fd0-bd7d-0204f1f180ba')
+    @decorators.idempotent_id('7fff3fb3-91d8-4fd0-bd7d-0204f1f180ba')
     @test.attr(type='smoke')
     @test.services('compute', 'network')
     def test_server_basic_ops(self):
@@ -137,8 +138,7 @@
             key_name=keypair['name'],
             security_groups=[{'name': security_group['name']}],
             config_drive=CONF.compute_feature_enabled.config_drive,
-            metadata=self.md,
-            wait_until='ACTIVE')
+            metadata=self.md)
         self.verify_ssh(keypair)
         self.verify_metadata()
         self.verify_metadata_on_config_drive()
diff --git a/tempest/scenario/test_server_multinode.py b/tempest/scenario/test_server_multinode.py
index 170d220..9cc89a4 100644
--- a/tempest/scenario/test_server_multinode.py
+++ b/tempest/scenario/test_server_multinode.py
@@ -15,6 +15,7 @@
 
 
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions
 from tempest.scenario import manager
 from tempest import test
@@ -43,7 +44,7 @@
         # scheduler hint, which is admin_only by default
         cls.servers_client = cls.admin_manager.servers_client
 
-    @test.idempotent_id('9cecbe35-b9d4-48da-a37e-7ce70aa43d30')
+    @decorators.idempotent_id('9cecbe35-b9d4-48da-a37e-7ce70aa43d30')
     @test.attr(type='smoke')
     @test.services('compute', 'network')
     def test_schedule_to_all_nodes(self):
@@ -74,8 +75,7 @@
             # by getting to active state here, this means this has
             # landed on the host in question.
             inst = self.create_server(
-                availability_zone='%(zone)s:%(host_name)s' % host,
-                wait_until='ACTIVE')
+                availability_zone='%(zone)s:%(host_name)s' % host)
             server = self.servers_client.show_server(inst['id'])['server']
             servers.append(server)
 
diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py
index 7f04b0d..e950766 100644
--- a/tempest/scenario/test_shelve_instance.py
+++ b/tempest/scenario/test_shelve_instance.py
@@ -16,6 +16,7 @@
 from tempest.common import compute
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -57,7 +58,6 @@
             image_id=CONF.compute.image_ref,
             key_name=keypair['name'],
             security_groups=security_groups,
-            wait_until='ACTIVE',
             volume_backed=boot_from_volume)
 
         instance_ip = self.get_server_ip(server)
@@ -73,12 +73,12 @@
                                         private_key=keypair['private_key'])
         self.assertEqual(timestamp, timestamp2)
 
-    @test.idempotent_id('1164e700-0af0-4a4c-8792-35909a88743c')
+    @decorators.idempotent_id('1164e700-0af0-4a4c-8792-35909a88743c')
     @test.services('compute', 'network', 'image')
     def test_shelve_instance(self):
         self._create_server_then_shelve_and_unshelve()
 
-    @test.idempotent_id('c1b6318c-b9da-490b-9c67-9339b627271f')
+    @decorators.idempotent_id('c1b6318c-b9da-490b-9c67-9339b627271f')
     @test.services('compute', 'volume', 'network', 'image')
     def test_shelve_volume_backed_instance(self):
         self._create_server_then_shelve_and_unshelve(boot_from_volume=True)
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index 47c6e8d..8197d52 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest import config
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -37,7 +38,7 @@
         if not CONF.compute_feature_enabled.snapshot:
             raise cls.skipException("Snapshotting is not available.")
 
-    @test.idempotent_id('608e604b-1d63-4a82-8e3e-91bc665c90b4')
+    @decorators.idempotent_id('608e604b-1d63-4a82-8e3e-91bc665c90b4')
     @test.services('compute', 'network', 'image')
     def test_snapshot_pattern(self):
         # prepare for booting an instance
@@ -48,8 +49,7 @@
         server = self.create_server(
             image_id=CONF.compute.image_ref,
             key_name=keypair['name'],
-            security_groups=[{'name': security_group['name']}],
-            wait_until='ACTIVE')
+            security_groups=[{'name': security_group['name']}])
 
         instance_ip = self.get_server_ip(server)
         timestamp = self.create_timestamp(instance_ip,
@@ -62,8 +62,7 @@
         server_from_snapshot = self.create_server(
             image_id=snapshot_image['id'],
             key_name=keypair['name'],
-            security_groups=[{'name': security_group['name']}],
-            wait_until='ACTIVE')
+            security_groups=[{'name': security_group['name']}])
 
         # check the existence of the timestamp file in the second instance
         server_from_snapshot_ip = self.get_server_ip(server_from_snapshot)
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index b10be11..0c25664 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -95,7 +95,7 @@
             raise lib_exc.TimeoutException
 
     @decorators.skip_because(bug="1205344")
-    @test.idempotent_id('10fd234a-515c-41e5-b092-8323060598c5')
+    @decorators.idempotent_id('10fd234a-515c-41e5-b092-8323060598c5')
     @testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
                           'Snapshotting is not available.')
     @test.services('compute', 'network', 'volume', 'image')
@@ -109,8 +109,7 @@
         server = self.create_server(
             image_id=CONF.compute.image_ref,
             key_name=keypair['name'],
-            security_groups=security_group,
-            wait_until='ACTIVE')
+            security_groups=security_group)
 
         # create and add floating IP to server1
         ip_for_server = self.get_server_ip(server)
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 4064e04..5254082 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -15,6 +15,7 @@
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -68,10 +69,7 @@
             source_type,
             delete_on_termination=delete_on_termination))
 
-        return self.create_server(
-            image_id='',
-            wait_until='ACTIVE',
-            **create_kwargs)
+        return self.create_server(image_id='', **create_kwargs)
 
     def _create_snapshot_from_volume(self, vol_id):
         snap_name = data_utils.rand_name(
@@ -98,7 +96,7 @@
         self.servers_client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.servers_client, server['id'])
 
-    @test.idempotent_id('557cd2c2-4eb8-4dce-98be-f86765ff311b')
+    @decorators.idempotent_id('557cd2c2-4eb8-4dce-98be-f86765ff311b')
     @test.attr(type='smoke')
     @test.services('compute', 'volume', 'image')
     def test_volume_boot_pattern(self):
@@ -178,7 +176,7 @@
                                         private_key=keypair['private_key'])
         self.assertEqual(timestamp, timestamp3)
 
-    @test.idempotent_id('05795fb2-b2a7-4c9f-8fac-ff25aedb1489')
+    @decorators.idempotent_id('05795fb2-b2a7-4c9f-8fac-ff25aedb1489')
     @test.services('compute', 'image', 'volume')
     def test_create_server_from_volume_snapshot(self):
         # Create a volume from an image
@@ -214,7 +212,7 @@
         self.assertEqual(created_volume[0]['id'],
                          created_volume_info['attachments'][0]['volume_id'])
 
-    @test.idempotent_id('36c34c67-7b54-4b59-b188-02a2f458a63b')
+    @decorators.idempotent_id('36c34c67-7b54-4b59-b188-02a2f458a63b')
     @test.services('compute', 'volume', 'image')
     def test_create_ebs_image_and_check_boot(self):
         # create an instance from volume
@@ -230,8 +228,7 @@
         self._delete_server(instance)
 
         # boot instance from EBS image
-        instance = self.create_server(
-            image_id=image['id'])
+        instance = self.create_server(image_id=image['id'])
         # just ensure that instance booted
 
         # delete instance
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
index dfda18d..891e22d 100644
--- a/tempest/scenario/test_volume_migrate_attached.py
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -14,6 +14,7 @@
 
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -61,7 +62,7 @@
         block_device_mapping = [{'device_name': 'vda', 'volume_id': vol_id,
                                  'delete_on_termination': False}]
 
-        return self.create_server(image_id='', wait_until='ACTIVE',
+        return self.create_server(image_id='',
                                   key_name=key_name,
                                   security_groups=security_groups,
                                   block_device_mapping=block_device_mapping)
@@ -90,7 +91,7 @@
         waiters.wait_for_volume_retype(self.volumes_client,
                                        volume_id, new_volume_type)
 
-    @test.idempotent_id('deadd2c2-beef-4dce-98be-f86765ff311b')
+    @decorators.idempotent_id('deadd2c2-beef-4dce-98be-f86765ff311b')
     @test.services('compute', 'volume')
     def test_volume_migrate_attached(self):
         LOG.info("Creating keypair and security group")
diff --git a/tempest/tests/api/__init__.py b/tempest/tests/api/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/tests/api/__init__.py
diff --git a/tempest/tests/api/compute/__init__.py b/tempest/tests/api/compute/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/tests/api/compute/__init__.py
diff --git a/tempest/tests/api/compute/test_base.py b/tempest/tests/api/compute/test_base.py
new file mode 100644
index 0000000..a1da343
--- /dev/null
+++ b/tempest/tests/api/compute/test_base.py
@@ -0,0 +1,140 @@
+# Copyright 2017 IBM Corp.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import mock
+
+from oslo_utils import uuidutils
+import six
+
+from tempest.api.compute import base as compute_base
+from tempest.common import waiters
+from tempest import exceptions
+from tempest.lib import exceptions as lib_exc
+from tempest.tests import base
+
+
+class TestBaseV2ComputeTest(base.TestCase):
+    """Unit tests for utility functions in BaseV2ComputeTest."""
+
+    @mock.patch.multiple(compute_base.BaseV2ComputeTest,
+                         compute_images_client=mock.DEFAULT,
+                         images=[], create=True)
+    def test_create_image_from_server_no_wait(self, compute_images_client):
+        """Tests create_image_from_server without the wait_until kwarg."""
+        # setup mocks
+        image_id = uuidutils.generate_uuid()
+        fake_image = mock.Mock(response={'location': image_id})
+        compute_images_client.create_image.return_value = fake_image
+        # call the utility method
+        image = compute_base.BaseV2ComputeTest.create_image_from_server(
+            mock.sentinel.server_id, name='fake-snapshot-name')
+        self.assertEqual(fake_image, image)
+        # make our assertions
+        compute_images_client.create_image.assert_called_once_with(
+            mock.sentinel.server_id, name='fake-snapshot-name')
+        self.assertEqual(1, len(compute_base.BaseV2ComputeTest.images))
+        self.assertEqual(image_id, compute_base.BaseV2ComputeTest.images[0])
+
+    @mock.patch.multiple(compute_base.BaseV2ComputeTest,
+                         compute_images_client=mock.DEFAULT,
+                         images=[], create=True)
+    @mock.patch.object(waiters, 'wait_for_image_status')
+    def test_create_image_from_server_wait_until_active(self,
+                                                        wait_for_image_status,
+                                                        compute_images_client):
+        """Tests create_image_from_server with wait_until='ACTIVE' kwarg."""
+        # setup mocks
+        image_id = uuidutils.generate_uuid()
+        fake_image = mock.Mock(response={'location': image_id})
+        compute_images_client.create_image.return_value = fake_image
+        compute_images_client.show_image.return_value = (
+            {'image': fake_image})
+        # call the utility method
+        image = compute_base.BaseV2ComputeTest.create_image_from_server(
+            mock.sentinel.server_id, wait_until='ACTIVE')
+        self.assertEqual(fake_image, image)
+        # make our assertions
+        wait_for_image_status.assert_called_once_with(
+            compute_images_client, image_id, 'ACTIVE')
+        compute_images_client.show_image.assert_called_once_with(image_id)
+
+    @mock.patch.multiple(compute_base.BaseV2ComputeTest,
+                         compute_images_client=mock.DEFAULT,
+                         servers_client=mock.DEFAULT,
+                         images=[], create=True)
+    @mock.patch.object(waiters, 'wait_for_image_status',
+                       side_effect=lib_exc.NotFound)
+    def _test_create_image_from_server_wait_until_active_not_found(
+            self, wait_for_image_status, compute_images_client,
+            servers_client, fault=None):
+        # setup mocks
+        image_id = uuidutils.generate_uuid()
+        fake_image = mock.Mock(response={'location': image_id})
+        compute_images_client.create_image.return_value = fake_image
+        fake_server = {'id': mock.sentinel.server_id}
+        if fault:
+            fake_server['fault'] = fault
+        servers_client.show_server.return_value = {'server': fake_server}
+        # call the utility method
+        ex = self.assertRaises(
+            exceptions.SnapshotNotFoundException,
+            compute_base.BaseV2ComputeTest.create_image_from_server,
+            mock.sentinel.server_id, wait_until='active')
+        # make our assertions
+        if fault:
+            self.assertIn(fault, six.text_type(ex))
+        else:
+            self.assertNotIn(fault, six.text_type(ex))
+        wait_for_image_status.assert_called_once_with(
+            compute_images_client, image_id, 'active')
+        servers_client.show_server.assert_called_once_with(
+            mock.sentinel.server_id)
+
+    def test_create_image_from_server_wait_until_active_not_found_no_fault(
+            self):
+        # Tests create_image_from_server with wait_until='active' kwarg and
+        # the a 404 is raised while waiting for the image status to change. In
+        # this test the server does not have a fault associated with it.
+        self._test_create_image_from_server_wait_until_active_not_found()
+
+    def test_create_image_from_server_wait_until_active_not_found_with_fault(
+            self):
+        # Tests create_image_from_server with wait_until='active' kwarg and
+        # the a 404 is raised while waiting for the image status to change. In
+        # this test the server has a fault associated with it.
+        self._test_create_image_from_server_wait_until_active_not_found(
+            fault='Lost connection to hypervisor!')
+
+    @mock.patch.multiple(compute_base.BaseV2ComputeTest,
+                         compute_images_client=mock.DEFAULT,
+                         images=[], create=True)
+    @mock.patch.object(waiters, 'wait_for_image_status',
+                       side_effect=lib_exc.NotFound)
+    def test_create_image_from_server_wait_until_saving_not_found(
+            self, wait_for_image_status, compute_images_client):
+        # Tests create_image_from_server with wait_until='SAVING' kwarg and
+        # the a 404 is raised while waiting for the image status to change. In
+        # this case we do not get the server details and just re-raise the 404.
+        # setup mocks
+        image_id = uuidutils.generate_uuid()
+        fake_image = mock.Mock(response={'location': image_id})
+        compute_images_client.create_image.return_value = fake_image
+        # call the utility method
+        self.assertRaises(
+            lib_exc.NotFound,
+            compute_base.BaseV2ComputeTest.create_image_from_server,
+            mock.sentinel.server_id, wait_until='SAVING')
+        # make our assertions
+        wait_for_image_status.assert_called_once_with(
+            compute_images_client, image_id, 'SAVING')
diff --git a/tempest/tests/lib/services/identity/v3/test_roles_client.py b/tempest/tests/lib/services/identity/v3/test_roles_client.py
index 4f70b47..41cea85 100644
--- a/tempest/tests/lib/services/identity/v3/test_roles_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_roles_client.py
@@ -52,6 +52,65 @@
 
     FAKE_LIST_ROLES = {"roles": [FAKE_ROLE_INFO, FAKE_ROLE_INFO_2]}
 
+    FAKE_ROLE_INFERENCE_RULE = {
+        "role_inference": {
+            "prior_role": {
+                "id": FAKE_ROLE_ID,
+                "name": FAKE_ROLE_NAME,
+                "links": {
+                    "self": "http://example.com/identity/v3/roles/%s" % (
+                        FAKE_ROLE_ID)
+                }
+            },
+            "implies": {
+                "id": FAKE_ROLE_ID_2,
+                "name": FAKE_ROLE_NAME_2,
+                "links": {
+                    "self": "http://example.com/identity/v3/roles/%s" % (
+                        FAKE_ROLE_ID_2)
+                }
+            }
+        },
+        "links": {
+            "self": "http://example.com/identity/v3/roles/"
+                    "%s/implies/%s" % (FAKE_ROLE_ID, FAKE_ROLE_ID_2)
+        }
+    }
+
+    FAKE_LIST_ROLE_INFERENCES_RULES = {
+        "role_inference": {
+            "prior_role": {
+                "id": FAKE_ROLE_ID,
+                "name": FAKE_ROLE_NAME,
+                "links": {
+                    "self": "http://example.com/identity/v3/roles/%s" % (
+                        FAKE_ROLE_ID)
+                }
+            },
+            "implies": [
+                {
+                    "id": FAKE_ROLE_ID_2,
+                    "name": FAKE_ROLE_NAME_2,
+                    "links": {
+                        "self": "http://example.com/identity/v3/roles/%s" % (
+                            FAKE_ROLE_ID_2)
+                    }
+                },
+                {
+                    "id": "3",
+                    "name": "test3",
+                    "links": {
+                        "self": "http://example.com/identity/v3/roles/3"
+                    }
+                }
+            ]
+        },
+        "links": {
+            "self": "http://example.com/identity/v3/roles/"
+                    "%s/implies" % FAKE_ROLE_ID
+        }
+    }
+
     def setUp(self):
         super(TestRolesClient, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -172,6 +231,33 @@
             domain_id="b344506af7644f6794d9cb316600b020",
             group_id="123")
 
+    def _test_create_role_inference_rule(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_role_inference_rule,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_ROLE_INFERENCE_RULE,
+            bytes_body,
+            status=201,
+            prior_role=self.FAKE_ROLE_ID,
+            implies_role=self.FAKE_ROLE_ID_2)
+
+    def _test_show_role_inference_rule(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_role_inference_rule,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_ROLE_INFERENCE_RULE,
+            bytes_body,
+            prior_role=self.FAKE_ROLE_ID,
+            implies_role=self.FAKE_ROLE_ID_2)
+
+    def _test_list_role_inferences_rules(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_role_inferences_rules,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_LIST_ROLE_INFERENCES_RULES,
+            bytes_body,
+            prior_role=self.FAKE_ROLE_ID)
+
     def test_create_role_with_str_body(self):
         self._test_create_role()
 
@@ -319,3 +405,39 @@
             group_id="123",
             role_id="1234",
             status=204)
+
+    def test_create_role_inference_rule_with_str_body(self):
+        self._test_create_role_inference_rule()
+
+    def test_create_role_inference_rule_with_bytes_body(self):
+        self._test_create_role_inference_rule(bytes_body=True)
+
+    def test_show_role_inference_rule_with_str_body(self):
+        self._test_show_role_inference_rule()
+
+    def test_show_role_inference_rule_with_bytes_body(self):
+        self._test_show_role_inference_rule(bytes_body=True)
+
+    def test_list_role_inferences_rules_with_str_body(self):
+        self._test_list_role_inferences_rules()
+
+    def test_list_role_inferences_rules_with_bytes_body(self):
+        self._test_list_role_inferences_rules(bytes_body=True)
+
+    def test_check_role_inference_rule(self):
+        self.check_service_client_function(
+            self.client.check_role_inference_rule,
+            'tempest.lib.common.rest_client.RestClient.head',
+            {},
+            status=204,
+            prior_role=self.FAKE_ROLE_ID,
+            implies_role=self.FAKE_ROLE_ID_2)
+
+    def test_delete_role_inference_rule(self):
+        self.check_service_client_function(
+            self.client.delete_role_inference_rule,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            status=204,
+            prior_role=self.FAKE_ROLE_ID,
+            implies_role=self.FAKE_ROLE_ID_2)