Merge "Try boot a vm with lower than min ram"
diff --git a/doc/source/library/clients.rst b/doc/source/library/clients.rst
index 086cfc9..0f4ba4c 100644
--- a/doc/source/library/clients.rst
+++ b/doc/source/library/clients.rst
@@ -16,9 +16,18 @@
 The ``ServiceClients`` class provides a convenient way to get access to all
 available service clients initialized with a provided set of credentials.
 
-------------------
-The clients module
-------------------
+-----------------------------
+The clients management module
+-----------------------------
 
 .. automodule:: tempest.lib.services.clients
    :members:
+
+------------------------------
+Compute service client modules
+------------------------------
+
+.. toctree::
+   :maxdepth: 2
+
+   service_clients/compute_clients
diff --git a/doc/source/library/service_clients/compute_clients.rst b/doc/source/library/service_clients/compute_clients.rst
new file mode 100644
index 0000000..4ca55d4
--- /dev/null
+++ b/doc/source/library/service_clients/compute_clients.rst
@@ -0,0 +1,7 @@
+.. _servers_client:
+
+Compute Client Usage
+====================
+
+.. automodule:: tempest.lib.services.compute.servers_client
+   :members:
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/notes/jsonschema-validator-2377ba131e12d3c7.yaml b/releasenotes/notes/jsonschema-validator-2377ba131e12d3c7.yaml
new file mode 100644
index 0000000..8817ed4
--- /dev/null
+++ b/releasenotes/notes/jsonschema-validator-2377ba131e12d3c7.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - Added customized JSON schema format checker for 'date-time' format.
+    Compute response schema will be validated against customized format
+    checker.
diff --git a/releasenotes/notes/remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml b/releasenotes/notes/remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml
new file mode 100644
index 0000000..371c061
--- /dev/null
+++ b/releasenotes/notes/remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+  - The deprecated input-scenario config options and group
+    have been removed.
+    The input scenarios functionality already being removed from tempest
+    and from this release, their corresponding config options too.
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_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 3fd1612..f3a5e01 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -33,12 +33,6 @@
             raise cls.skipException(msg)
 
     @classmethod
-    def setup_clients(cls):
-        super(FlavorsAdminTestJSON, cls).setup_clients()
-        cls.client = cls.os_adm.flavors_client
-        cls.user_client = cls.os.flavors_client
-
-    @classmethod
     def resource_setup(cls):
         super(FlavorsAdminTestJSON, cls).resource_setup()
 
@@ -50,50 +44,22 @@
         cls.swap = 1024
         cls.rxtx = 2
 
-    def flavor_clean_up(self, flavor_id):
-        self.client.delete_flavor(flavor_id)
-        self.client.wait_for_resource_deletion(flavor_id)
-
-    def _create_flavor(self, flavor_id):
-        # Create a flavor and ensure it is listed
-        # This operation requires the user to have 'admin' role
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-
-        # Create the flavor
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=flavor_id,
-                                           ephemeral=self.ephemeral,
-                                           swap=self.swap,
-                                           rxtx_factor=self.rxtx)['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
-        self.assertEqual(flavor['name'], flavor_name)
-        self.assertEqual(flavor['vcpus'], self.vcpus)
-        self.assertEqual(flavor['disk'], self.disk)
-        self.assertEqual(flavor['ram'], self.ram)
-        self.assertEqual(flavor['swap'], self.swap)
-        self.assertEqual(flavor['rxtx_factor'], self.rxtx)
-        self.assertEqual(flavor['OS-FLV-EXT-DATA:ephemeral'],
-                         self.ephemeral)
-        self.assertEqual(flavor['os-flavor-access:is_public'], True)
-
-        # Verify flavor is retrieved
-        flavor = self.client.show_flavor(flavor['id'])['flavor']
-        self.assertEqual(flavor['name'], flavor_name)
-
-        return flavor['id']
-
     @decorators.idempotent_id('8b4330e1-12c4-4554-9390-e6639971f086')
     def test_create_flavor_with_int_id(self):
         flavor_id = data_utils.rand_int_id(start=1000)
-        new_flavor_id = self._create_flavor(flavor_id)
+        new_flavor_id = self.create_flavor(ram=self.ram,
+                                           vcpus=self.vcpus,
+                                           disk=self.disk,
+                                           id=flavor_id)['id']
         self.assertEqual(new_flavor_id, str(flavor_id))
 
     @decorators.idempotent_id('94c9bb4e-2c2a-4f3c-bb1f-5f0daf918e6d')
     def test_create_flavor_with_uuid_id(self):
         flavor_id = data_utils.rand_uuid()
-        new_flavor_id = self._create_flavor(flavor_id)
+        new_flavor_id = self.create_flavor(ram=self.ram,
+                                           vcpus=self.vcpus,
+                                           disk=self.disk,
+                                           id=flavor_id)['id']
         self.assertEqual(new_flavor_id, flavor_id)
 
     @decorators.idempotent_id('f83fe669-6758-448a-a85e-32d351f36fe0')
@@ -101,7 +67,10 @@
         # If nova receives a request with None as flavor_id,
         # nova generates flavor_id of uuid.
         flavor_id = None
-        new_flavor_id = self._create_flavor(flavor_id)
+        new_flavor_id = self.create_flavor(ram=self.ram,
+                                           vcpus=self.vcpus,
+                                           disk=self.disk,
+                                           id=flavor_id)['id']
         self.assertEqual(new_flavor_id, str(uuid.UUID(new_flavor_id)))
 
     @decorators.idempotent_id('8261d7b0-be58-43ec-a2e5-300573c3f6c5')
@@ -109,20 +78,18 @@
         # Create a flavor and ensure it's details are listed
         # This operation requires the user to have 'admin' role
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
 
         # Create the flavor
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=new_flavor_id,
-                                           ephemeral=self.ephemeral,
-                                           swap=self.swap,
-                                           rxtx_factor=self.rxtx)['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        flavor = self.create_flavor(name=flavor_name,
+                                    ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk,
+                                    ephemeral=self.ephemeral,
+                                    swap=self.swap,
+                                    rxtx_factor=self.rxtx)
         flag = False
         # Verify flavor is retrieved
-        flavors = self.client.list_flavors(detail=True)['flavors']
+        flavors = self.admin_flavors_client.list_flavors(
+            detail=True)['flavors']
         for flavor in flavors:
             if flavor['name'] == flavor_name:
                 flag = True
@@ -144,11 +111,10 @@
         new_flavor_id = data_utils.rand_int_id(start=1000)
 
         # Create the flavor
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=new_flavor_id)['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        flavor = self.create_flavor(name=flavor_name,
+                                    ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk,
+                                    id=new_flavor_id)
         self.assertEqual(flavor['name'], flavor_name)
         self.assertEqual(flavor['ram'], self.ram)
         self.assertEqual(flavor['vcpus'], self.vcpus)
@@ -157,13 +123,13 @@
         verify_flavor_response_extension(flavor)
 
         # Verify flavor is retrieved
-        flavor = self.client.show_flavor(new_flavor_id)['flavor']
+        flavor = self.admin_flavors_client.show_flavor(new_flavor_id)['flavor']
         self.assertEqual(flavor['name'], flavor_name)
         verify_flavor_response_extension(flavor)
 
         # Check if flavor is present in list
         flag = False
-        flavors = self.user_client.list_flavors(detail=True)['flavors']
+        flavors = self.flavors_client.list_flavors(detail=True)['flavors']
         for flavor in flavors:
             if flavor['name'] == flavor_name:
                 verify_flavor_response_extension(flavor)
@@ -177,18 +143,16 @@
         # tenant is not automatically added access list.
         # This operation requires the user to have 'admin' role
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
 
         # Create the flavor
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=new_flavor_id,
-                                           is_public="False")['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        flavor = self.create_flavor(name=flavor_name,
+                                    ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk,
+                                    is_public="False")
         # Verify flavor is retrieved
         flag = False
-        flavors = self.client.list_flavors(detail=True)['flavors']
+        flavors = self.admin_flavors_client.list_flavors(
+            detail=True)['flavors']
         for flavor in flavors:
             if flavor['name'] == flavor_name:
                 flag = True
@@ -196,7 +160,7 @@
 
         # Verify flavor is not retrieved with other user
         flag = False
-        flavors = self.user_client.list_flavors(detail=True)['flavors']
+        flavors = self.flavors_client.list_flavors(detail=True)['flavors']
         for flavor in flavors:
             if flavor['name'] == flavor_name:
                 flag = True
@@ -205,16 +169,9 @@
     @decorators.idempotent_id('bcc418ef-799b-47cc-baa1-ce01368b8987')
     def test_create_server_with_non_public_flavor(self):
         # Create a flavor with os-flavor-access:is_public false
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
-
-        # Create the flavor
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=new_flavor_id,
-                                           is_public="False")['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk,
+                                    is_public="False")
 
         # Verify flavor is not used by other user
         self.assertRaises(lib_exc.BadRequest,
@@ -227,19 +184,15 @@
         # Create a Flavor with public access.
         # Try to List/Get flavor with another user
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
 
         # Create the flavor
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=new_flavor_id,
-                                           is_public="True")['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        flavor = self.create_flavor(name=flavor_name,
+                                    ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk,
+                                    is_public="True")
         flag = False
-        self.new_client = self.flavors_client
         # Verify flavor is retrieved with new user
-        flavors = self.new_client.list_flavors(detail=True)['flavors']
+        flavors = self.flavors_client.list_flavors(detail=True)['flavors']
         for flavor in flavors:
             if flavor['name'] == flavor_name:
                 flag = True
@@ -247,26 +200,20 @@
 
     @decorators.idempotent_id('fb9cbde6-3a0e-41f2-a983-bdb0a823c44e')
     def test_is_public_string_variations(self):
-        flavor_id_not_public = data_utils.rand_int_id(start=1000)
         flavor_name_not_public = data_utils.rand_name(self.flavor_name_prefix)
-        flavor_id_public = data_utils.rand_int_id(start=1000)
         flavor_name_public = data_utils.rand_name(self.flavor_name_prefix)
 
         # Create a non public flavor
-        flavor = self.client.create_flavor(name=flavor_name_not_public,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=flavor_id_not_public,
-                                           is_public="False")['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        self.create_flavor(name=flavor_name_not_public,
+                           ram=self.ram, vcpus=self.vcpus,
+                           disk=self.disk,
+                           is_public="False")
 
         # Create a public flavor
-        flavor = self.client.create_flavor(name=flavor_name_public,
-                                           ram=self.ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=flavor_id_public,
-                                           is_public="True")['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        self.create_flavor(name=flavor_name_public,
+                           ram=self.ram, vcpus=self.vcpus,
+                           disk=self.disk,
+                           is_public="True")
 
         def _flavor_lookup(flavors, flavor_name):
             for flavor in flavors:
@@ -277,7 +224,8 @@
         def _test_string_variations(variations, flavor_name):
             for string in variations:
                 params = {'is_public': string}
-                flavors = (self.client.list_flavors(detail=True, **params)
+                flavors = (self.admin_flavors_client.list_flavors(detail=True,
+                                                                  **params)
                            ['flavors'])
                 flavor = _flavor_lookup(flavors, flavor_name)
                 self.assertIsNotNone(flavor)
@@ -290,17 +238,11 @@
 
     @decorators.idempotent_id('3b541a2e-2ac2-4b42-8b8d-ba6e22fcd4da')
     def test_create_flavor_using_string_ram(self):
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
 
         ram = "1024"
-        flavor = self.client.create_flavor(name=flavor_name,
-                                           ram=ram, vcpus=self.vcpus,
-                                           disk=self.disk,
-                                           id=new_flavor_id)['flavor']
-        self.addCleanup(self.flavor_clean_up, flavor['id'])
-        self.assertEqual(flavor['name'], flavor_name)
-        self.assertEqual(flavor['vcpus'], self.vcpus)
-        self.assertEqual(flavor['disk'], self.disk)
+        flavor = self.create_flavor(ram=ram, vcpus=self.vcpus,
+                                    disk=self.disk,
+                                    id=new_flavor_id)
         self.assertEqual(flavor['ram'], int(ram))
         self.assertEqual(int(flavor['id']), new_flavor_id)
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index 38ff4c0..04b0c2d 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -33,11 +33,6 @@
             raise cls.skipException(msg)
 
     @classmethod
-    def setup_clients(cls):
-        super(FlavorsAccessTestJSON, cls).setup_clients()
-        cls.client = cls.os_adm.flavors_client
-
-    @classmethod
     def resource_setup(cls):
         super(FlavorsAccessTestJSON, cls).resource_setup()
 
@@ -54,14 +49,16 @@
         # private flavor will return an empty access list
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
-        new_flavor = self.client.create_flavor(name=flavor_name,
-                                               ram=self.ram, vcpus=self.vcpus,
-                                               disk=self.disk,
-                                               id=new_flavor_id,
-                                               is_public='False')['flavor']
-        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
-        flavor_access = (self.client.list_flavor_access(new_flavor_id)
-                         ['flavor_access'])
+        new_flavor = self.admin_flavors_client.create_flavor(
+            name=flavor_name,
+            ram=self.ram, vcpus=self.vcpus,
+            disk=self.disk,
+            id=new_flavor_id,
+            is_public='False')['flavor']
+        self.addCleanup(self.admin_flavors_client.delete_flavor,
+                        new_flavor['id'])
+        flavor_access = (self.admin_flavors_client.list_flavor_access(
+            new_flavor_id)['flavor_access'])
         self.assertEqual(len(flavor_access), 0, str(flavor_access))
 
     @decorators.idempotent_id('59e622f6-bdf6-45e3-8ba8-fedad905a6b4')
@@ -69,20 +66,21 @@
         # Test to add and remove flavor access to a given tenant.
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
-        new_flavor = self.client.create_flavor(name=flavor_name,
-                                               ram=self.ram, vcpus=self.vcpus,
-                                               disk=self.disk,
-                                               id=new_flavor_id,
-                                               is_public='False')['flavor']
-        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+        new_flavor = self.admin_flavors_client.create_flavor(
+            name=flavor_name,
+            ram=self.ram, vcpus=self.vcpus,
+            disk=self.disk,
+            id=new_flavor_id,
+            is_public='False')['flavor']
+        self.addCleanup(self.admin_flavors_client.delete_flavor,
+                        new_flavor['id'])
         # Add flavor access to a tenant.
         resp_body = {
             "tenant_id": str(self.tenant_id),
             "flavor_id": str(new_flavor['id']),
         }
-        add_body = (self.client.add_flavor_access(new_flavor['id'],
-                                                  self.tenant_id)
-                    ['flavor_access'])
+        add_body = (self.admin_flavors_client.add_flavor_access(
+            new_flavor['id'], self.tenant_id)['flavor_access'])
         self.assertIn(resp_body, add_body)
 
         # The flavor is present in list.
@@ -90,9 +88,8 @@
         self.assertIn(new_flavor['id'], map(lambda x: x['id'], flavors))
 
         # Remove flavor access from a tenant.
-        remove_body = (self.client.remove_flavor_access(new_flavor['id'],
-                                                        self.tenant_id)
-                       ['flavor_access'])
+        remove_body = (self.admin_flavors_client.remove_flavor_access(
+            new_flavor['id'], self.tenant_id)['flavor_access'])
         self.assertNotIn(resp_body, remove_body)
 
         # The flavor is not present in list.
diff --git a/tempest/api/compute/admin/test_flavors_access_negative.py b/tempest/api/compute/admin/test_flavors_access_negative.py
index 2719cc4..bd72d13 100644
--- a/tempest/api/compute/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/admin/test_flavors_access_negative.py
@@ -34,11 +34,6 @@
             raise cls.skipException(msg)
 
     @classmethod
-    def setup_clients(cls):
-        super(FlavorsAccessNegativeTestJSON, cls).setup_clients()
-        cls.client = cls.os_adm.flavors_client
-
-    @classmethod
     def resource_setup(cls):
         super(FlavorsAccessNegativeTestJSON, cls).resource_setup()
 
@@ -54,14 +49,16 @@
         # Test to list flavor access with exceptions by querying public flavor
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
-        new_flavor = self.client.create_flavor(name=flavor_name,
-                                               ram=self.ram, vcpus=self.vcpus,
-                                               disk=self.disk,
-                                               id=new_flavor_id,
-                                               is_public='True')['flavor']
-        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+        new_flavor = self.admin_flavors_client.create_flavor(
+            name=flavor_name,
+            ram=self.ram, vcpus=self.vcpus,
+            disk=self.disk,
+            id=new_flavor_id,
+            is_public='True')['flavor']
+        self.addCleanup(self.admin_flavors_client.delete_flavor,
+                        new_flavor['id'])
         self.assertRaises(lib_exc.NotFound,
-                          self.client.list_flavor_access,
+                          self.admin_flavors_client.list_flavor_access,
                           new_flavor_id)
 
     @test.attr(type=['negative'])
@@ -70,12 +67,14 @@
         # Test to add flavor access as a user without admin privileges.
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
-        new_flavor = self.client.create_flavor(name=flavor_name,
-                                               ram=self.ram, vcpus=self.vcpus,
-                                               disk=self.disk,
-                                               id=new_flavor_id,
-                                               is_public='False')['flavor']
-        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+        new_flavor = self.admin_flavors_client.create_flavor(
+            name=flavor_name,
+            ram=self.ram, vcpus=self.vcpus,
+            disk=self.disk,
+            id=new_flavor_id,
+            is_public='False')['flavor']
+        self.addCleanup(self.admin_flavors_client.delete_flavor,
+                        new_flavor['id'])
         self.assertRaises(lib_exc.Forbidden,
                           self.flavors_client.add_flavor_access,
                           new_flavor['id'],
@@ -87,15 +86,18 @@
         # Test to remove flavor access as a user without admin privileges.
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
-        new_flavor = self.client.create_flavor(name=flavor_name,
-                                               ram=self.ram, vcpus=self.vcpus,
-                                               disk=self.disk,
-                                               id=new_flavor_id,
-                                               is_public='False')['flavor']
-        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+        new_flavor = self.admin_flavors_client.create_flavor(
+            name=flavor_name,
+            ram=self.ram, vcpus=self.vcpus,
+            disk=self.disk,
+            id=new_flavor_id,
+            is_public='False')['flavor']
+        self.addCleanup(self.admin_flavors_client.delete_flavor,
+                        new_flavor['id'])
         # Add flavor access to a tenant.
-        self.client.add_flavor_access(new_flavor['id'], self.tenant_id)
-        self.addCleanup(self.client.remove_flavor_access,
+        self.admin_flavors_client.add_flavor_access(new_flavor['id'],
+                                                    self.tenant_id)
+        self.addCleanup(self.admin_flavors_client.remove_flavor_access,
                         new_flavor['id'], self.tenant_id)
         self.assertRaises(lib_exc.Forbidden,
                           self.flavors_client.remove_flavor_access,
@@ -108,22 +110,25 @@
         # Create a new flavor.
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
-        new_flavor = self.client.create_flavor(name=flavor_name,
-                                               ram=self.ram, vcpus=self.vcpus,
-                                               disk=self.disk,
-                                               id=new_flavor_id,
-                                               is_public='False')['flavor']
-        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+        new_flavor = self.admin_flavors_client.create_flavor(
+            name=flavor_name,
+            ram=self.ram, vcpus=self.vcpus,
+            disk=self.disk,
+            id=new_flavor_id,
+            is_public='False')['flavor']
+        self.addCleanup(self.admin_flavors_client.delete_flavor,
+                        new_flavor['id'])
 
         # Add flavor access to a tenant.
-        self.client.add_flavor_access(new_flavor['id'], self.tenant_id)
-        self.addCleanup(self.client.remove_flavor_access,
+        self.admin_flavors_client.add_flavor_access(new_flavor['id'],
+                                                    self.tenant_id)
+        self.addCleanup(self.admin_flavors_client.remove_flavor_access,
                         new_flavor['id'], self.tenant_id)
 
         # An exception should be raised when adding flavor access to the same
         # tenant
         self.assertRaises(lib_exc.Conflict,
-                          self.client.add_flavor_access,
+                          self.admin_flavors_client.add_flavor_access,
                           new_flavor['id'],
                           self.tenant_id)
 
@@ -133,15 +138,17 @@
         # Create a new flavor.
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
-        new_flavor = self.client.create_flavor(name=flavor_name,
-                                               ram=self.ram, vcpus=self.vcpus,
-                                               disk=self.disk,
-                                               id=new_flavor_id,
-                                               is_public='False')['flavor']
-        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+        new_flavor = self.admin_flavors_client.create_flavor(
+            name=flavor_name,
+            ram=self.ram, vcpus=self.vcpus,
+            disk=self.disk,
+            id=new_flavor_id,
+            is_public='False')['flavor']
+        self.addCleanup(self.admin_flavors_client.delete_flavor,
+                        new_flavor['id'])
 
         # An exception should be raised when flavor access is not found
         self.assertRaises(lib_exc.NotFound,
-                          self.client.remove_flavor_access,
+                          self.admin_flavors_client.remove_flavor_access,
                           new_flavor['id'],
                           data_utils.rand_uuid())
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index 70e662c..8ec6400 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -34,11 +34,6 @@
             raise cls.skipException(msg)
 
     @classmethod
-    def setup_clients(cls):
-        super(FlavorsExtraSpecsTestJSON, cls).setup_clients()
-        cls.client = cls.os_adm.flavors_client
-
-    @classmethod
     def resource_setup(cls):
         super(FlavorsExtraSpecsTestJSON, cls).resource_setup()
         flavor_name = data_utils.rand_name('test_flavor')
@@ -50,18 +45,19 @@
         swap = 1024
         rxtx = 1
         # Create a flavor so as to set/get/unset extra specs
-        cls.flavor = cls.client.create_flavor(name=flavor_name,
-                                              ram=ram, vcpus=vcpus,
-                                              disk=disk,
-                                              id=cls.new_flavor_id,
-                                              ephemeral=ephemeral,
-                                              swap=swap,
-                                              rxtx_factor=rxtx)['flavor']
+        cls.flavor = cls.admin_flavors_client.create_flavor(
+            name=flavor_name,
+            ram=ram, vcpus=vcpus,
+            disk=disk,
+            id=cls.new_flavor_id,
+            ephemeral=ephemeral,
+            swap=swap,
+            rxtx_factor=rxtx)['flavor']
 
     @classmethod
     def resource_cleanup(cls):
-        cls.client.delete_flavor(cls.flavor['id'])
-        cls.client.wait_for_resource_deletion(cls.flavor['id'])
+        cls.admin_flavors_client.delete_flavor(cls.flavor['id'])
+        cls.admin_flavors_client.wait_for_resource_deletion(cls.flavor['id'])
         super(FlavorsExtraSpecsTestJSON, cls).resource_cleanup()
 
     @decorators.idempotent_id('0b2f9d4b-1ca2-4b99-bb40-165d4bb94208')
@@ -71,46 +67,47 @@
         # Assigning extra specs values that are to be set
         specs = {"key1": "value1", "key2": "value2"}
         # SET extra specs to the flavor created in setUp
-        set_body = self.client.set_flavor_extra_spec(self.flavor['id'],
-                                                     **specs)['extra_specs']
+        set_body = self.admin_flavors_client.set_flavor_extra_spec(
+            self.flavor['id'], **specs)['extra_specs']
         self.assertEqual(set_body, specs)
         # GET extra specs and verify
-        get_body = (self.client.list_flavor_extra_specs(self.flavor['id'])
-                    ['extra_specs'])
+        get_body = (self.admin_flavors_client.list_flavor_extra_specs(
+            self.flavor['id'])['extra_specs'])
         self.assertEqual(get_body, specs)
 
         # UPDATE the value of the extra specs key1
         update_body = \
-            self.client.update_flavor_extra_spec(self.flavor['id'],
-                                                 "key1",
-                                                 key1="value")
+            self.admin_flavors_client.update_flavor_extra_spec(
+                self.flavor['id'], "key1", key1="value")
         self.assertEqual({"key1": "value"}, update_body)
 
         # GET extra specs and verify the value of the key2
         # is the same as before
-        get_body = (self.client.list_flavor_extra_specs(self.flavor['id'])
-                    ['extra_specs'])
+        get_body = (self.admin_flavors_client.list_flavor_extra_specs(
+            self.flavor['id'])['extra_specs'])
         self.assertEqual(get_body, {"key1": "value", "key2": "value2"})
 
         # UNSET extra specs that were set in this test
-        self.client.unset_flavor_extra_spec(self.flavor['id'], "key1")
-        self.client.unset_flavor_extra_spec(self.flavor['id'], "key2")
+        self.admin_flavors_client.unset_flavor_extra_spec(self.flavor['id'],
+                                                          "key1")
+        self.admin_flavors_client.unset_flavor_extra_spec(self.flavor['id'],
+                                                          "key2")
 
     @decorators.idempotent_id('a99dad88-ae1c-4fba-aeb4-32f898218bd0')
     def test_flavor_non_admin_get_all_keys(self):
         specs = {"key1": "value1", "key2": "value2"}
-        self.client.set_flavor_extra_spec(self.flavor['id'], **specs)
-        body = (self.flavors_client.list_flavor_extra_specs(self.flavor['id'])
-                ['extra_specs'])
+        self.admin_flavors_client.set_flavor_extra_spec(self.flavor['id'],
+                                                        **specs)
+        body = (self.flavors_client.list_flavor_extra_specs(
+            self.flavor['id'])['extra_specs'])
 
         for key in specs:
             self.assertEqual(body[key], specs[key])
 
     @decorators.idempotent_id('12805a7f-39a3-4042-b989-701d5cad9c90')
     def test_flavor_non_admin_get_specific_key(self):
-        body = self.client.set_flavor_extra_spec(self.flavor['id'],
-                                                 key1="value1",
-                                                 key2="value2")['extra_specs']
+        body = self.admin_flavors_client.set_flavor_extra_spec(
+            self.flavor['id'], key1="value1", key2="value2")['extra_specs']
         self.assertEqual(body['key1'], 'value1')
         self.assertIn('key2', body)
         body = self.flavors_client.show_flavor_extra_spec(
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
index 767a1ca..79a9068 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
@@ -35,11 +35,6 @@
             raise cls.skipException(msg)
 
     @classmethod
-    def setup_clients(cls):
-        super(FlavorsExtraSpecsNegativeTestJSON, cls).setup_clients()
-        cls.client = cls.os_adm.flavors_client
-
-    @classmethod
     def resource_setup(cls):
         super(FlavorsExtraSpecsNegativeTestJSON, cls).resource_setup()
 
@@ -52,18 +47,19 @@
         swap = 1024
         rxtx = 1
         # Create a flavor
-        cls.flavor = cls.client.create_flavor(name=flavor_name,
-                                              ram=ram, vcpus=vcpus,
-                                              disk=disk,
-                                              id=cls.new_flavor_id,
-                                              ephemeral=ephemeral,
-                                              swap=swap,
-                                              rxtx_factor=rxtx)['flavor']
+        cls.flavor = cls.admin_flavors_client.create_flavor(
+            name=flavor_name,
+            ram=ram, vcpus=vcpus,
+            disk=disk,
+            id=cls.new_flavor_id,
+            ephemeral=ephemeral,
+            swap=swap,
+            rxtx_factor=rxtx)['flavor']
 
     @classmethod
     def resource_cleanup(cls):
-        cls.client.delete_flavor(cls.flavor['id'])
-        cls.client.wait_for_resource_deletion(cls.flavor['id'])
+        cls.admin_flavors_client.delete_flavor(cls.flavor['id'])
+        cls.admin_flavors_client.wait_for_resource_deletion(cls.flavor['id'])
         super(FlavorsExtraSpecsNegativeTestJSON, cls).resource_cleanup()
 
     @test.attr(type=['negative'])
@@ -79,7 +75,7 @@
     @decorators.idempotent_id('1ebf4ef8-759e-48fe-a801-d451d80476fb')
     def test_flavor_non_admin_update_specific_key(self):
         # non admin user is not allowed to update flavor extra spec
-        body = self.client.set_flavor_extra_spec(
+        body = self.admin_flavors_client.set_flavor_extra_spec(
             self.flavor['id'], key1="value1", key2="value2")['extra_specs']
         self.assertEqual(body['key1'], 'value1')
         self.assertRaises(lib_exc.Forbidden,
@@ -92,8 +88,8 @@
     @test.attr(type=['negative'])
     @decorators.idempotent_id('28f12249-27c7-44c1-8810-1f382f316b11')
     def test_flavor_non_admin_unset_keys(self):
-        self.client.set_flavor_extra_spec(self.flavor['id'],
-                                          key1="value1", key2="value2")
+        self.admin_flavors_client.set_flavor_extra_spec(
+            self.flavor['id'], key1="value1", key2="value2")
 
         self.assertRaises(lib_exc.Forbidden,
                           self.flavors_client.unset_flavor_extra_spec,
@@ -104,7 +100,7 @@
     @decorators.idempotent_id('440b9f3f-3c7f-4293-a106-0ceda350f8de')
     def test_flavor_unset_nonexistent_key(self):
         self.assertRaises(lib_exc.NotFound,
-                          self.client.unset_flavor_extra_spec,
+                          self.admin_flavors_client.unset_flavor_extra_spec,
                           self.flavor['id'],
                           'nonexistent_key')
 
@@ -121,7 +117,7 @@
     def test_flavor_update_mismatch_key(self):
         # the key will be updated should be match the key in the body
         self.assertRaises(lib_exc.BadRequest,
-                          self.client.update_flavor_extra_spec,
+                          self.admin_flavors_client.update_flavor_extra_spec,
                           self.flavor['id'],
                           "key2",
                           key1="value")
@@ -131,7 +127,7 @@
     def test_flavor_update_more_key(self):
         # there should be just one item in the request body
         self.assertRaises(lib_exc.BadRequest,
-                          self.client.update_flavor_extra_spec,
+                          self.admin_flavors_client.update_flavor_extra_spec,
                           self.flavor['id'],
                           "key1",
                           key1="value",
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..c636894 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
@@ -453,3 +467,17 @@
         super(BaseV2ComputeAdminTest, cls).setup_clients()
         cls.availability_zone_admin_client = (
             cls.os_adm.availability_zone_client)
+        cls.admin_flavors_client = cls.os_adm.flavors_client
+
+    def create_flavor(self, ram, vcpus, disk, name=None,
+                      is_public='True', **kwargs):
+        if name is None:
+            name = data_utils.rand_name(self.__class__.__name__ + "-flavor")
+        id = kwargs.pop('id', data_utils.rand_int_id(start=1000))
+        client = self.admin_flavors_client
+        flavor = client.create_flavor(
+            ram=ram, vcpus=vcpus, disk=disk, name=name,
+            id=id, is_public=is_public, **kwargs)['flavor']
+        self.addCleanup(client.wait_for_resource_deletion, flavor['id'])
+        self.addCleanup(client.delete_flavor, flavor['id'])
+        return flavor
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index 546667f..89051c1 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -22,17 +22,12 @@
     _min_disk = 'minDisk'
     _min_ram = 'minRam'
 
-    @classmethod
-    def setup_clients(cls):
-        super(FlavorsV2TestJSON, cls).setup_clients()
-        cls.client = cls.flavors_client
-
     @test.attr(type='smoke')
     @decorators.idempotent_id('e36c0eaa-dff5-4082-ad1f-3f9a80aa3f59')
     def test_list_flavors(self):
         # List of all flavors should contain the expected flavor
-        flavors = self.client.list_flavors()['flavors']
-        flavor = self.client.show_flavor(self.flavor_ref)['flavor']
+        flavors = self.flavors_client.list_flavors()['flavors']
+        flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         flavor_min_detail = {'id': flavor['id'], 'links': flavor['links'],
                              'name': flavor['name']}
         self.assertIn(flavor_min_detail, flavors)
@@ -40,89 +35,93 @@
     @decorators.idempotent_id('6e85fde4-b3cd-4137-ab72-ed5f418e8c24')
     def test_list_flavors_with_detail(self):
         # Detailed list of all flavors should contain the expected flavor
-        flavors = self.client.list_flavors(detail=True)['flavors']
-        flavor = self.client.show_flavor(self.flavor_ref)['flavor']
+        flavors = self.flavors_client.list_flavors(detail=True)['flavors']
+        flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         self.assertIn(flavor, flavors)
 
     @test.attr(type='smoke')
     @decorators.idempotent_id('1f12046b-753d-40d2-abb6-d8eb8b30cb2f')
     def test_get_flavor(self):
         # The expected flavor details should be returned
-        flavor = self.client.show_flavor(self.flavor_ref)['flavor']
+        flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         self.assertEqual(self.flavor_ref, flavor['id'])
 
     @decorators.idempotent_id('8d7691b3-6ed4-411a-abc9-2839a765adab')
     def test_list_flavors_limit_results(self):
         # Only the expected number of flavors should be returned
         params = {'limit': 1}
-        flavors = self.client.list_flavors(**params)['flavors']
+        flavors = self.flavors_client.list_flavors(**params)['flavors']
         self.assertEqual(1, len(flavors))
 
     @decorators.idempotent_id('b26f6327-2886-467a-82be-cef7a27709cb')
     def test_list_flavors_detailed_limit_results(self):
         # Only the expected number of flavors (detailed) should be returned
         params = {'limit': 1}
-        flavors = self.client.list_flavors(detail=True, **params)['flavors']
+        flavors = self.flavors_client.list_flavors(detail=True,
+                                                   **params)['flavors']
         self.assertEqual(1, len(flavors))
 
     @decorators.idempotent_id('e800f879-9828-4bd0-8eae-4f17189951fb')
     def test_list_flavors_using_marker(self):
         # The list of flavors should start from the provided marker
-        flavor = self.client.show_flavor(self.flavor_ref)['flavor']
+        flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         flavor_id = flavor['id']
 
         params = {'marker': flavor_id}
-        flavors = self.client.list_flavors(**params)['flavors']
+        flavors = self.flavors_client.list_flavors(**params)['flavors']
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]),
                          'The list of flavors did not start after the marker.')
 
     @decorators.idempotent_id('6db2f0c0-ddee-4162-9c84-0703d3dd1107')
     def test_list_flavors_detailed_using_marker(self):
         # The list of flavors should start from the provided marker
-        flavor = self.client.show_flavor(self.flavor_ref)['flavor']
+        flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         flavor_id = flavor['id']
 
         params = {'marker': flavor_id}
-        flavors = self.client.list_flavors(detail=True, **params)['flavors']
+        flavors = self.flavors_client.list_flavors(detail=True,
+                                                   **params)['flavors']
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]),
                          'The list of flavors did not start after the marker.')
 
     @decorators.idempotent_id('3df2743e-3034-4e57-a4cb-b6527f6eac79')
     def test_list_flavors_detailed_filter_by_min_disk(self):
         # The detailed list of flavors should be filtered by disk space
-        flavor = self.client.show_flavor(self.flavor_ref)['flavor']
+        flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         flavor_id = flavor['id']
 
         params = {self._min_disk: flavor['disk'] + 1}
-        flavors = self.client.list_flavors(detail=True, **params)['flavors']
+        flavors = self.flavors_client.list_flavors(detail=True,
+                                                   **params)['flavors']
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
     @decorators.idempotent_id('09fe7509-b4ee-4b34-bf8b-39532dc47292')
     def test_list_flavors_detailed_filter_by_min_ram(self):
         # The detailed list of flavors should be filtered by RAM
-        flavor = self.client.show_flavor(self.flavor_ref)['flavor']
+        flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         flavor_id = flavor['id']
 
         params = {self._min_ram: flavor['ram'] + 1}
-        flavors = self.client.list_flavors(detail=True, **params)['flavors']
+        flavors = self.flavors_client.list_flavors(detail=True,
+                                                   **params)['flavors']
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
     @decorators.idempotent_id('10645a4d-96f5-443f-831b-730711e11dd4')
     def test_list_flavors_filter_by_min_disk(self):
         # The list of flavors should be filtered by disk space
-        flavor = self.client.show_flavor(self.flavor_ref)['flavor']
+        flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         flavor_id = flavor['id']
 
         params = {self._min_disk: flavor['disk'] + 1}
-        flavors = self.client.list_flavors(**params)['flavors']
+        flavors = self.flavors_client.list_flavors(**params)['flavors']
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
     @decorators.idempotent_id('935cf550-e7c8-4da6-8002-00f92d5edfaa')
     def test_list_flavors_filter_by_min_ram(self):
         # The list of flavors should be filtered by RAM
-        flavor = self.client.show_flavor(self.flavor_ref)['flavor']
+        flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         flavor_id = flavor['id']
 
         params = {self._min_ram: flavor['ram'] + 1}
-        flavors = self.client.list_flavors(**params)['flavors']
+        flavors = self.flavors_client.list_flavors(**params)['flavors']
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
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..5bcbdac 100644
--- a/tempest/api/compute/servers/test_device_tagging.py
+++ b/tempest/api/compute/servers/test_device_tagging.py
@@ -20,6 +20,7 @@
 from tempest.common.utils import data_utils
 from tempest.common.utils.linux import remote_client
 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
@@ -33,7 +34,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):
@@ -245,9 +250,9 @@
                 self.verify_device_metadata(md_json)
                 return True
 
-            if not test.call_until_true(get_and_verify_metadata,
-                                        CONF.compute.build_timeout,
-                                        CONF.compute.build_interval):
+            if not test_utils.call_until_true(get_and_verify_metadata,
+                                              CONF.compute.build_timeout,
+                                              CONF.compute.build_interval):
                 raise exceptions.TimeoutException('Timeout while verifying '
                                                   'metadata on server.')
 
@@ -262,3 +267,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/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
new file mode 100644
index 0000000..04fe11f
--- /dev/null
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -0,0 +1,241 @@
+# Copyright 2016 OpenStack Foundation
+# All Rights Reserved.
+#
+#    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 socket
+import struct
+
+import six
+from six.moves.urllib import parse as urlparse
+import urllib3
+
+from tempest.api.compute import base
+from tempest import config
+from tempest.lib import decorators
+
+CONF = config.CONF
+
+
+class NoVNCConsoleTestJSON(base.BaseV2ComputeTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(NoVNCConsoleTestJSON, cls).skip_checks()
+        if not CONF.compute_feature_enabled.vnc_console:
+            raise cls.skipException('VNC Console feature is disabled.')
+
+    def setUp(self):
+        super(NoVNCConsoleTestJSON, self).setUp()
+        self._websocket = None
+
+    def tearDown(self):
+        self.server_check_teardown()
+        super(NoVNCConsoleTestJSON, self).tearDown()
+        if self._websocket is not None:
+            self._websocket.close()
+
+    @classmethod
+    def setup_clients(cls):
+        super(NoVNCConsoleTestJSON, cls).setup_clients()
+        cls.client = cls.servers_client
+
+    @classmethod
+    def resource_setup(cls):
+        super(NoVNCConsoleTestJSON, cls).resource_setup()
+        cls.server = cls.create_test_server(wait_until="ACTIVE")
+
+    def _validate_novnc_html(self, vnc_url):
+        """Verify we can connect to novnc and get back the javascript."""
+        resp = urllib3.PoolManager().request('GET', vnc_url)
+        # Make sure that the GET request was accepted by the novncproxy
+        self.assertEqual(resp.status, 200, 'Got a Bad HTTP Response on the '
+                         'initial call: ' + str(resp.status))
+        # Do some basic validation to make sure it is an expected HTML document
+        self.assertTrue('<html>' in resp.data and '</html>' in resp.data,
+                        'Not a valid html document in the response.')
+        # Just try to make sure we got JavaScript back for noVNC, since we
+        # won't actually use it since not inside of a browser
+        self.assertTrue('noVNC' in resp.data and '<script' in resp.data,
+                        'Not a valid noVNC javascript html document.')
+
+    def _validate_rfb_negotiation(self):
+        """Verify we can connect to novnc and do the websocket connection."""
+        # Turn the Socket into a WebSocket to do the communication
+        data = self._websocket.receive_frame()
+        self.assertFalse(data is None or len(data) == 0,
+                         'Token must be invalid because the connection '
+                         'closed.')
+        # Parse the RFB version from the data to make sure it is valid
+        # and greater than or equal to 3.3
+        version = float("%d.%d" % (int(data[4:7], base=10),
+                                   int(data[8:11], base=10)))
+        self.assertTrue(version >= 3.3, 'Bad RFB Version: ' + str(version))
+        # Send our RFB version to the server, which we will just go with 3.3
+        self._websocket.send_frame(str(data))
+        # Get the sever authentication type and make sure None is supported
+        data = self._websocket.receive_frame()
+        self.assertIsNotNone(data, 'Expected authentication type None.')
+        self.assertGreaterEqual(
+            len(data), 2, 'Expected authentication type None.')
+        self.assertIn(
+            1, [ord(data[i + 1]) for i in range(ord(data[0]))],
+            'Expected authentication type None.')
+        # Send to the server that we only support authentication type None
+        self._websocket.send_frame(six.int2byte(1))
+        # The server should send 4 bytes of 0's if security handshake succeeded
+        data = self._websocket.receive_frame()
+        self.assertEqual(
+            len(data), 4, 'Server did not think security was successful.')
+        self.assertEqual(
+            [ord(i) for i in data], [0, 0, 0, 0],
+            'Server did not think security was successful.')
+        # Say to leave the desktop as shared as part of client initialization
+        self._websocket.send_frame(six.int2byte(1))
+        # Get the server initialization packet back and make sure it is the
+        # right structure where bytes 20-24 is the name length and
+        # 24-N is the name
+        data = self._websocket.receive_frame()
+        data_length = len(data) if data is not None else 0
+        self.assertFalse(data_length <= 24 or
+                         data_length != (struct.unpack(">L",
+                                         data[20:24])[0] + 24),
+                         'Server initialization was not the right format.')
+        # Since the rest of the data on the screen is arbitrary, we will
+        # close the socket and end our validation of the data at this point
+        # Assert that the latest check was false, meaning that the server
+        # initialization was the right format
+        self.assertFalse(data_length <= 24 or
+                         data_length != (struct.unpack(">L",
+                                         data[20:24])[0] + 24))
+
+    def _validate_websocket_upgrade(self):
+        self.assertTrue(
+            self._websocket.response.startswith('HTTP/1.1 101 Switching '
+                                                'Protocols\r\n'),
+            'Did not get the expected 101 on the websockify call: '
+            + str(len(self._websocket.response)))
+        self.assertTrue(
+            self._websocket.response.find('Server: WebSockify') > 0,
+            'Did not get the expected WebSocket HTTP Response.')
+
+    def _create_websocket(self, url):
+        url = urlparse.urlparse(url)
+        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        client_socket.connect((url.hostname, url.port))
+        # Turn the Socket into a WebSocket to do the communication
+        return _WebSocket(client_socket, url)
+
+    @decorators.idempotent_id('c640fdff-8ab4-45a4-a5d8-7e6146cbd0dc')
+    def test_novnc(self):
+        body = self.client.get_vnc_console(self.server['id'],
+                                           type='novnc')['console']
+        self.assertEqual('novnc', body['type'])
+        # Do the initial HTTP Request to novncproxy to get the NoVNC JavaScript
+        self._validate_novnc_html(body['url'])
+        # Do the WebSockify HTTP Request to novncproxy to do the RFB connection
+        self._websocket = self._create_websocket(body['url'])
+        # Validate that we succesfully connected and upgraded to Web Sockets
+        self._validate_websocket_upgrade()
+        # Validate the RFB Negotiation to determine if a valid VNC session
+        self._validate_rfb_negotiation()
+
+    @decorators.idempotent_id('f9c79937-addc-4aaa-9e0e-841eef02aeb7')
+    def test_novnc_bad_token(self):
+        body = self.client.get_vnc_console(self.server['id'],
+                                           type='novnc')['console']
+        self.assertEqual('novnc', body['type'])
+        # Do the WebSockify HTTP Request to novncproxy with a bad token
+        url = body['url'].replace('token=', 'token=bad')
+        self._websocket = self._create_websocket(url)
+        # Make sure the novncproxy rejected the connection and closed it
+        data = self._websocket.receive_frame()
+        self.assertTrue(data is None or len(data) == 0,
+                        "The novnc proxy actually sent us some data, but we "
+                        "expected it to close the connection.")
+
+
+class _WebSocket(object):
+    def __init__(self, client_socket, url):
+        """Contructor for the WebSocket wrapper to the socket."""
+        self._socket = client_socket
+        # Upgrade the HTTP connection to a WebSocket
+        self._upgrade(url)
+
+    def receive_frame(self):
+        """Wrapper for receiving data to parse the WebSocket frame format"""
+        # We need to loop until we either get some bytes back in the frame
+        # or no data was received (meaning the socket was closed).  This is
+        # done to handle the case where we get back some empty frames
+        while True:
+            header = self._socket.recv(2)
+            # If we didn't receive any data, just return None
+            if len(header) == 0:
+                return None
+            # We will make the assumption that we are only dealing with
+            # frames less than 125 bytes here (for the negotiation) and
+            # that only the 2nd byte contains the length, and since the
+            # server doesn't do masking, we can just read the data length
+            if ord(header[1]) & 127 > 0:
+                return self._socket.recv(ord(header[1]) & 127)
+
+    def send_frame(self, data):
+        """Wrapper for sending data to add in the WebSocket frame format."""
+        frame_bytes = list()
+        # For the first byte, want to say we are sending binary data (130)
+        frame_bytes.append(130)
+        # Only sending negotiation data so don't need to worry about > 125
+        # We do need to add the bit that says we are masking the data
+        frame_bytes.append(len(data) | 128)
+        # We don't really care about providing a random mask for security
+        # So we will just hard-code a value since a test program
+        mask = [7, 2, 1, 9]
+        for i in range(len(mask)):
+            frame_bytes.append(mask[i])
+        # Mask each of the actual data bytes that we are going to send
+        for i in range(len(data)):
+            frame_bytes.append(ord(data[i]) ^ mask[i % 4])
+        # Convert our integer list to a binary array of bytes
+        frame_bytes = struct.pack('!%iB' % len(frame_bytes), * frame_bytes)
+        self._socket.sendall(frame_bytes)
+
+    def close(self):
+        """Helper method to close the connection."""
+        # Close down the real socket connection and exit the test program
+        if self._socket is not None:
+            self._socket.shutdown(1)
+            self._socket.close()
+            self._socket = None
+
+    def _upgrade(self, url):
+        """Upgrade the HTTP connection to a WebSocket and verify."""
+        # The real request goes to the /websockify URI always
+        reqdata = 'GET /websockify HTTP/1.1\r\n'
+        reqdata += 'Host: %s:%s\r\n' % (url.hostname, url.port)
+        # Tell the HTTP Server to Upgrade the connection to a WebSocket
+        reqdata += 'Upgrade: websocket\r\nConnection: Upgrade\r\n'
+        # The token=xxx is sent as a Cookie not in the URI
+        reqdata += 'Cookie: %s\r\n' % url.query
+        # Use a hard-coded WebSocket key since a test program
+        reqdata += 'Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n'
+        reqdata += 'Sec-WebSocket-Version: 13\r\n'
+        # We are choosing to use binary even though browser may do Base64
+        reqdata += 'Sec-WebSocket-Protocol: binary\r\n\r\n'
+        # Send the HTTP GET request and get the response back
+        self._socket.sendall(reqdata)
+        self.response = data = self._socket.recv(4096)
+        # Loop through & concatenate all of the data in the response body
+        while len(data) > 0 and self.response.find('\r\n\r\n') < 0:
+            data = self._socket.recv(4096)
+            self.response += data
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 853d2ff..b22a434 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -178,6 +178,7 @@
                           self.client.rebuild_server,
                           server['id'], self.image_ref_alt)
 
+    @test.related_bug('1660878', status_code=409)
     @test.attr(type=['negative'])
     @decorators.idempotent_id('581a397d-5eab-486f-9cf9-1014bbd4c984')
     def test_reboot_deleted_server(self):
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/v2/test_endpoints.py b/tempest/api/identity/admin/v2/test_endpoints.py
index 0da579c..df55d2f 100644
--- a/tempest/api/identity/admin/v2/test_endpoints.py
+++ b/tempest/api/identity/admin/v2/test_endpoints.py
@@ -15,7 +15,7 @@
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class EndPointsTestJSON(base.BaseIdentityV2AdminTest):
@@ -55,7 +55,7 @@
             cls.services_client.delete_service(s)
         super(EndPointsTestJSON, cls).resource_cleanup()
 
-    @test.idempotent_id('11f590eb-59d8-4067-8b2b-980c7f387f51')
+    @decorators.idempotent_id('11f590eb-59d8-4067-8b2b-980c7f387f51')
     def test_list_endpoints(self):
         # Get a list of endpoints
         fetched_endpoints = self.endpoints_client.list_endpoints()['endpoints']
@@ -66,7 +66,7 @@
                          "Failed to find endpoint %s in fetched list" %
                          ', '.join(str(e) for e in missing_endpoints))
 
-    @test.idempotent_id('9974530a-aa28-4362-8403-f06db02b26c1')
+    @decorators.idempotent_id('9974530a-aa28-4362-8403-f06db02b26c1')
     def test_create_list_delete_endpoint(self):
         region = data_utils.rand_name('region')
         url = data_utils.rand_url()
diff --git a/tempest/api/identity/admin/v2/test_roles.py b/tempest/api/identity/admin/v2/test_roles.py
index d284aac..799b653 100644
--- a/tempest/api/identity/admin/v2/test_roles.py
+++ b/tempest/api/identity/admin/v2/test_roles.py
@@ -16,7 +16,7 @@
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class RolesTestJSON(base.BaseIdentityV2AdminTest):
@@ -49,7 +49,7 @@
                 found = True
         self.assertTrue(found, "assigned role was not in list")
 
-    @test.idempotent_id('75d9593f-50b7-4fcf-bd64-e3fb4a278e23')
+    @decorators.idempotent_id('75d9593f-50b7-4fcf-bd64-e3fb4a278e23')
     def test_list_roles(self):
         """Return a list of all roles."""
         body = self.roles_client.list_roles()['roles']
@@ -57,7 +57,7 @@
         self.assertTrue(any(found))
         self.assertEqual(len(found), len(self.roles))
 
-    @test.idempotent_id('c62d909d-6c21-48c0-ae40-0a0760e6db5e')
+    @decorators.idempotent_id('c62d909d-6c21-48c0-ae40-0a0760e6db5e')
     def test_role_create_delete(self):
         """Role should be created, verified, and deleted."""
         role_name = data_utils.rand_name(name='role-test')
@@ -76,7 +76,7 @@
         found = [role for role in body if role['name'] == role_name]
         self.assertFalse(any(found))
 
-    @test.idempotent_id('db6870bd-a6ed-43be-a9b1-2f10a5c9994f')
+    @decorators.idempotent_id('db6870bd-a6ed-43be-a9b1-2f10a5c9994f')
     def test_get_role_by_id(self):
         """Get a role by its id."""
         role = self.setup_test_role()
@@ -86,7 +86,7 @@
         self.assertEqual(role_id, body['id'])
         self.assertEqual(role_name, body['name'])
 
-    @test.idempotent_id('0146f675-ffbd-4208-b3a4-60eb628dbc5e')
+    @decorators.idempotent_id('0146f675-ffbd-4208-b3a4-60eb628dbc5e')
     def test_assign_user_role(self):
         """Assign a role to a user on a tenant."""
         (user, tenant, role) = self._get_role_params()
@@ -97,7 +97,7 @@
             tenant['id'], user['id'])['roles']
         self.assert_role_in_role_list(role, roles)
 
-    @test.idempotent_id('f0b9292c-d3ba-4082-aa6c-440489beef69')
+    @decorators.idempotent_id('f0b9292c-d3ba-4082-aa6c-440489beef69')
     def test_remove_user_role(self):
         """Remove a role assigned to a user on a tenant."""
         (user, tenant, role) = self._get_role_params()
@@ -107,7 +107,7 @@
                                                            user['id'],
                                                            user_role['id'])
 
-    @test.idempotent_id('262e1e3e-ed71-4edd-a0e5-d64e83d66d05')
+    @decorators.idempotent_id('262e1e3e-ed71-4edd-a0e5-d64e83d66d05')
     def test_list_user_roles(self):
         """List roles assigned to a user on tenant."""
         (user, tenant, role) = self._get_role_params()
diff --git a/tempest/api/identity/admin/v2/test_roles_negative.py b/tempest/api/identity/admin/v2/test_roles_negative.py
index 7116913..b017b44 100644
--- a/tempest/api/identity/admin/v2/test_roles_negative.py
+++ b/tempest/api/identity/admin/v2/test_roles_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.identity 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
 
@@ -28,14 +29,14 @@
         return (user, tenant, role)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d5d5f1df-f8ca-4de0-b2ef-259c1cc67025')
+    @decorators.idempotent_id('d5d5f1df-f8ca-4de0-b2ef-259c1cc67025')
     def test_list_roles_by_unauthorized_user(self):
         # Non-administrator user should not be able to list roles
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_roles_client.list_roles)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('11a3c7da-df6c-40c2-abc2-badd682edf9f')
+    @decorators.idempotent_id('11a3c7da-df6c-40c2-abc2-badd682edf9f')
     def test_list_roles_request_without_token(self):
         # Request to list roles without a valid token should fail
         token = self.client.auth_provider.get_token()
@@ -44,14 +45,14 @@
         self.client.auth_provider.clear_auth()
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('c0b89e56-accc-4c73-85f8-9c0f866104c1')
+    @decorators.idempotent_id('c0b89e56-accc-4c73-85f8-9c0f866104c1')
     def test_role_create_blank_name(self):
         # Should not be able to create a role with a blank name
         self.assertRaises(lib_exc.BadRequest, self.roles_client.create_role,
                           name='')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('585c8998-a8a4-4641-a5dd-abef7a8ced00')
+    @decorators.idempotent_id('585c8998-a8a4-4641-a5dd-abef7a8ced00')
     def test_create_role_by_unauthorized_user(self):
         # Non-administrator user should not be able to create role
         role_name = data_utils.rand_name(name='role')
@@ -60,7 +61,7 @@
                           name=role_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a7edd17a-e34a-4aab-8bb7-fa6f498645b8')
+    @decorators.idempotent_id('a7edd17a-e34a-4aab-8bb7-fa6f498645b8')
     def test_create_role_request_without_token(self):
         # Request to create role without a valid token should fail
         token = self.client.auth_provider.get_token()
@@ -71,7 +72,7 @@
         self.client.auth_provider.clear_auth()
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('c0cde2c8-81c1-4bb0-8fe2-cf615a3547a8')
+    @decorators.idempotent_id('c0cde2c8-81c1-4bb0-8fe2-cf615a3547a8')
     def test_role_create_duplicate(self):
         # Role names should be unique
         role_name = data_utils.rand_name(name='role-dup')
@@ -82,7 +83,7 @@
                           name=role_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('15347635-b5b1-4a87-a280-deb2bd6d865e')
+    @decorators.idempotent_id('15347635-b5b1-4a87-a280-deb2bd6d865e')
     def test_delete_role_by_unauthorized_user(self):
         # Non-administrator user should not be able to delete role
         role_name = data_utils.rand_name(name='role')
@@ -93,7 +94,7 @@
                           self.non_admin_roles_client.delete_role, role_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('44b60b20-70de-4dac-beaf-a3fc2650a16b')
+    @decorators.idempotent_id('44b60b20-70de-4dac-beaf-a3fc2650a16b')
     def test_delete_role_request_without_token(self):
         # Request to delete role without a valid token should fail
         role_name = data_utils.rand_name(name='role')
@@ -108,7 +109,7 @@
         self.client.auth_provider.clear_auth()
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('38373691-8551-453a-b074-4260ad8298ef')
+    @decorators.idempotent_id('38373691-8551-453a-b074-4260ad8298ef')
     def test_delete_role_non_existent(self):
         # Attempt to delete a non existent role should fail
         non_existent_role = data_utils.rand_uuid_hex()
@@ -116,7 +117,7 @@
                           non_existent_role)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('391df5cf-3ec3-46c9-bbe5-5cb58dd4dc41')
+    @decorators.idempotent_id('391df5cf-3ec3-46c9-bbe5-5cb58dd4dc41')
     def test_assign_user_role_by_unauthorized_user(self):
         # Non-administrator user should not be authorized to
         # assign a role to user
@@ -127,7 +128,7 @@
             tenant['id'], user['id'], role['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f0d2683c-5603-4aee-95d7-21420e87cfd8')
+    @decorators.idempotent_id('f0d2683c-5603-4aee-95d7-21420e87cfd8')
     def test_assign_user_role_request_without_token(self):
         # Request to assign a role to a user without a valid token
         (user, tenant, role) = self._get_role_params()
@@ -140,7 +141,7 @@
         self.client.auth_provider.clear_auth()
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('99b297f6-2b5d-47c7-97a9-8b6bb4f91042')
+    @decorators.idempotent_id('99b297f6-2b5d-47c7-97a9-8b6bb4f91042')
     def test_assign_user_role_for_non_existent_role(self):
         # Attempt to assign a non existent role to user should fail
         (user, tenant, role) = self._get_role_params()
@@ -150,7 +151,7 @@
                           tenant['id'], user['id'], non_existent_role)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('b2285aaa-9e76-4704-93a9-7a8acd0a6c8f')
+    @decorators.idempotent_id('b2285aaa-9e76-4704-93a9-7a8acd0a6c8f')
     def test_assign_user_role_for_non_existent_tenant(self):
         # Attempt to assign a role on a non existent tenant should fail
         (user, tenant, role) = self._get_role_params()
@@ -160,7 +161,7 @@
                           non_existent_tenant, user['id'], role['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5c3132cd-c4c8-4402-b5ea-71eb44e97793')
+    @decorators.idempotent_id('5c3132cd-c4c8-4402-b5ea-71eb44e97793')
     def test_assign_duplicate_user_role(self):
         # Duplicate user role should not get assigned
         (user, tenant, role) = self._get_role_params()
@@ -172,7 +173,7 @@
                           tenant['id'], user['id'], role['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d0537987-0977-448f-a435-904c15de7298')
+    @decorators.idempotent_id('d0537987-0977-448f-a435-904c15de7298')
     def test_remove_user_role_by_unauthorized_user(self):
         # Non-administrator user should not be authorized to
         # remove a user's role
@@ -186,7 +187,7 @@
             tenant['id'], user['id'], role['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('cac81cf4-c1d2-47dc-90d3-f2b7eb572286')
+    @decorators.idempotent_id('cac81cf4-c1d2-47dc-90d3-f2b7eb572286')
     def test_remove_user_role_request_without_token(self):
         # Request to remove a user's role without a valid token
         (user, tenant, role) = self._get_role_params()
@@ -201,7 +202,7 @@
         self.client.auth_provider.clear_auth()
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ab32d759-cd16-41f1-a86e-44405fa9f6d2')
+    @decorators.idempotent_id('ab32d759-cd16-41f1-a86e-44405fa9f6d2')
     def test_remove_user_role_non_existent_role(self):
         # Attempt to delete a non existent role from a user should fail
         (user, tenant, role) = self._get_role_params()
@@ -214,7 +215,7 @@
                           tenant['id'], user['id'], non_existent_role)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('67a679ec-03dd-4551-bbfc-d1c93284f023')
+    @decorators.idempotent_id('67a679ec-03dd-4551-bbfc-d1c93284f023')
     def test_remove_user_role_non_existent_tenant(self):
         # Attempt to remove a role from a non existent tenant should fail
         (user, tenant, role) = self._get_role_params()
@@ -227,7 +228,7 @@
                           non_existent_tenant, user['id'], role['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7391ab4c-06f3-477a-a64a-c8e55ce89837')
+    @decorators.idempotent_id('7391ab4c-06f3-477a-a64a-c8e55ce89837')
     def test_list_user_roles_by_unauthorized_user(self):
         # Non-administrator user should not be authorized to list
         # a user's roles
@@ -241,7 +242,7 @@
             tenant['id'], user['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('682adfb2-fd5f-4b0a-a9ca-322e9bebb907')
+    @decorators.idempotent_id('682adfb2-fd5f-4b0a-a9ca-322e9bebb907')
     def test_list_user_roles_request_without_token(self):
         # Request to list user's roles without a valid token should fail
         (user, tenant, role) = self._get_role_params()
diff --git a/tempest/api/identity/admin/v2/test_services.py b/tempest/api/identity/admin/v2/test_services.py
index 7973a03..3b0ddbb 100644
--- a/tempest/api/identity/admin/v2/test_services.py
+++ b/tempest/api/identity/admin/v2/test_services.py
@@ -15,6 +15,7 @@
 
 from tempest.api.identity 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
 
@@ -28,7 +29,7 @@
         self.assertRaises(lib_exc.NotFound, self.services_client.show_service,
                           service_id)
 
-    @test.idempotent_id('84521085-c6e6-491c-9a08-ec9f70f90110')
+    @decorators.idempotent_id('84521085-c6e6-491c-9a08-ec9f70f90110')
     def test_create_get_delete_service(self):
         # GET Service
         # Creating a Service
@@ -63,7 +64,7 @@
         self.assertEqual(fetched_service['description'],
                          service_data['description'])
 
-    @test.idempotent_id('5d3252c8-e555-494b-a6c8-e11d7335da42')
+    @decorators.idempotent_id('5d3252c8-e555-494b-a6c8-e11d7335da42')
     def test_create_service_without_description(self):
         # Create a service only with name and type
         name = data_utils.rand_name('service')
@@ -78,7 +79,7 @@
         self.assertEqual(s_type, service['type'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('34ea6489-012d-4a86-9038-1287cadd5eca')
+    @decorators.idempotent_id('34ea6489-012d-4a86-9038-1287cadd5eca')
     def test_list_services(self):
         # Create, List, Verify and Delete Services
         services = []
diff --git a/tempest/api/identity/admin/v2/test_tenant_negative.py b/tempest/api/identity/admin/v2/test_tenant_negative.py
index baa78e9..e8c32b9 100644
--- a/tempest/api/identity/admin/v2/test_tenant_negative.py
+++ b/tempest/api/identity/admin/v2/test_tenant_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.identity 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
 
@@ -22,14 +23,14 @@
 class TenantsNegativeTestJSON(base.BaseIdentityV2AdminTest):
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ca9bb202-63dd-4240-8a07-8ef9c19c04bb')
+    @decorators.idempotent_id('ca9bb202-63dd-4240-8a07-8ef9c19c04bb')
     def test_list_tenants_by_unauthorized_user(self):
         # Non-administrator user should not be able to list tenants
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_tenants_client.list_tenants)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('df33926c-1c96-4d8d-a762-79cc6b0c3cf4')
+    @decorators.idempotent_id('df33926c-1c96-4d8d-a762-79cc6b0c3cf4')
     def test_list_tenant_request_without_token(self):
         # Request to list tenants without a valid token should fail
         token = self.client.auth_provider.get_token()
@@ -39,7 +40,7 @@
         self.client.auth_provider.clear_auth()
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('162ba316-f18b-4987-8c0c-fd9140cd63ed')
+    @decorators.idempotent_id('162ba316-f18b-4987-8c0c-fd9140cd63ed')
     def test_tenant_delete_by_unauthorized_user(self):
         # Non-administrator user should not be able to delete a tenant
         tenant_name = data_utils.rand_name(name='tenant')
@@ -50,7 +51,7 @@
                           tenant['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e450db62-2e9d-418f-893a-54772d6386b1')
+    @decorators.idempotent_id('e450db62-2e9d-418f-893a-54772d6386b1')
     def test_tenant_delete_request_without_token(self):
         # Request to delete a tenant without a valid token should fail
         tenant_name = data_utils.rand_name(name='tenant')
@@ -64,14 +65,14 @@
         self.client.auth_provider.clear_auth()
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9c9a2aed-6e3c-467a-8f5c-89da9d1b516b')
+    @decorators.idempotent_id('9c9a2aed-6e3c-467a-8f5c-89da9d1b516b')
     def test_delete_non_existent_tenant(self):
         # Attempt to delete a non existent tenant should fail
         self.assertRaises(lib_exc.NotFound, self.tenants_client.delete_tenant,
                           data_utils.rand_uuid_hex())
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('af16f44b-a849-46cb-9f13-a751c388f739')
+    @decorators.idempotent_id('af16f44b-a849-46cb-9f13-a751c388f739')
     def test_tenant_create_duplicate(self):
         # Tenant names should be unique
         tenant_name = data_utils.rand_name(name='tenant')
@@ -83,7 +84,7 @@
                           name=tenant_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d26b278a-6389-4702-8d6e-5980d80137e0')
+    @decorators.idempotent_id('d26b278a-6389-4702-8d6e-5980d80137e0')
     def test_create_tenant_by_unauthorized_user(self):
         # Non-administrator user should not be authorized to create a tenant
         tenant_name = data_utils.rand_name(name='tenant')
@@ -92,7 +93,7 @@
                           name=tenant_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a3ee9d7e-6920-4dd5-9321-d4b2b7f0a638')
+    @decorators.idempotent_id('a3ee9d7e-6920-4dd5-9321-d4b2b7f0a638')
     def test_create_tenant_request_without_token(self):
         # Create tenant request without a token should not be authorized
         tenant_name = data_utils.rand_name(name='tenant')
@@ -104,7 +105,7 @@
         self.client.auth_provider.clear_auth()
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5a2e4ca9-b0c0-486c-9c48-64a94fba2395')
+    @decorators.idempotent_id('5a2e4ca9-b0c0-486c-9c48-64a94fba2395')
     def test_create_tenant_with_empty_name(self):
         # Tenant name should not be empty
         self.assertRaises(lib_exc.BadRequest,
@@ -112,7 +113,7 @@
                           name='')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('2ff18d1e-dfe3-4359-9dc3-abf582c196b9')
+    @decorators.idempotent_id('2ff18d1e-dfe3-4359-9dc3-abf582c196b9')
     def test_create_tenants_name_length_over_64(self):
         # Tenant name length should not be greater than 64 characters
         tenant_name = 'a' * 65
@@ -121,14 +122,14 @@
                           name=tenant_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('bd20dc2a-9557-4db7-b755-f48d952ad706')
+    @decorators.idempotent_id('bd20dc2a-9557-4db7-b755-f48d952ad706')
     def test_update_non_existent_tenant(self):
         # Attempt to update a non existent tenant should fail
         self.assertRaises(lib_exc.NotFound, self.tenants_client.update_tenant,
                           data_utils.rand_uuid_hex())
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('41704dc5-c5f7-4f79-abfa-76e6fedc570b')
+    @decorators.idempotent_id('41704dc5-c5f7-4f79-abfa-76e6fedc570b')
     def test_tenant_update_by_unauthorized_user(self):
         # Non-administrator user should not be able to update a tenant
         tenant_name = data_utils.rand_name(name='tenant')
@@ -139,7 +140,7 @@
                           tenant['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7a421573-72c7-4c22-a98e-ce539219c657')
+    @decorators.idempotent_id('7a421573-72c7-4c22-a98e-ce539219c657')
     def test_tenant_update_request_without_token(self):
         # Request to update a tenant without a valid token should fail
         tenant_name = data_utils.rand_name(name='tenant')
diff --git a/tempest/api/identity/admin/v2/test_tenants.py b/tempest/api/identity/admin/v2/test_tenants.py
index f4fad53..eb51b5a 100644
--- a/tempest/api/identity/admin/v2/test_tenants.py
+++ b/tempest/api/identity/admin/v2/test_tenants.py
@@ -16,12 +16,12 @@
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class TenantsTestJSON(base.BaseIdentityV2AdminTest):
 
-    @test.idempotent_id('16c6e05c-6112-4b0e-b83f-5e43f221b6b0')
+    @decorators.idempotent_id('16c6e05c-6112-4b0e-b83f-5e43f221b6b0')
     def test_tenant_list_delete(self):
         # Create several tenants and delete them
         tenants = []
@@ -45,7 +45,7 @@
         found = [tenant for tenant in body if tenant['id'] in tenant_ids]
         self.assertFalse(any(found), 'Tenants failed to delete')
 
-    @test.idempotent_id('d25e9f24-1310-4d29-b61b-d91299c21d6d')
+    @decorators.idempotent_id('d25e9f24-1310-4d29-b61b-d91299c21d6d')
     def test_tenant_create_with_description(self):
         # Create tenant with a description
         tenant_name = data_utils.rand_name(name='tenant')
@@ -66,7 +66,7 @@
                          'to be set')
         self.tenants_client.delete_tenant(tenant_id)
 
-    @test.idempotent_id('670bdddc-1cd7-41c7-b8e2-751cfb67df50')
+    @decorators.idempotent_id('670bdddc-1cd7-41c7-b8e2-751cfb67df50')
     def test_tenant_create_enabled(self):
         # Create a tenant that is enabled
         tenant_name = data_utils.rand_name(name='tenant')
@@ -84,7 +84,7 @@
         self.assertTrue(en2, 'Enable should be True in lookup')
         self.tenants_client.delete_tenant(tenant_id)
 
-    @test.idempotent_id('3be22093-b30f-499d-b772-38340e5e16fb')
+    @decorators.idempotent_id('3be22093-b30f-499d-b772-38340e5e16fb')
     def test_tenant_create_not_enabled(self):
         # Create a tenant that is not enabled
         tenant_name = data_utils.rand_name(name='tenant')
@@ -104,7 +104,7 @@
                          'Enable should be False in lookup')
         self.tenants_client.delete_tenant(tenant_id)
 
-    @test.idempotent_id('781f2266-d128-47f3-8bdb-f70970add238')
+    @decorators.idempotent_id('781f2266-d128-47f3-8bdb-f70970add238')
     def test_tenant_update_name(self):
         # Update name attribute of a tenant
         t_name1 = data_utils.rand_name(name='tenant')
@@ -131,7 +131,7 @@
 
         self.tenants_client.delete_tenant(t_id)
 
-    @test.idempotent_id('859fcfe1-3a03-41ef-86f9-b19a47d1cd87')
+    @decorators.idempotent_id('859fcfe1-3a03-41ef-86f9-b19a47d1cd87')
     def test_tenant_update_desc(self):
         # Update description attribute of a tenant
         t_name = data_utils.rand_name(name='tenant')
@@ -161,7 +161,7 @@
 
         self.tenants_client.delete_tenant(t_id)
 
-    @test.idempotent_id('8fc8981f-f12d-4c66-9972-2bdcf2bc2e1a')
+    @decorators.idempotent_id('8fc8981f-f12d-4c66-9972-2bdcf2bc2e1a')
     def test_tenant_update_enable(self):
         # Update the enabled attribute of a tenant
         t_name = data_utils.rand_name(name='tenant')
diff --git a/tempest/api/identity/admin/v2/test_tokens.py b/tempest/api/identity/admin/v2/test_tokens.py
index 2f7e941..7b5e01e 100644
--- a/tempest/api/identity/admin/v2/test_tokens.py
+++ b/tempest/api/identity/admin/v2/test_tokens.py
@@ -15,12 +15,12 @@
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class TokensTestJSON(base.BaseIdentityV2AdminTest):
 
-    @test.idempotent_id('453ad4d5-e486-4b2f-be72-cffc8149e586')
+    @decorators.idempotent_id('453ad4d5-e486-4b2f-be72-cffc8149e586')
     def test_create_get_delete_token(self):
         # get a token by username and password
         user_name = data_utils.rand_name(name='user')
@@ -54,7 +54,7 @@
         # then delete the token
         self.client.delete_token(token_id)
 
-    @test.idempotent_id('25ba82ee-8a32-4ceb-8f50-8b8c71e8765e')
+    @decorators.idempotent_id('25ba82ee-8a32-4ceb-8f50-8b8c71e8765e')
     def test_rescope_token(self):
         """An unscoped token can be requested
 
diff --git a/tempest/api/identity/admin/v2/test_users.py b/tempest/api/identity/admin/v2/test_users.py
index 4a4b51a..5889813 100644
--- a/tempest/api/identity/admin/v2/test_users.py
+++ b/tempest/api/identity/admin/v2/test_users.py
@@ -20,6 +20,7 @@
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -33,7 +34,7 @@
         cls.alt_email = cls.alt_user + '@testmail.tm'
 
     @test.attr(type='smoke')
-    @test.idempotent_id('2d55a71e-da1d-4b43-9c03-d269fd93d905')
+    @decorators.idempotent_id('2d55a71e-da1d-4b43-9c03-d269fd93d905')
     def test_create_user(self):
         # Create a user
         tenant = self.setup_test_tenant()
@@ -45,7 +46,7 @@
         self.addCleanup(self.users_client.delete_user, user['id'])
         self.assertEqual(self.alt_user, user['name'])
 
-    @test.idempotent_id('89d9fdb8-15c2-4304-a429-48715d0af33d')
+    @decorators.idempotent_id('89d9fdb8-15c2-4304-a429-48715d0af33d')
     def test_create_user_with_enabled(self):
         # Create a user with enabled : False
         tenant = self.setup_test_tenant()
@@ -61,7 +62,7 @@
         self.assertEqual(False, user['enabled'])
         self.assertEqual(self.alt_email, user['email'])
 
-    @test.idempotent_id('39d05857-e8a5-4ed4-ba83-0b52d3ab97ee')
+    @decorators.idempotent_id('39d05857-e8a5-4ed4-ba83-0b52d3ab97ee')
     def test_update_user(self):
         # Test case to check if updating of user attributes is successful.
         test_user = data_utils.rand_name('test_user')
@@ -88,7 +89,7 @@
         self.assertEqual(u_email2, updated_user['email'])
         self.assertEqual(False, update_user['enabled'])
 
-    @test.idempotent_id('29ed26f4-a74e-4425-9a85-fdb49fa269d2')
+    @decorators.idempotent_id('29ed26f4-a74e-4425-9a85-fdb49fa269d2')
     def test_delete_user(self):
         # Delete a user
         test_user = data_utils.rand_name('test_user')
@@ -102,7 +103,7 @@
                         self.users_client.delete_user, user['id'])
         self.users_client.delete_user(user['id'])
 
-    @test.idempotent_id('aca696c3-d645-4f45-b728-63646045beb1')
+    @decorators.idempotent_id('aca696c3-d645-4f45-b728-63646045beb1')
     def test_user_authentication(self):
         # Valid user's token is authenticated
         password = data_utils.rand_password()
@@ -117,7 +118,7 @@
                                password,
                                tenant['name'])
 
-    @test.idempotent_id('5d1fa498-4c2d-4732-a8fe-2b054598cfdd')
+    @decorators.idempotent_id('5d1fa498-4c2d-4732-a8fe-2b054598cfdd')
     def test_authentication_request_without_token(self):
         # Request for token authentication with a valid token in header
         password = data_utils.rand_password()
@@ -136,7 +137,7 @@
                                tenant['name'])
         self.client.auth_provider.clear_auth()
 
-    @test.idempotent_id('a149c02e-e5e0-4b89-809e-7e8faf33ccda')
+    @decorators.idempotent_id('a149c02e-e5e0-4b89-809e-7e8faf33ccda')
     def test_get_users(self):
         # Get a list of users and find the test user
         user = self.setup_test_user()
@@ -145,7 +146,7 @@
                         matchers.Contains(user['name']),
                         "Could not find %s" % user['name'])
 
-    @test.idempotent_id('6e317209-383a-4bed-9f10-075b7c82c79a')
+    @decorators.idempotent_id('6e317209-383a-4bed-9f10-075b7c82c79a')
     def test_list_users_for_tenant(self):
         # Return a list of all users for a tenant
         tenant = self.setup_test_tenant()
@@ -181,7 +182,7 @@
                          "Failed to find user %s in fetched list" %
                          ', '.join(m_user for m_user in missing_users))
 
-    @test.idempotent_id('a8b54974-40e1-41c0-b812-50fc90827971')
+    @decorators.idempotent_id('a8b54974-40e1-41c0-b812-50fc90827971')
     def test_list_users_with_roles_for_tenant(self):
         # Return list of users on tenant when roles are assigned to users
         user = self.setup_test_user()
@@ -217,7 +218,7 @@
                          "Failed to find user %s in fetched list" %
                          ', '.join(m_user for m_user in missing_users))
 
-    @test.idempotent_id('1aeb25ac-6ec5-4d8b-97cb-7ac3567a989f')
+    @decorators.idempotent_id('1aeb25ac-6ec5-4d8b-97cb-7ac3567a989f')
     def test_update_user_password(self):
         # Test case to check if updating of user password is successful.
         user = self.setup_test_user()
diff --git a/tempest/api/identity/admin/v2/test_users_negative.py b/tempest/api/identity/admin/v2/test_users_negative.py
index 597413e..49fda4e 100644
--- a/tempest/api/identity/admin/v2/test_users_negative.py
+++ b/tempest/api/identity/admin/v2/test_users_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.identity 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
 
@@ -29,7 +30,7 @@
         cls.alt_email = cls.alt_user + '@testmail.tm'
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('60a1f5fa-5744-4cdf-82bf-60b7de2d29a4')
+    @decorators.idempotent_id('60a1f5fa-5744-4cdf-82bf-60b7de2d29a4')
     def test_create_user_by_unauthorized_user(self):
         # Non-administrator should not be authorized to create a user
         tenant = self.setup_test_tenant()
@@ -40,7 +41,7 @@
                           email=self.alt_email)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d80d0c2f-4514-4d1e-806d-0930dfc5a187')
+    @decorators.idempotent_id('d80d0c2f-4514-4d1e-806d-0930dfc5a187')
     def test_create_user_with_empty_name(self):
         # User with an empty name should not be created
         tenant = self.setup_test_tenant()
@@ -50,7 +51,7 @@
                           email=self.alt_email)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7704b4f3-3b75-4b82-87cc-931d41c8f780')
+    @decorators.idempotent_id('7704b4f3-3b75-4b82-87cc-931d41c8f780')
     def test_create_user_with_name_length_over_255(self):
         # Length of user name filed should be restricted to 255 characters
         tenant = self.setup_test_tenant()
@@ -60,7 +61,7 @@
                           email=self.alt_email)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('57ae8558-120c-4723-9308-3751474e7ecf')
+    @decorators.idempotent_id('57ae8558-120c-4723-9308-3751474e7ecf')
     def test_create_user_with_duplicate_name(self):
         # Duplicate user should not be created
         password = data_utils.rand_password()
@@ -73,7 +74,7 @@
                           email=user['email'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0132cc22-7c4f-42e1-9e50-ac6aad31d59a')
+    @decorators.idempotent_id('0132cc22-7c4f-42e1-9e50-ac6aad31d59a')
     def test_create_user_for_non_existent_tenant(self):
         # Attempt to create a user in a non-existent tenant should fail
         self.assertRaises(lib_exc.NotFound, self.users_client.create_user,
@@ -83,7 +84,7 @@
                           email=self.alt_email)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('55bbb103-d1ae-437b-989b-bcdf8175c1f4')
+    @decorators.idempotent_id('55bbb103-d1ae-437b-989b-bcdf8175c1f4')
     def test_create_user_request_without_a_token(self):
         # Request to create a user without a valid token should fail
         tenant = self.setup_test_tenant()
@@ -101,7 +102,7 @@
                           email=self.alt_email)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('23a2f3da-4a1a-41da-abdd-632328a861ad')
+    @decorators.idempotent_id('23a2f3da-4a1a-41da-abdd-632328a861ad')
     def test_create_user_with_enabled_non_bool(self):
         # Attempt to create a user with valid enabled para should fail
         tenant = self.setup_test_tenant()
@@ -112,7 +113,7 @@
                           email=self.alt_email, enabled=3)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('3d07e294-27a0-4144-b780-a2a1bf6fee19')
+    @decorators.idempotent_id('3d07e294-27a0-4144-b780-a2a1bf6fee19')
     def test_update_user_for_non_existent_user(self):
         # Attempt to update a user non-existent user should fail
         user_name = data_utils.rand_name('user')
@@ -121,7 +122,7 @@
                           non_existent_id, name=user_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('3cc2a64b-83aa-4b02-88f0-d6ab737c4466')
+    @decorators.idempotent_id('3cc2a64b-83aa-4b02-88f0-d6ab737c4466')
     def test_update_user_request_without_a_token(self):
         # Request to update a user without a valid token should fail
 
@@ -137,7 +138,7 @@
                           self.alt_user)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('424868d5-18a7-43e1-8903-a64f95ee3aac')
+    @decorators.idempotent_id('424868d5-18a7-43e1-8903-a64f95ee3aac')
     def test_update_user_by_unauthorized_user(self):
         # Non-administrator should not be authorized to update user
         self.assertRaises(lib_exc.Forbidden,
@@ -145,7 +146,7 @@
                           self.alt_user)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d45195d5-33ed-41b9-a452-7d0d6a00f6e9')
+    @decorators.idempotent_id('d45195d5-33ed-41b9-a452-7d0d6a00f6e9')
     def test_delete_users_by_unauthorized_user(self):
         # Non-administrator user should not be authorized to delete a user
         user = self.setup_test_user()
@@ -154,14 +155,14 @@
                           user['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7cc82f7e-9998-4f89-abae-23df36495867')
+    @decorators.idempotent_id('7cc82f7e-9998-4f89-abae-23df36495867')
     def test_delete_non_existent_user(self):
         # Attempt to delete a non-existent user should fail
         self.assertRaises(lib_exc.NotFound, self.users_client.delete_user,
                           'junk12345123')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('57fe1df8-0aa7-46c0-ae9f-c2e785c7504a')
+    @decorators.idempotent_id('57fe1df8-0aa7-46c0-ae9f-c2e785c7504a')
     def test_delete_user_request_without_a_token(self):
         # Request to delete a user without a valid token should fail
 
@@ -177,7 +178,7 @@
                           self.alt_user)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('593a4981-f6d4-460a-99a1-57a78bf20829')
+    @decorators.idempotent_id('593a4981-f6d4-460a-99a1-57a78bf20829')
     def test_authentication_for_disabled_user(self):
         # Disabled user's token should not get authenticated
         password = data_utils.rand_password()
@@ -190,7 +191,7 @@
                           tenant['name'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('440a7a8d-9328-4b7b-83e0-d717010495e4')
+    @decorators.idempotent_id('440a7a8d-9328-4b7b-83e0-d717010495e4')
     def test_authentication_when_tenant_is_disabled(self):
         # User's token for a disabled tenant should not be authenticated
         password = data_utils.rand_password()
@@ -203,7 +204,7 @@
                           tenant['name'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('921f1ad6-7907-40b8-853f-637e7ee52178')
+    @decorators.idempotent_id('921f1ad6-7907-40b8-853f-637e7ee52178')
     def test_authentication_with_invalid_tenant(self):
         # User's token for an invalid tenant should not be authenticated
         password = data_utils.rand_password()
@@ -214,7 +215,7 @@
                           'junktenant1234')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('bde9aecd-3b1c-4079-858f-beb5deaa5b5e')
+    @decorators.idempotent_id('bde9aecd-3b1c-4079-858f-beb5deaa5b5e')
     def test_authentication_with_invalid_username(self):
         # Non-existent user's token should not get authenticated
         password = data_utils.rand_password()
@@ -224,7 +225,7 @@
                           'junkuser123', password, tenant['name'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d5308b33-3574-43c3-8d87-1c090c5e1eca')
+    @decorators.idempotent_id('d5308b33-3574-43c3-8d87-1c090c5e1eca')
     def test_authentication_with_invalid_password(self):
         # User's token with invalid password should not be authenticated
         user = self.setup_test_user()
@@ -233,14 +234,14 @@
                           user['name'], 'junkpass1234', tenant['name'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('284192ce-fb7c-4909-a63b-9a502e0ddd11')
+    @decorators.idempotent_id('284192ce-fb7c-4909-a63b-9a502e0ddd11')
     def test_get_users_by_unauthorized_user(self):
         # Non-administrator user should not be authorized to get user list
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_users_client.list_users)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a73591ec-1903-4ffe-be42-282b39fefc9d')
+    @decorators.idempotent_id('a73591ec-1903-4ffe-be42-282b39fefc9d')
     def test_get_users_request_without_token(self):
         # Request to get list of users without a valid token should fail
         token = self.client.auth_provider.get_token()
@@ -252,7 +253,7 @@
         self.assertRaises(lib_exc.Unauthorized, self.users_client.list_users)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f5d39046-fc5f-425c-b29e-bac2632da28e')
+    @decorators.idempotent_id('f5d39046-fc5f-425c-b29e-bac2632da28e')
     def test_list_users_with_invalid_tenant(self):
         # Should not be able to return a list of all
         # users for a non-existent tenant
diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py
index d4fe32d..e5a218d 100644
--- a/tempest/api/identity/admin/v3/test_credentials.py
+++ b/tempest/api/identity/admin/v3/test_credentials.py
@@ -16,6 +16,7 @@
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -52,7 +53,7 @@
         self.creds_client.delete_credential(cred_id)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('7cd59bf9-bda4-4c72-9467-d21cab278355')
+    @decorators.idempotent_id('7cd59bf9-bda4-4c72-9467-d21cab278355')
     def test_credentials_create_get_update_delete(self):
         blob = '{"access": "%s", "secret": "%s"}' % (
             data_utils.rand_name('Access'), data_utils.rand_name('Secret'))
@@ -87,7 +88,7 @@
             self.assertEqual(update_body['blob'][value2],
                              get_body['blob'][value2])
 
-    @test.idempotent_id('13202c00-0021-42a1-88d4-81b44d448aab')
+    @decorators.idempotent_id('13202c00-0021-42a1-88d4-81b44d448aab')
     def test_credentials_list_delete(self):
         created_cred_ids = list()
         fetched_cred_ids = list()
diff --git a/tempest/api/identity/admin/v3/test_default_project_id.py b/tempest/api/identity/admin/v3/test_default_project_id.py
index 361ff31..110695d 100644
--- a/tempest/api/identity/admin/v3/test_default_project_id.py
+++ b/tempest/api/identity/admin/v3/test_default_project_id.py
@@ -14,7 +14,7 @@
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest.lib import auth
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -32,7 +32,7 @@
         self.domains_client.update_domain(domain_id, enabled=False)
         self.domains_client.delete_domain(domain_id)
 
-    @test.idempotent_id('d6110661-6a71-49a7-a453-b5e26640ff6d')
+    @decorators.idempotent_id('d6110661-6a71-49a7-a453-b5e26640ff6d')
     def test_default_project_id(self):
         # create a domain
         dom_name = data_utils.rand_name('dom')
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index e71341f..4cf9f66 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -17,6 +17,7 @@
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -50,7 +51,7 @@
         cls.domains_client.update_domain(domain_id, enabled=False)
         cls.domains_client.delete_domain(domain_id)
 
-    @test.idempotent_id('8cf516ef-2114-48f1-907b-d32726c734d4')
+    @decorators.idempotent_id('8cf516ef-2114-48f1-907b-d32726c734d4')
     def test_list_domains(self):
         # Test to list domains
         fetched_ids = list()
@@ -62,7 +63,7 @@
                         if d['id'] not in fetched_ids]
         self.assertEqual(0, len(missing_doms))
 
-    @test.idempotent_id('c6aee07b-4981-440c-bb0b-eb598f58ffe9')
+    @decorators.idempotent_id('c6aee07b-4981-440c-bb0b-eb598f58ffe9')
     def test_list_domains_filter_by_name(self):
         # List domains filtering by name
         params = {'name': self.setup_domains[0]['name']}
@@ -74,7 +75,7 @@
         self.assertEqual(self.setup_domains[0]['name'],
                          fetched_domains[0]['name'])
 
-    @test.idempotent_id('3fd19840-65c1-43f8-b48c-51bdd066dff9')
+    @decorators.idempotent_id('3fd19840-65c1-43f8-b48c-51bdd066dff9')
     def test_list_domains_filter_by_enabled(self):
         # List domains filtering by enabled domains
         params = {'enabled': True}
@@ -87,7 +88,7 @@
             self.assertEqual(True, domain['enabled'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('f2f5b44a-82e8-4dad-8084-0661ea3b18cf')
+    @decorators.idempotent_id('f2f5b44a-82e8-4dad-8084-0661ea3b18cf')
     def test_create_update_delete_domain(self):
         # Create domain
         d_name = data_utils.rand_name('domain')
@@ -132,7 +133,7 @@
         domains_list = [d['id'] for d in body]
         self.assertNotIn(domain['id'], domains_list)
 
-    @test.idempotent_id('036df86e-bb5d-42c0-a7c2-66b9db3a6046')
+    @decorators.idempotent_id('036df86e-bb5d-42c0-a7c2-66b9db3a6046')
     def test_create_domain_with_disabled_status(self):
         # Create domain with enabled status as false
         d_name = data_utils.rand_name('domain')
@@ -144,7 +145,7 @@
         self.assertFalse(domain['enabled'])
         self.assertEqual(d_desc, domain['description'])
 
-    @test.idempotent_id('2abf8764-309a-4fa9-bc58-201b799817ad')
+    @decorators.idempotent_id('2abf8764-309a-4fa9-bc58-201b799817ad')
     def test_create_domain_without_description(self):
         # Create domain only with name
         d_name = data_utils.rand_name('domain')
@@ -168,7 +169,7 @@
         super(DefaultDomainTestJSON, cls).resource_setup()
 
     @test.attr(type='smoke')
-    @test.idempotent_id('17a5de24-e6a0-4e4a-a9ee-d85b6e5612b5')
+    @decorators.idempotent_id('17a5de24-e6a0-4e4a-a9ee-d85b6e5612b5')
     def test_default_domain_exists(self):
         domain = self.domains_client.show_domain(self.domain_id)['domain']
 
diff --git a/tempest/api/identity/admin/v3/test_domains_negative.py b/tempest/api/identity/admin/v3/test_domains_negative.py
index 100a121..4555a6a 100644
--- a/tempest/api/identity/admin/v3/test_domains_negative.py
+++ b/tempest/api/identity/admin/v3/test_domains_negative.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.lib.common.utils import data_utils
+from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -23,7 +24,7 @@
     _interface = 'json'
 
     @test.attr(type=['negative', 'gate'])
-    @test.idempotent_id('1f3fbff5-4e44-400d-9ca1-d953f05f609b')
+    @decorators.idempotent_id('1f3fbff5-4e44-400d-9ca1-d953f05f609b')
     def test_delete_active_domain(self):
         d_name = data_utils.rand_name('domain')
         d_desc = data_utils.rand_name('domain-desc')
@@ -39,14 +40,14 @@
                           domain_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9018461d-7d24-408d-b3fe-ae37e8cd5c9e')
+    @decorators.idempotent_id('9018461d-7d24-408d-b3fe-ae37e8cd5c9e')
     def test_create_domain_with_empty_name(self):
         # Domain name should not be empty
         self.assertRaises(lib_exc.BadRequest,
                           self.domains_client.create_domain, name='')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('37b1bbf2-d664-4785-9a11-333438586eae')
+    @decorators.idempotent_id('37b1bbf2-d664-4785-9a11-333438586eae')
     def test_create_domain_with_name_length_over_64(self):
         # Domain name length should not ne greater than 64 characters
         d_name = 'a' * 65
@@ -55,14 +56,14 @@
                           name=d_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('43781c07-764f-4cf2-a405-953c1916f605')
+    @decorators.idempotent_id('43781c07-764f-4cf2-a405-953c1916f605')
     def test_delete_non_existent_domain(self):
         # Attempt to delete a non existent domain should fail
         self.assertRaises(lib_exc.NotFound, self.domains_client.delete_domain,
                           data_utils.rand_uuid_hex())
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e6f9e4a2-4f36-4be8-bdbc-4e199ae29427')
+    @decorators.idempotent_id('e6f9e4a2-4f36-4be8-bdbc-4e199ae29427')
     def test_domain_create_duplicate(self):
         domain_name = data_utils.rand_name('domain-dup')
         domain = self.domains_client.create_domain(name=domain_name)['domain']
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index ef450a2..686743b 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -15,6 +15,7 @@
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -58,7 +59,7 @@
             cls.services_client.delete_service(s)
         super(EndPointsTestJSON, cls).resource_cleanup()
 
-    @test.idempotent_id('c19ecf90-240e-4e23-9966-21cee3f6a618')
+    @decorators.idempotent_id('c19ecf90-240e-4e23-9966-21cee3f6a618')
     def test_list_endpoints(self):
         # Get a list of endpoints
         fetched_endpoints = self.client.list_endpoints()['endpoints']
@@ -69,7 +70,7 @@
                          "Failed to find endpoint %s in fetched list" %
                          ', '.join(str(e) for e in missing_endpoints))
 
-    @test.idempotent_id('0e2446d2-c1fd-461b-a729-b9e73e3e3b37')
+    @decorators.idempotent_id('0e2446d2-c1fd-461b-a729-b9e73e3e3b37')
     def test_create_list_show_delete_endpoint(self):
         region = data_utils.rand_name('region')
         url = data_utils.rand_url()
@@ -110,7 +111,7 @@
         self.assertNotIn(endpoint['id'], fetched_endpoints_id)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('37e8f15e-ee7c-4657-a1e7-f6b61e375eff')
+    @decorators.idempotent_id('37e8f15e-ee7c-4657-a1e7-f6b61e375eff')
     def test_update_endpoint(self):
         # Creating an endpoint so as to check update endpoint
         # with new values
diff --git a/tempest/api/identity/admin/v3/test_endpoints_negative.py b/tempest/api/identity/admin/v3/test_endpoints_negative.py
index f0f8707..53c2b1f 100644
--- a/tempest/api/identity/admin/v3/test_endpoints_negative.py
+++ b/tempest/api/identity/admin/v3/test_endpoints_negative.py
@@ -16,6 +16,7 @@
 
 from tempest.api.identity 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
 
@@ -48,7 +49,7 @@
         super(EndpointsNegativeTestJSON, cls).resource_cleanup()
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ac6c137e-4d3d-448f-8c83-4f13d0942651')
+    @decorators.idempotent_id('ac6c137e-4d3d-448f-8c83-4f13d0942651')
     def test_create_with_enabled_False(self):
         # Enabled should be a boolean, not a string like 'False'
         interface = 'public'
@@ -59,7 +60,7 @@
                           url=url, region=region, enabled='False')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9c43181e-0627-484a-8c79-923e8a59598b')
+    @decorators.idempotent_id('9c43181e-0627-484a-8c79-923e8a59598b')
     def test_create_with_enabled_True(self):
         # Enabled should be a boolean, not a string like 'True'
         interface = 'public'
@@ -86,13 +87,13 @@
                           endpoint_for_update['id'], enabled=enabled)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('65e41f32-5eb7-498f-a92a-a6ccacf7439a')
+    @decorators.idempotent_id('65e41f32-5eb7-498f-a92a-a6ccacf7439a')
     def test_update_with_enabled_False(self):
         # Enabled should be a boolean, not a string like 'False'
         self._assert_update_raises_bad_request('False')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('faba3587-f066-4757-a48e-b4a3f01803bb')
+    @decorators.idempotent_id('faba3587-f066-4757-a48e-b4a3f01803bb')
     def test_update_with_enabled_True(self):
         # Enabled should be a boolean, not a string like 'True'
         self._assert_update_raises_bad_request('True')
diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py
index 34b4468..5ce0709 100644
--- a/tempest/api/identity/admin/v3/test_groups.py
+++ b/tempest/api/identity/admin/v3/test_groups.py
@@ -15,6 +15,7 @@
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -32,7 +33,7 @@
         cls.domains_client.delete_domain(cls.domain['id'])
         super(GroupsV3TestJSON, cls).resource_cleanup()
 
-    @test.idempotent_id('2e80343b-6c81-4ac3-88c7-452f3e9d5129')
+    @decorators.idempotent_id('2e80343b-6c81-4ac3-88c7-452f3e9d5129')
     def test_group_create_update_get(self):
         name = data_utils.rand_name('Group')
         description = data_utils.rand_name('Description')
@@ -55,7 +56,7 @@
         self.assertEqual(new_name, new_group['name'])
         self.assertEqual(new_desc, new_group['description'])
 
-    @test.idempotent_id('b66eb441-b08a-4a6d-81ab-fef71baeb26c')
+    @decorators.idempotent_id('b66eb441-b08a-4a6d-81ab-fef71baeb26c')
     def test_group_update_with_few_fields(self):
         name = data_utils.rand_name('Group')
         old_description = data_utils.rand_name('Description')
@@ -72,7 +73,7 @@
         self.assertEqual(old_description, updated_group['description'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('1598521a-2f36-4606-8df9-30772bd51339')
+    @decorators.idempotent_id('1598521a-2f36-4606-8df9-30772bd51339')
     def test_group_users_add_list_delete(self):
         name = data_utils.rand_name('Group')
         group = self.groups_client.create_group(
@@ -101,7 +102,7 @@
         group_users = self.groups_client.list_group_users(group['id'])['users']
         self.assertEqual(len(group_users), 0)
 
-    @test.idempotent_id('64573281-d26a-4a52-b899-503cb0f4e4ec')
+    @decorators.idempotent_id('64573281-d26a-4a52-b899-503cb0f4e4ec')
     def test_list_user_groups(self):
         # create a user
         user = self.users_client.create_user(
@@ -123,7 +124,7 @@
                          sorted(user_groups, key=lambda k: k['name']))
         self.assertEqual(2, len(user_groups))
 
-    @test.idempotent_id('cc9a57a5-a9ed-4f2d-a29f-4f979a06ec71')
+    @decorators.idempotent_id('cc9a57a5-a9ed-4f2d-a29f-4f979a06ec71')
     def test_list_groups(self):
         # Test to list groups
         group_ids = list()
diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py
index 33fce8d..8523396 100644
--- a/tempest/api/identity/admin/v3/test_inherits.py
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -12,6 +12,7 @@
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -61,7 +62,7 @@
 
 class InheritsV3TestJSON(BaseInheritsV3Test):
 
-    @test.idempotent_id('4e6f0366-97c8-423c-b2be-41eae6ac91c8')
+    @decorators.idempotent_id('4e6f0366-97c8-423c-b2be-41eae6ac91c8')
     def test_inherit_assign_list_check_revoke_roles_on_domains_user(self):
         # Create role
         src_role = self.roles_client.create_role(
@@ -87,7 +88,7 @@
         self.inherited_roles_client.delete_inherited_role_from_user_on_domain(
             self.domain['id'], self.user['id'], src_role['id'])
 
-    @test.idempotent_id('c7a8dda2-be50-4fb4-9a9c-e830771078b1')
+    @decorators.idempotent_id('c7a8dda2-be50-4fb4-9a9c-e830771078b1')
     def test_inherit_assign_list_check_revoke_roles_on_domains_group(self):
         # Create role
         src_role = self.roles_client.create_role(
@@ -113,7 +114,7 @@
         self.inherited_roles_client.delete_inherited_role_from_group_on_domain(
             self.domain['id'], self.group['id'], src_role['id'])
 
-    @test.idempotent_id('18b70e45-7687-4b72-8277-b8f1a47d7591')
+    @decorators.idempotent_id('18b70e45-7687-4b72-8277-b8f1a47d7591')
     def test_inherit_assign_check_revoke_roles_on_projects_user(self):
         # Create role
         src_role = self.roles_client.create_role(
@@ -130,7 +131,7 @@
         self.inherited_roles_client.delete_inherited_role_from_user_on_project(
             self.project['id'], self.user['id'], src_role['id'])
 
-    @test.idempotent_id('26021436-d5a4-4256-943c-ded01e0d4b45')
+    @decorators.idempotent_id('26021436-d5a4-4256-943c-ded01e0d4b45')
     def test_inherit_assign_check_revoke_roles_on_projects_group(self):
         # Create role
         src_role = self.roles_client.create_role(
@@ -148,7 +149,7 @@
          delete_inherited_role_from_group_on_project(
              self.project['id'], self.group['id'], src_role['id']))
 
-    @test.idempotent_id('3acf666e-5354-42ac-8e17-8b68893bcd36')
+    @decorators.idempotent_id('3acf666e-5354-42ac-8e17-8b68893bcd36')
     def test_inherit_assign_list_revoke_user_roles_on_domain(self):
         # Create role
         src_role = self.roles_client.create_role(
@@ -198,7 +199,7 @@
             effective=True, **params)['role_assignments']
         self.assertEmpty(assignments)
 
-    @test.idempotent_id('9f02ccd9-9b57-46b4-8f77-dd5a736f3a06')
+    @decorators.idempotent_id('9f02ccd9-9b57-46b4-8f77-dd5a736f3a06')
     def test_inherit_assign_list_revoke_user_roles_on_project_tree(self):
         # Create role
         src_role = self.roles_client.create_role(
diff --git a/tempest/api/identity/admin/v3/test_list_projects.py b/tempest/api/identity/admin/v3/test_list_projects.py
index 7d9e41b..2d046bb 100644
--- a/tempest/api/identity/admin/v3/test_list_projects.py
+++ b/tempest/api/identity/admin/v3/test_list_projects.py
@@ -15,7 +15,7 @@
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class ListProjectsTestJSON(base.BaseIdentityV3AdminTest):
@@ -56,7 +56,7 @@
         cls.domains_client.delete_domain(cls.domain['id'])
         super(ListProjectsTestJSON, cls).resource_cleanup()
 
-    @test.idempotent_id('1d830662-22ad-427c-8c3e-4ec854b0af44')
+    @decorators.idempotent_id('1d830662-22ad-427c-8c3e-4ec854b0af44')
     def test_list_projects(self):
         # List projects
         list_projects = self.projects_client.list_projects()['projects']
@@ -65,23 +65,23 @@
             show_project = self.projects_client.show_project(p)['project']
             self.assertIn(show_project, list_projects)
 
-    @test.idempotent_id('fab13f3c-f6a6-4b9f-829b-d32fd44fdf10')
+    @decorators.idempotent_id('fab13f3c-f6a6-4b9f-829b-d32fd44fdf10')
     def test_list_projects_with_domains(self):
         # List projects with domain
         self._list_projects_with_params(
             {'domain_id': self.domain['id']}, 'domain_id')
 
-    @test.idempotent_id('0fe7a334-675a-4509-b00e-1c4b95d5dae8')
+    @decorators.idempotent_id('0fe7a334-675a-4509-b00e-1c4b95d5dae8')
     def test_list_projects_with_enabled(self):
         # List the projects with enabled
         self._list_projects_with_params({'enabled': False}, 'enabled')
 
-    @test.idempotent_id('fa178524-4e6d-4925-907c-7ab9f42c7e26')
+    @decorators.idempotent_id('fa178524-4e6d-4925-907c-7ab9f42c7e26')
     def test_list_projects_with_name(self):
         # List projects with name
         self._list_projects_with_params({'name': self.p1_name}, 'name')
 
-    @test.idempotent_id('6edc66f5-2941-4a17-9526-4073311c1fac')
+    @decorators.idempotent_id('6edc66f5-2941-4a17-9526-4073311c1fac')
     def test_list_projects_with_parent(self):
         # List projects with parent
         params = {'parent_id': self.p3['parent_id']}
diff --git a/tempest/api/identity/admin/v3/test_list_users.py b/tempest/api/identity/admin/v3/test_list_users.py
index 99df559..0a0d65a 100644
--- a/tempest/api/identity/admin/v3/test_list_users.py
+++ b/tempest/api/identity/admin/v3/test_list_users.py
@@ -15,7 +15,7 @@
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class UsersV3TestJSON(base.BaseIdentityV3AdminTest):
@@ -62,7 +62,7 @@
         cls.domains_client.delete_domain(cls.domain['id'])
         super(UsersV3TestJSON, cls).resource_cleanup()
 
-    @test.idempotent_id('08f9aabb-dcfe-41d0-8172-82b5fa0bd73d')
+    @decorators.idempotent_id('08f9aabb-dcfe-41d0-8172-82b5fa0bd73d')
     def test_list_user_domains(self):
         # List users with domain
         params = {'domain_id': self.domain['id']}
@@ -70,7 +70,7 @@
                                      self.domain_enabled_user,
                                      self.non_domain_enabled_user)
 
-    @test.idempotent_id('bff8bf2f-9408-4ef5-b63a-753c8c2124eb')
+    @decorators.idempotent_id('bff8bf2f-9408-4ef5-b63a-753c8c2124eb')
     def test_list_users_with_not_enabled(self):
         # List the users with not enabled
         params = {'enabled': False}
@@ -78,7 +78,7 @@
                                      self.non_domain_enabled_user,
                                      self.domain_enabled_user)
 
-    @test.idempotent_id('c285bb37-7325-4c02-bff3-3da5d946d683')
+    @decorators.idempotent_id('c285bb37-7325-4c02-bff3-3da5d946d683')
     def test_list_users_with_name(self):
         # List users with name
         params = {'name': self.domain_enabled_user['name']}
@@ -86,7 +86,7 @@
                                      self.domain_enabled_user,
                                      self.non_domain_enabled_user)
 
-    @test.idempotent_id('b30d4651-a2ea-4666-8551-0c0e49692635')
+    @decorators.idempotent_id('b30d4651-a2ea-4666-8551-0c0e49692635')
     def test_list_users(self):
         # List users
         body = self.users_client.list_users()['users']
@@ -97,7 +97,7 @@
                          "Failed to find user %s in fetched list" %
                          ', '.join(m_user for m_user in missing_users))
 
-    @test.idempotent_id('b4baa3ae-ac00-4b4e-9e27-80deaad7771f')
+    @decorators.idempotent_id('b4baa3ae-ac00-4b4e-9e27-80deaad7771f')
     def test_get_user(self):
         # Get a user detail
         user = self.users_client.show_user(self.users[0]['id'])['user']
diff --git a/tempest/api/identity/admin/v3/test_policies.py b/tempest/api/identity/admin/v3/test_policies.py
index 3b5e5d4..eb1c69e 100644
--- a/tempest/api/identity/admin/v3/test_policies.py
+++ b/tempest/api/identity/admin/v3/test_policies.py
@@ -15,6 +15,7 @@
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -23,7 +24,7 @@
     def _delete_policy(self, policy_id):
         self.policies_client.delete_policy(policy_id)
 
-    @test.idempotent_id('1a0ad286-2d06-4123-ab0d-728893a76201')
+    @decorators.idempotent_id('1a0ad286-2d06-4123-ab0d-728893a76201')
     def test_list_policies(self):
         # Test to list policies
         policy_ids = list()
@@ -44,7 +45,7 @@
         self.assertEqual(0, len(missing_pols))
 
     @test.attr(type='smoke')
-    @test.idempotent_id('e544703a-2f03-4cf2-9b0f-350782fdb0d3')
+    @decorators.idempotent_id('e544703a-2f03-4cf2-9b0f-350782fdb0d3')
     def test_create_update_delete_policy(self):
         # Test to update policy
         blob = data_utils.rand_name('BlobName')
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index 1137191..b37d33d 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -18,14 +18,14 @@
 from tempest.api.identity 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
 
 
 class ProjectsTestJSON(base.BaseIdentityV3AdminTest):
 
-    @test.idempotent_id('0ecf465c-0dc4-4532-ab53-91ffeb74d12d')
+    @decorators.idempotent_id('0ecf465c-0dc4-4532-ab53-91ffeb74d12d')
     def test_project_create_with_description(self):
         # Create project with a description
         project_name = data_utils.rand_name('project')
@@ -42,7 +42,7 @@
         self.assertEqual(desc2, project_desc, 'Description does not appear'
                          'to be set')
 
-    @test.idempotent_id('5f50fe07-8166-430b-a882-3b2ee0abe26f')
+    @decorators.idempotent_id('5f50fe07-8166-430b-a882-3b2ee0abe26f')
     def test_project_create_with_domain(self):
         # Create project with a domain
         domain = self.setup_test_domain()
@@ -59,7 +59,7 @@
 
     @testtools.skipUnless(CONF.identity_feature_enabled.reseller,
                           'Reseller not available.')
-    @test.idempotent_id('1854f9c0-70bc-4d11-a08a-1c789d339e3d')
+    @decorators.idempotent_id('1854f9c0-70bc-4d11-a08a-1c789d339e3d')
     def test_project_create_with_parent(self):
         # Create root project without providing a parent_id
         domain = self.setup_test_domain()
@@ -88,7 +88,31 @@
         self.assertEqual(project_name, project['name'])
         self.assertEqual(root_project_id, parent_id)
 
-    @test.idempotent_id('1f66dc76-50cc-4741-a200-af984509e480')
+    @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
         project_name = data_utils.rand_name('project')
@@ -102,7 +126,7 @@
         en2 = body['enabled']
         self.assertTrue(en2, 'Enable should be True in lookup')
 
-    @test.idempotent_id('78f96a9c-e0e0-4ee6-a3ba-fbf6dfd03207')
+    @decorators.idempotent_id('78f96a9c-e0e0-4ee6-a3ba-fbf6dfd03207')
     def test_project_create_not_enabled(self):
         # Create a project that is not enabled
         project_name = data_utils.rand_name('project')
@@ -117,7 +141,7 @@
         self.assertEqual('false', str(en2).lower(),
                          'Enable should be False in lookup')
 
-    @test.idempotent_id('f608f368-048c-496b-ad63-d286c26dab6b')
+    @decorators.idempotent_id('f608f368-048c-496b-ad63-d286c26dab6b')
     def test_project_update_name(self):
         # Update name attribute of a project
         p_name1 = data_utils.rand_name('project')
@@ -139,7 +163,7 @@
         self.assertEqual(p_name1, resp1_name)
         self.assertEqual(resp2_name, resp3_name)
 
-    @test.idempotent_id('f138b715-255e-4a7d-871d-351e1ef2e153')
+    @decorators.idempotent_id('f138b715-255e-4a7d-871d-351e1ef2e153')
     def test_project_update_desc(self):
         # Update description attribute of a project
         p_name = data_utils.rand_name('project')
@@ -162,7 +186,7 @@
         self.assertEqual(p_desc, resp1_desc)
         self.assertEqual(resp2_desc, resp3_desc)
 
-    @test.idempotent_id('b6b25683-c97f-474d-a595-55d410b68100')
+    @decorators.idempotent_id('b6b25683-c97f-474d-a595-55d410b68100')
     def test_project_update_enable(self):
         # Update the enabled attribute of a project
         p_name = data_utils.rand_name('project')
@@ -186,7 +210,7 @@
         self.assertEqual('false', str(resp1_en).lower())
         self.assertEqual(resp2_en, resp3_en)
 
-    @test.idempotent_id('59398d4a-5dc5-4f86-9a4c-c26cc804d6c6')
+    @decorators.idempotent_id('59398d4a-5dc5-4f86-9a4c-c26cc804d6c6')
     def test_associate_user_to_project(self):
         # Associate a user to a project
         # Create a Project
diff --git a/tempest/api/identity/admin/v3/test_projects_negative.py b/tempest/api/identity/admin/v3/test_projects_negative.py
index c76b9ee..87f8684 100644
--- a/tempest/api/identity/admin/v3/test_projects_negative.py
+++ b/tempest/api/identity/admin/v3/test_projects_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.identity 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
 
@@ -22,14 +23,14 @@
 class ProjectsNegativeTestJSON(base.BaseIdentityV3AdminTest):
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('24c49279-45dd-4155-887a-cb738c2385aa')
+    @decorators.idempotent_id('24c49279-45dd-4155-887a-cb738c2385aa')
     def test_list_projects_by_unauthorized_user(self):
         # Non-admin user should not be able to list projects
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_projects_client.list_projects)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('874c3e84-d174-4348-a16b-8c01f599561b')
+    @decorators.idempotent_id('874c3e84-d174-4348-a16b-8c01f599561b')
     def test_project_create_duplicate(self):
         # Project names should be unique
         project_name = data_utils.rand_name('project-dup')
@@ -40,7 +41,7 @@
                           self.projects_client.create_project, project_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('8fba9de2-3e1f-4e77-812a-60cb68f8df13')
+    @decorators.idempotent_id('8fba9de2-3e1f-4e77-812a-60cb68f8df13')
     def test_create_project_by_unauthorized_user(self):
         # Non-admin user should not be authorized to create a project
         project_name = data_utils.rand_name('project')
@@ -49,14 +50,14 @@
             project_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7828db17-95e5-475b-9432-9a51b4aa79a9')
+    @decorators.idempotent_id('7828db17-95e5-475b-9432-9a51b4aa79a9')
     def test_create_project_with_empty_name(self):
         # Project name should not be empty
         self.assertRaises(lib_exc.BadRequest,
                           self.projects_client.create_project, name='')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('502b6ceb-b0c8-4422-bf53-f08fdb21e2f0')
+    @decorators.idempotent_id('502b6ceb-b0c8-4422-bf53-f08fdb21e2f0')
     def test_create_projects_name_length_over_64(self):
         # Project name length should not be greater than 64 characters
         project_name = 'a' * 65
@@ -64,7 +65,7 @@
                           self.projects_client.create_project, project_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('8d68c012-89e0-4394-8d6b-ccd7196def97')
+    @decorators.idempotent_id('8d68c012-89e0-4394-8d6b-ccd7196def97')
     def test_project_delete_by_unauthorized_user(self):
         # Non-admin user should not be able to delete a project
         project_name = data_utils.rand_name('project')
@@ -75,7 +76,7 @@
             project['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7965b581-60c1-43b7-8169-95d4ab7fc6fb')
+    @decorators.idempotent_id('7965b581-60c1-43b7-8169-95d4ab7fc6fb')
     def test_delete_non_existent_project(self):
         # Attempt to delete a non existent project should fail
         self.assertRaises(lib_exc.NotFound,
diff --git a/tempest/api/identity/admin/v3/test_regions.py b/tempest/api/identity/admin/v3/test_regions.py
index b5ea90d..f57a07c 100644
--- a/tempest/api/identity/admin/v3/test_regions.py
+++ b/tempest/api/identity/admin/v3/test_regions.py
@@ -16,6 +16,7 @@
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -42,7 +43,7 @@
             cls.client.delete_region(r['id'])
         super(RegionsTestJSON, cls).resource_cleanup()
 
-    @test.idempotent_id('56186092-82e4-43f2-b954-91013218ba42')
+    @decorators.idempotent_id('56186092-82e4-43f2-b954-91013218ba42')
     def test_create_update_get_delete_region(self):
         # Create region
         r_description = data_utils.rand_name('description')
@@ -79,7 +80,7 @@
         self.assertNotIn(region['id'], regions_list)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('2c12c5b5-efcf-4aa5-90c5-bff1ab0cdbe2')
+    @decorators.idempotent_id('2c12c5b5-efcf-4aa5-90c5-bff1ab0cdbe2')
     def test_create_region_with_specific_id(self):
         # Create a region with a specific id
         r_region_id = data_utils.rand_uuid()
@@ -91,7 +92,7 @@
         self.assertEqual(r_region_id, region['id'])
         self.assertEqual(r_description, region['description'])
 
-    @test.idempotent_id('d180bf99-544a-445c-ad0d-0c0d27663796')
+    @decorators.idempotent_id('d180bf99-544a-445c-ad0d-0c0d27663796')
     def test_list_regions(self):
         # Get a list of regions
         fetched_regions = self.client.list_regions()['regions']
@@ -102,7 +103,7 @@
                          "Failed to find region %s in fetched list" %
                          ', '.join(str(e) for e in missing_regions))
 
-    @test.idempotent_id('2d1057cb-bbde-413a-acdf-e2d265284542')
+    @decorators.idempotent_id('2d1057cb-bbde-413a-acdf-e2d265284542')
     def test_list_regions_filter_by_parent_region_id(self):
         # Add a sub-region to one of the existing test regions
         r_description = data_utils.rand_name('description')
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index 670cb2f..445d928 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -15,6 +15,9 @@
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
@@ -69,7 +72,7 @@
         self.assertIn(role_id, fetched_role_ids)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('18afc6c0-46cf-4911-824e-9989cc056c3a')
+    @decorators.idempotent_id('18afc6c0-46cf-4911-824e-9989cc056c3a')
     def test_role_create_update_show_list(self):
         r_name = data_utils.rand_name('Role')
         role = self.roles_client.create_role(name=r_name)['role']
@@ -92,7 +95,7 @@
         roles = self.roles_client.list_roles()['roles']
         self.assertIn(role['id'], [r['id'] for r in roles])
 
-    @test.idempotent_id('c6b80012-fe4a-498b-9ce8-eb391c05169f')
+    @decorators.idempotent_id('c6b80012-fe4a-498b-9ce8-eb391c05169f')
     def test_grant_list_revoke_role_to_user_on_project(self):
         self.roles_client.create_user_role_on_project(self.project['id'],
                                                       self.user_body['id'],
@@ -113,7 +116,7 @@
         self.roles_client.delete_role_from_user_on_project(
             self.project['id'], self.user_body['id'], self.role['id'])
 
-    @test.idempotent_id('6c9a2940-3625-43a3-ac02-5dcec62ef3bd')
+    @decorators.idempotent_id('6c9a2940-3625-43a3-ac02-5dcec62ef3bd')
     def test_grant_list_revoke_role_to_user_on_domain(self):
         self.roles_client.create_user_role_on_domain(
             self.domain['id'], self.user_body['id'], self.role['id'])
@@ -133,7 +136,7 @@
         self.roles_client.delete_role_from_user_on_domain(
             self.domain['id'], self.user_body['id'], self.role['id'])
 
-    @test.idempotent_id('cbf11737-1904-4690-9613-97bcbb3df1c4')
+    @decorators.idempotent_id('cbf11737-1904-4690-9613-97bcbb3df1c4')
     def test_grant_list_revoke_role_to_group_on_project(self):
         # Grant role to group on project
         self.roles_client.create_group_role_on_project(
@@ -168,7 +171,7 @@
         self.roles_client.delete_role_from_group_on_project(
             self.project['id'], self.group_body['id'], self.role['id'])
 
-    @test.idempotent_id('4bf8a70b-e785-413a-ad53-9f91ce02faa7')
+    @decorators.idempotent_id('4bf8a70b-e785-413a-ad53-9f91ce02faa7')
     def test_grant_list_revoke_role_to_group_on_domain(self):
         self.roles_client.create_group_role_on_domain(
             self.domain['id'], self.group_body['id'], self.role['id'])
@@ -188,9 +191,118 @@
         self.roles_client.delete_role_from_group_on_domain(
             self.domain['id'], self.group_body['id'], self.role['id'])
 
-    @test.idempotent_id('f5654bcc-08c4-4f71-88fe-05d64e06de94')
+    @decorators.idempotent_id('f5654bcc-08c4-4f71-88fe-05d64e06de94')
     def test_list_roles(self):
         # Return a list of all roles
         body = self.roles_client.list_roles()['roles']
         found = [role for role in body if role in self.roles]
         self.assertEqual(len(found), len(self.roles))
+
+    def _create_implied_role(self, prior_role_id, implies_role_id,
+                             ignore_not_found=False):
+        self.roles_client.create_role_inference_rule(
+            prior_role_id, implies_role_id)
+        if ignore_not_found:
+            self.addCleanup(
+                test_utils.call_and_ignore_notfound_exc,
+                self.roles_client.delete_role_inference_rule,
+                prior_role_id,
+                implies_role_id)
+        else:
+            self.addCleanup(
+                self.roles_client.delete_role_inference_rule,
+                prior_role_id,
+                implies_role_id)
+
+    @decorators.idempotent_id('c90c316c-d706-4728-bcba-eb1912081b69')
+    def test_implied_roles_create_delete(self):
+        prior_role_id = self.roles[0]['id']
+        implies_role_id = self.roles[1]['id']
+
+        # Create an inference rule from prior_role to implies_role
+        self._create_implied_role(prior_role_id, implies_role_id,
+                                  ignore_not_found=True)
+
+        # Check if the inference rule exists
+        self.roles_client.show_role_inference_rule(
+            prior_role_id, implies_role_id)
+
+        # Delete the inference rule
+        self.roles_client.delete_role_inference_rule(
+            prior_role_id, implies_role_id)
+        # Check if the inference rule no longer exists
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.roles_client.show_role_inference_rule,
+            prior_role_id,
+            implies_role_id)
+
+    @decorators.idempotent_id('dc6f5959-b74d-4e30-a9e5-a8255494ff00')
+    def test_roles_hierarchy(self):
+        # Create inference rule from "roles[0]" to "role[1]"
+        self._create_implied_role(
+            self.roles[0]['id'], self.roles[1]['id'])
+
+        # Create inference rule from "roles[0]" to "role[2]"
+        self._create_implied_role(
+            self.roles[0]['id'], self.roles[2]['id'])
+
+        # Create inference rule from "roles[2]" to "role"
+        self._create_implied_role(
+            self.roles[2]['id'], self.role['id'])
+
+        # Listing inferences rules from "roles[2]" should only return "role"
+        rules = self.roles_client.list_role_inferences_rules(
+            self.roles[2]['id'])['role_inference']
+        self.assertEqual(1, len(rules['implies']))
+        self.assertEqual(self.role['id'], rules['implies'][0]['id'])
+
+        # Listing inferences rules from "roles[0]" should return "roles[1]" and
+        # "roles[2]" (only direct rules are listed)
+        rules = self.roles_client.list_role_inferences_rules(
+            self.roles[0]['id'])['role_inference']
+        implies_ids = [role['id'] for role in rules['implies']]
+        self.assertEqual(2, len(implies_ids))
+        self.assertIn(self.roles[1]['id'], implies_ids)
+        self.assertIn(self.roles[2]['id'], implies_ids)
+
+    @decorators.idempotent_id('c8828027-df48-4021-95df-b65b92c7429e')
+    def test_assignments_for_implied_roles_create_delete(self):
+        # Create a grant using "roles[0]"
+        self.roles_client.create_user_role_on_project(
+            self.project['id'], self.user_body['id'], self.roles[0]['id'])
+        self.addCleanup(
+            self.roles_client.delete_role_from_user_on_project,
+            self.project['id'], self.user_body['id'], self.roles[0]['id'])
+
+        # Create an inference rule from "roles[0]" to "roles[1]"
+        self._create_implied_role(self.roles[0]['id'], self.roles[1]['id'],
+                                  ignore_not_found=True)
+
+        # In the effective list of role assignments, both prior role and
+        # implied role should be present. This means that a user can
+        # authenticate using both roles (both roles will be present
+        # in the token).
+        params = {'scope.project.id': self.project['id'],
+                  'user.id': self.user_body['id']}
+        role_assignments = self.role_assignments.list_role_assignments(
+            effective=True, **params)['role_assignments']
+        self.assertEqual(2, len(role_assignments))
+
+        roles_ids = [assignment['role']['id']
+                     for assignment in role_assignments]
+        self.assertIn(self.roles[0]['id'], roles_ids)
+        self.assertIn(self.roles[1]['id'], roles_ids)
+
+        # After deleting the implied role, only the assignment with "roles[0]"
+        # should be present.
+        self.roles_client.delete_role_inference_rule(
+            self.roles[0]['id'], self.roles[1]['id'])
+
+        role_assignments = self.role_assignments.list_role_assignments(
+            effective=True, **params)['role_assignments']
+        self.assertEqual(1, len(role_assignments))
+
+        roles_ids = [assignment['role']['id']
+                     for assignment in role_assignments]
+        self.assertIn(self.roles[0]['id'], roles_ids)
diff --git a/tempest/api/identity/admin/v3/test_services.py b/tempest/api/identity/admin/v3/test_services.py
index 2c3cae5..35e1814 100644
--- a/tempest/api/identity/admin/v3/test_services.py
+++ b/tempest/api/identity/admin/v3/test_services.py
@@ -15,6 +15,7 @@
 
 from tempest.api.identity 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
 
@@ -29,7 +30,7 @@
                           service_id)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('5193aad5-bcb7-411d-85b0-b3b61b96ef06')
+    @decorators.idempotent_id('5193aad5-bcb7-411d-85b0-b3b61b96ef06')
     def test_create_update_get_service(self):
         # Creating a Service
         name = data_utils.rand_name('service')
@@ -61,7 +62,7 @@
         self.assertEqual(resp2_desc, resp3_desc)
         self.assertDictContainsSubset(update_service, fetched_service)
 
-    @test.idempotent_id('d1dcb1a1-2b6b-4da8-bbb8-5532ef6e8269')
+    @decorators.idempotent_id('d1dcb1a1-2b6b-4da8-bbb8-5532ef6e8269')
     def test_create_service_without_description(self):
         # Create a service only with name and type
         name = data_utils.rand_name('service')
@@ -73,7 +74,7 @@
         expected_data = {'name': name, 'type': serv_type}
         self.assertDictContainsSubset(expected_data, service)
 
-    @test.idempotent_id('e55908e8-360e-439e-8719-c3230a3e179e')
+    @decorators.idempotent_id('e55908e8-360e-439e-8719-c3230a3e179e')
     def test_list_services(self):
         # Create, List, Verify and Delete Services
         service_ids = list()
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index 8706cf7..a9508d1 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -17,13 +17,13 @@
 
 from tempest.api.identity 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 TokensV3TestJSON(base.BaseIdentityV3AdminTest):
 
-    @test.idempotent_id('0f9f5a5f-d5cd-4a86-8a5b-c5ded151f212')
+    @decorators.idempotent_id('0f9f5a5f-d5cd-4a86-8a5b-c5ded151f212')
     def test_tokens(self):
         # Valid user's token is authenticated
         # Create a User
@@ -49,7 +49,7 @@
         self.assertRaises(lib_exc.NotFound, self.client.show_token,
                           subject_token)
 
-    @test.idempotent_id('565fa210-1da1-4563-999b-f7b5b67cf112')
+    @decorators.idempotent_id('565fa210-1da1-4563-999b-f7b5b67cf112')
     def test_rescope_token(self):
         """Rescope a token.
 
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index 4e69de8..1a466a0 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -20,6 +20,7 @@
 from tempest.common import credentials_factory as common_creds
 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
 
@@ -197,7 +198,7 @@
         self.create_trustor_and_roles()
         self.addCleanup(self.cleanup_user_and_roles)
 
-    @test.idempotent_id('5a0a91a4-baef-4a14-baba-59bf4d7fcace')
+    @decorators.idempotent_id('5a0a91a4-baef-4a14-baba-59bf4d7fcace')
     def test_trust_impersonate(self):
         # Test case to check we can create, get and delete a trust
         # updates are not supported for trusts
@@ -209,7 +210,7 @@
 
         self.check_trust_roles()
 
-    @test.idempotent_id('ed2a8779-a7ac-49dc-afd7-30f32f936ed2')
+    @decorators.idempotent_id('ed2a8779-a7ac-49dc-afd7-30f32f936ed2')
     def test_trust_noimpersonate(self):
         # Test case to check we can create, get and delete a trust
         # with impersonation=False
@@ -221,7 +222,7 @@
 
         self.check_trust_roles()
 
-    @test.idempotent_id('0ed14b66-cefd-4b5c-a964-65759453e292')
+    @decorators.idempotent_id('0ed14b66-cefd-4b5c-a964-65759453e292')
     def test_trust_expire(self):
         # Test case to check we can create, get and delete a trust
         # with an expiry specified
@@ -246,7 +247,7 @@
 
         self.check_trust_roles()
 
-    @test.idempotent_id('3e48f95d-e660-4fa9-85e0-5a3d85594384')
+    @decorators.idempotent_id('3e48f95d-e660-4fa9-85e0-5a3d85594384')
     def test_trust_expire_invalid(self):
         # Test case to check we can check an invalid expiry time
         # is rejected with the correct error
@@ -256,7 +257,7 @@
                           self.create_trust,
                           expires=expires_str)
 
-    @test.idempotent_id('6268b345-87ca-47c0-9ce3-37792b43403a')
+    @decorators.idempotent_id('6268b345-87ca-47c0-9ce3-37792b43403a')
     def test_get_trusts_query(self):
         self.create_trust()
         trusts_get = self.trustor_client.list_trusts(
@@ -265,7 +266,7 @@
         self.validate_trust(trusts_get[0], summary=True)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('4773ebd5-ecbf-4255-b8d8-b63e6f72b65d')
+    @decorators.idempotent_id('4773ebd5-ecbf-4255-b8d8-b63e6f72b65d')
     def test_get_trusts_all(self):
 
         # Simple function that can be used for cleanup
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index 54c62c7..e0ec883 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -20,7 +20,7 @@
 from tempest.api.identity 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
@@ -28,7 +28,7 @@
 
 class UsersV3TestJSON(base.BaseIdentityV3AdminTest):
 
-    @test.idempotent_id('b537d090-afb9-4519-b95d-270b0708e87e')
+    @decorators.idempotent_id('b537d090-afb9-4519-b95d-270b0708e87e')
     def test_user_update(self):
         # Test case to check if updating of user attributes is successful.
         # Creating first user
@@ -71,7 +71,7 @@
         self.assertEqual(u_email2, new_user_get['email'])
         self.assertEqual(False, new_user_get['enabled'])
 
-    @test.idempotent_id('2d223a0e-e457-4a70-9fb1-febe027a0ff9')
+    @decorators.idempotent_id('2d223a0e-e457-4a70-9fb1-febe027a0ff9')
     def test_update_user_password(self):
         # Creating User to check password updation
         u_name = data_utils.rand_name('user')
@@ -97,7 +97,7 @@
         self.assertEqual(token_details['user']['id'], user['id'])
         self.assertEqual(token_details['user']['name'], u_name)
 
-    @test.idempotent_id('a831e70c-e35b-430b-92ed-81ebbc5437b8')
+    @decorators.idempotent_id('a831e70c-e35b-430b-92ed-81ebbc5437b8')
     def test_list_user_projects(self):
         # List the projects that a user has access upon
         assigned_project_ids = list()
@@ -152,7 +152,7 @@
                          ', '.join(m_project for m_project
                                    in missing_projects))
 
-    @test.idempotent_id('c10dcd90-461d-4b16-8e23-4eb836c00644')
+    @decorators.idempotent_id('c10dcd90-461d-4b16-8e23-4eb836c00644')
     def test_get_user(self):
         # Get a user detail
         user = self.setup_test_user()
@@ -161,7 +161,7 @@
 
     @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
                           'Security compliance not available.')
-    @test.idempotent_id('568cd46c-ee6c-4ab4-a33a-d3791931979e')
+    @decorators.idempotent_id('568cd46c-ee6c-4ab4-a33a-d3791931979e')
     def test_password_history_not_enforced_in_admin_reset(self):
         old_password = self.os.credentials.password
         user_id = self.os.credentials.user_id
diff --git a/tempest/api/identity/admin/v3/test_users_negative.py b/tempest/api/identity/admin/v3/test_users_negative.py
index 5b0fc97..9626108 100644
--- a/tempest/api/identity/admin/v3/test_users_negative.py
+++ b/tempest/api/identity/admin/v3/test_users_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.identity 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
 
@@ -22,7 +23,7 @@
 class UsersNegativeTest(base.BaseIdentityV3AdminTest):
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e75f006c-89cc-477b-874d-588e4eab4b17')
+    @decorators.idempotent_id('e75f006c-89cc-477b-874d-588e4eab4b17')
     def test_create_user_for_non_existent_domain(self):
         # Attempt to create a user in a non-existent domain should fail
         u_name = data_utils.rand_name('user')
@@ -34,7 +35,7 @@
                           domain_id=data_utils.rand_uuid_hex())
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('b3c9fccc-4134-46f5-b600-1da6fb0a3b1f')
+    @decorators.idempotent_id('b3c9fccc-4134-46f5-b600-1da6fb0a3b1f')
     def test_authentication_for_disabled_user(self):
         # Attempt to authenticate for disabled user should fail
         password = data_utils.rand_password()
diff --git a/tempest/api/identity/test_extension.py b/tempest/api/identity/test_extension.py
index 01e5661..7095181 100644
--- a/tempest/api/identity/test_extension.py
+++ b/tempest/api/identity/test_extension.py
@@ -14,12 +14,12 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class ExtensionTestJSON(base.BaseIdentityV2AdminTest):
 
-    @test.idempotent_id('85f3f661-f54c-4d48-b563-72ae952b9383')
+    @decorators.idempotent_id('85f3f661-f54c-4d48-b563-72ae952b9383')
     def test_list_extensions(self):
         # List all the extensions
         body = self.non_admin_client.list_extensions()['extensions']['values']
diff --git a/tempest/api/identity/v2/test_api_discovery.py b/tempest/api/identity/v2/test_api_discovery.py
index ca807a4..02caef5 100644
--- a/tempest/api/identity/v2/test_api_discovery.py
+++ b/tempest/api/identity/v2/test_api_discovery.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest.api.identity import base
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -21,7 +22,7 @@
     """Tests for API discovery features."""
 
     @test.attr(type='smoke')
-    @test.idempotent_id('ea889a68-a15f-4166-bfb1-c12456eae853')
+    @decorators.idempotent_id('ea889a68-a15f-4166-bfb1-c12456eae853')
     def test_api_version_resources(self):
         descr = self.non_admin_client.show_api_description()['version']
         expected_resources = ('id', 'links', 'media-types', 'status',
@@ -32,7 +33,7 @@
             self.assertIn(res, keys)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('007a0be0-78fe-4fdb-bbee-e9216cc17bb2')
+    @decorators.idempotent_id('007a0be0-78fe-4fdb-bbee-e9216cc17bb2')
     def test_api_media_types(self):
         descr = self.non_admin_client.show_api_description()['version']
         # Get MIME type bases and descriptions
@@ -47,7 +48,7 @@
             self.assertIn(s_type, media_types)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('77fd6be0-8801-48e6-b9bf-38cdd2f253ec')
+    @decorators.idempotent_id('77fd6be0-8801-48e6-b9bf-38cdd2f253ec')
     def test_api_version_statuses(self):
         descr = self.non_admin_client.show_api_description()['version']
         status = descr['status'].lower()
diff --git a/tempest/api/identity/v2/test_ec2_credentials.py b/tempest/api/identity/v2/test_ec2_credentials.py
index 8f493aa..7a0f3d7 100644
--- a/tempest/api/identity/v2/test_ec2_credentials.py
+++ b/tempest/api/identity/v2/test_ec2_credentials.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest.api.identity import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -32,7 +33,7 @@
         super(EC2CredentialsTest, cls).resource_setup()
         cls.creds = cls.os.credentials
 
-    @test.idempotent_id('b580fab9-7ae9-46e8-8138-417260cb6f9f')
+    @decorators.idempotent_id('b580fab9-7ae9-46e8-8138-417260cb6f9f')
     def test_create_ec2_credential(self):
         """Create user ec2 credential."""
         resp = self.non_admin_users_client.create_user_ec2_credential(
@@ -47,7 +48,7 @@
         self.assertEqual(self.creds.user_id, resp['user_id'])
         self.assertEqual(self.creds.tenant_id, resp['tenant_id'])
 
-    @test.idempotent_id('9e2ea42f-0a4f-468c-a768-51859ce492e0')
+    @decorators.idempotent_id('9e2ea42f-0a4f-468c-a768-51859ce492e0')
     def test_list_ec2_credentials(self):
         """Get the list of user ec2 credentials."""
         created_creds = []
@@ -79,7 +80,7 @@
                          "Failed to find ec2_credentials %s in fetched list" %
                          ', '.join(cred for cred in missing))
 
-    @test.idempotent_id('cb284075-b613-440d-83ca-fe0b33b3c2b8')
+    @decorators.idempotent_id('cb284075-b613-440d-83ca-fe0b33b3c2b8')
     def test_show_ec2_credential(self):
         """Get the definite user ec2 credential."""
         resp = self.non_admin_users_client.create_user_ec2_credential(
@@ -95,7 +96,7 @@
         for key in ['access', 'secret', 'user_id', 'tenant_id']:
             self.assertEqual(ec2_creds[key], resp[key])
 
-    @test.idempotent_id('6aba0d4c-b76b-4e46-aa42-add79bc1551d')
+    @decorators.idempotent_id('6aba0d4c-b76b-4e46-aa42-add79bc1551d')
     def test_delete_ec2_credential(self):
         """Delete user ec2 credential."""
         resp = self.non_admin_users_client.create_user_ec2_credential(
diff --git a/tempest/api/identity/v2/test_tenants.py b/tempest/api/identity/v2/test_tenants.py
index cc6de47..2689998 100644
--- a/tempest/api/identity/v2/test_tenants.py
+++ b/tempest/api/identity/v2/test_tenants.py
@@ -14,15 +14,15 @@
 #    under the License.
 
 from tempest.api.identity import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 
 class IdentityTenantsTest(base.BaseIdentityV2Test):
 
     credentials = ['primary', 'alt']
 
-    @test.idempotent_id('ecae2459-243d-4ba1-ad02-65f15dc82b78')
+    @decorators.idempotent_id('ecae2459-243d-4ba1-ad02-65f15dc82b78')
     def test_list_tenants_returns_only_authorized_tenants(self):
         alt_tenant_name = self.alt_manager.credentials.tenant_name
         resp = self.non_admin_tenants_client.list_tenants()
diff --git a/tempest/api/identity/v2/test_tokens.py b/tempest/api/identity/v2/test_tokens.py
index bdca1e0..79a1765 100644
--- a/tempest/api/identity/v2/test_tokens.py
+++ b/tempest/api/identity/v2/test_tokens.py
@@ -16,12 +16,12 @@
 from oslo_utils import timeutils
 import six
 from tempest.api.identity import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class TokensTest(base.BaseIdentityV2Test):
 
-    @test.idempotent_id('65ae3b78-91ff-467b-a705-f6678863b8ec')
+    @decorators.idempotent_id('65ae3b78-91ff-467b-a705-f6678863b8ec')
     def test_create_token(self):
 
         token_client = self.non_admin_token_client
diff --git a/tempest/api/identity/v2/test_users.py b/tempest/api/identity/v2/test_users.py
index 06730f8..2b42981 100644
--- a/tempest/api/identity/v2/test_users.py
+++ b/tempest/api/identity/v2/test_users.py
@@ -18,8 +18,8 @@
 from tempest.api.identity 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
 
 
 CONF = config.CONF
@@ -77,7 +77,7 @@
         time.sleep(1)
         self.non_admin_users_client.auth_provider.set_auth()
 
-    @test.idempotent_id('165859c9-277f-4124-9479-a7d1627b0ca7')
+    @decorators.idempotent_id('165859c9-277f-4124-9479-a7d1627b0ca7')
     def test_user_update_own_password(self):
         old_pass = self.creds.password
         old_token = self.non_admin_users_client.token
diff --git a/tempest/api/identity/v3/test_api_discovery.py b/tempest/api/identity/v3/test_api_discovery.py
index 74e9ec1..2eed3c8 100644
--- a/tempest/api/identity/v3/test_api_discovery.py
+++ b/tempest/api/identity/v3/test_api_discovery.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest.api.identity import base
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -21,7 +22,7 @@
     """Tests for API discovery features."""
 
     @test.attr(type='smoke')
-    @test.idempotent_id('b9232f5e-d9e5-4d97-b96c-28d3db4de1bd')
+    @decorators.idempotent_id('b9232f5e-d9e5-4d97-b96c-28d3db4de1bd')
     def test_api_version_resources(self):
         descr = self.non_admin_client.show_api_description()['version']
         expected_resources = ('id', 'links', 'media-types', 'status',
@@ -32,7 +33,7 @@
             self.assertIn(res, keys)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('657c1970-4722-4189-8831-7325f3bc4265')
+    @decorators.idempotent_id('657c1970-4722-4189-8831-7325f3bc4265')
     def test_api_media_types(self):
         descr = self.non_admin_client.show_api_description()['version']
         # Get MIME type bases and descriptions
@@ -47,7 +48,7 @@
             self.assertIn(s_type, media_types)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('8879a470-abfb-47bb-bb8d-5a7fd279ad1e')
+    @decorators.idempotent_id('8879a470-abfb-47bb-bb8d-5a7fd279ad1e')
     def test_api_version_statuses(self):
         descr = self.non_admin_client.show_api_description()['version']
         status = descr['status'].lower()
diff --git a/tempest/api/identity/v3/test_projects.py b/tempest/api/identity/v3/test_projects.py
index 26cb90b..570be99 100644
--- a/tempest/api/identity/v3/test_projects.py
+++ b/tempest/api/identity/v3/test_projects.py
@@ -14,15 +14,15 @@
 #    under the License.
 
 from tempest.api.identity import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 
 class IdentityV3ProjectsTest(base.BaseIdentityV3Test):
 
     credentials = ['primary', 'alt']
 
-    @test.idempotent_id('86128d46-e170-4644-866a-cc487f699e1d')
+    @decorators.idempotent_id('86128d46-e170-4644-866a-cc487f699e1d')
     def test_list_projects_returns_only_authorized_projects(self):
         alt_project_name =\
             self.alt_manager.credentials.project_name
diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py
index b410da6..1dc1df6 100644
--- a/tempest/api/identity/v3/test_tokens.py
+++ b/tempest/api/identity/v3/test_tokens.py
@@ -16,12 +16,12 @@
 from oslo_utils import timeutils
 import six
 from tempest.api.identity import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class TokensV3Test(base.BaseIdentityV3Test):
 
-    @test.idempotent_id('6f8e4436-fc96-4282-8122-e41df57197a9')
+    @decorators.idempotent_id('6f8e4436-fc96-4282-8122-e41df57197a9')
     def test_create_token(self):
 
         creds = self.os.credentials
diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py
index 9592cb9..f263258 100644
--- a/tempest/api/identity/v3/test_users.py
+++ b/tempest/api/identity/v3/test_users.py
@@ -20,8 +20,8 @@
 from tempest.api.identity 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
 
 
 CONF = config.CONF
@@ -78,7 +78,7 @@
         time.sleep(1)
         self.non_admin_users_client.auth_provider.set_auth()
 
-    @test.idempotent_id('ad71bd23-12ad-426b-bb8b-195d2b635f27')
+    @decorators.idempotent_id('ad71bd23-12ad-426b-bb8b-195d2b635f27')
     def test_user_update_own_password(self):
         old_pass = self.creds.password
         old_token = self.non_admin_client.token
@@ -103,7 +103,7 @@
 
     @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
                           'Security compliance not available.')
-    @test.idempotent_id('941784ee-5342-4571-959b-b80dd2cea516')
+    @decorators.idempotent_id('941784ee-5342-4571-959b-b80dd2cea516')
     def test_password_history_check_self_service_api(self):
         old_pass = self.creds.password
         new_pass1 = data_utils.rand_password()
@@ -133,7 +133,7 @@
 
     @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
                           'Security compliance not available.')
-    @test.idempotent_id('a7ad8bbf-2cff-4520-8c1d-96332e151658')
+    @decorators.idempotent_id('a7ad8bbf-2cff-4520-8c1d-96332e151658')
     def test_user_account_lockout(self):
         password = self.creds.password
 
diff --git a/tempest/api/image/admin/v2/test_images.py b/tempest/api/image/admin/v2/test_images.py
index f22f321..11b595a 100644
--- a/tempest/api/image/admin/v2/test_images.py
+++ b/tempest/api/image/admin/v2/test_images.py
@@ -17,10 +17,10 @@
 import testtools
 
 from tempest.api.image import base
+from tempest.common.utils import data_utils
 from tempest import config
-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
 
 CONF = config.CONF
 
@@ -30,7 +30,7 @@
 
     @testtools.skipUnless(CONF.image_feature_enabled.deactivate_image,
                           'deactivate-image is not available.')
-    @test.idempotent_id('951ebe01-969f-4ea9-9898-8a3f1f442ab0')
+    @decorators.idempotent_id('951ebe01-969f-4ea9-9898-8a3f1f442ab0')
     def test_admin_deactivate_reactivate_image(self):
         # Create image by non-admin tenant
         image_name = data_utils.rand_name('image')
diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py
index 9c211ef..4902316 100644
--- a/tempest/api/image/v1/test_image_members.py
+++ b/tempest/api/image/v1/test_image_members.py
@@ -14,13 +14,13 @@
 
 
 from tempest.api.image import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 
 class ImageMembersTest(base.BaseV1ImageMembersTest):
 
-    @test.idempotent_id('1d6ef640-3a20-4c84-8710-d95828fdb6ad')
+    @decorators.idempotent_id('1d6ef640-3a20-4c84-8710-d95828fdb6ad')
     def test_add_image_member(self):
         image = self._create_image()
         self.image_member_client.create_image_member(image, self.alt_tenant_id)
@@ -31,7 +31,7 @@
         # get image as alt user
         self.alt_img_cli.show_image(image)
 
-    @test.idempotent_id('6a5328a5-80e8-4b82-bd32-6c061f128da9')
+    @decorators.idempotent_id('6a5328a5-80e8-4b82-bd32-6c061f128da9')
     def test_get_shared_images(self):
         image = self._create_image()
         self.image_member_client.create_image_member(image, self.alt_tenant_id)
@@ -45,7 +45,7 @@
         self.assertIn(share_image, images)
         self.assertIn(image, images)
 
-    @test.idempotent_id('a76a3191-8948-4b44-a9d6-4053e5f2b138')
+    @decorators.idempotent_id('a76a3191-8948-4b44-a9d6-4053e5f2b138')
     def test_remove_member(self):
         image_id = self._create_image()
         self.image_member_client.create_image_member(image_id,
diff --git a/tempest/api/image/v1/test_image_members_negative.py b/tempest/api/image/v1/test_image_members_negative.py
index 2538781..d1aa801 100644
--- a/tempest/api/image/v1/test_image_members_negative.py
+++ b/tempest/api/image/v1/test_image_members_negative.py
@@ -14,6 +14,7 @@
 
 from tempest.api.image 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
 
@@ -21,7 +22,7 @@
 class ImageMembersNegativeTest(base.BaseV1ImageMembersTest):
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('147a9536-18e3-45da-91ea-b037a028f364')
+    @decorators.idempotent_id('147a9536-18e3-45da-91ea-b037a028f364')
     def test_add_member_with_non_existing_image(self):
         # Add member with non existing image.
         non_exist_image = data_utils.rand_uuid()
@@ -30,7 +31,7 @@
                           non_exist_image, self.alt_tenant_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e1559f05-b667-4f1b-a7af-518b52dc0c0f')
+    @decorators.idempotent_id('e1559f05-b667-4f1b-a7af-518b52dc0c0f')
     def test_delete_member_with_non_existing_image(self):
         # Delete member with non existing image.
         non_exist_image = data_utils.rand_uuid()
@@ -39,7 +40,7 @@
                           non_exist_image, self.alt_tenant_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f5720333-dd69-4194-bb76-d2f048addd56')
+    @decorators.idempotent_id('f5720333-dd69-4194-bb76-d2f048addd56')
     def test_delete_member_with_non_existing_tenant(self):
         # Delete member with non existing tenant.
         image_id = self._create_image()
@@ -49,7 +50,7 @@
                           image_id, non_exist_tenant)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f25f89e4-0b6c-453b-a853-1f80b9d7ef26')
+    @decorators.idempotent_id('f25f89e4-0b6c-453b-a853-1f80b9d7ef26')
     def test_get_image_without_membership(self):
         # Image is hidden from another tenants.
         image_id = self._create_image()
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index b22ceed..a79c18c 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -20,8 +20,8 @@
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions
-from tempest import test
 
 CONF = config.CONF
 
@@ -54,7 +54,7 @@
 class CreateRegisterImagesTest(base.BaseV1ImageTest):
     """Here we test the registration and creation of images."""
 
-    @test.idempotent_id('3027f8e6-3492-4a11-8575-c3293017af4d')
+    @decorators.idempotent_id('3027f8e6-3492-4a11-8575-c3293017af4d')
     def test_register_then_upload(self):
         # Register, then upload an image
         properties = {'prop1': 'val1'}
@@ -76,7 +76,7 @@
         self.assertIn('size', body)
         self.assertEqual(1024, body.get('size'))
 
-    @test.idempotent_id('69da74d9-68a9-404b-9664-ff7164ccb0f5')
+    @decorators.idempotent_id('69da74d9-68a9-404b-9664-ff7164ccb0f5')
     def test_register_remote_image(self):
         # Register a new remote image
         container_format, disk_format = get_container_and_disk_format()
@@ -93,7 +93,7 @@
         self.assertEqual(properties['key1'], 'value1')
         self.assertEqual(properties['key2'], 'value2')
 
-    @test.idempotent_id('6d0e13a7-515b-460c-b91f-9f4793f09816')
+    @decorators.idempotent_id('6d0e13a7-515b-460c-b91f-9f4793f09816')
     def test_register_http_image(self):
         container_format, disk_format = get_container_and_disk_format()
         image = self.create_image(name='New Http Image',
@@ -105,7 +105,7 @@
         waiters.wait_for_image_status(self.client, image['id'], 'active')
         self.client.show_image(image['id'])
 
-    @test.idempotent_id('05b19d55-140c-40d0-b36b-fafd774d421b')
+    @decorators.idempotent_id('05b19d55-140c-40d0-b36b-fafd774d421b')
     def test_register_image_with_min_ram(self):
         # Register an image with min ram
         container_format, disk_format = get_container_and_disk_format()
@@ -210,7 +210,7 @@
                                  is_public=False, data=image_file)
         return image['id']
 
-    @test.idempotent_id('246178ab-3b33-4212-9a4b-a7fe8261794d')
+    @decorators.idempotent_id('246178ab-3b33-4212-9a4b-a7fe8261794d')
     def test_index_no_params(self):
         # Simple test to see all fixture images returned
         images_list = self.client.list_images()['images']
@@ -218,7 +218,7 @@
         for image_id in self.created_images:
             self.assertIn(image_id, image_list)
 
-    @test.idempotent_id('f1755589-63d6-4468-b098-589820eb4031')
+    @decorators.idempotent_id('f1755589-63d6-4468-b098-589820eb4031')
     def test_index_disk_format(self):
         images_list = self.client.list_images(
             disk_format=self.disk_format_alt)['images']
@@ -229,7 +229,7 @@
         self.assertFalse(self.created_set - self.same_disk_format_set
                          <= result_set)
 
-    @test.idempotent_id('2143655d-96d9-4bec-9188-8674206b4b3b')
+    @decorators.idempotent_id('2143655d-96d9-4bec-9188-8674206b4b3b')
     def test_index_container_format(self):
         images_list = self.client.list_images(
             container_format=self.container_format)['images']
@@ -240,7 +240,7 @@
         self.assertFalse(self.created_set - self.same_container_format_set
                          <= result_set)
 
-    @test.idempotent_id('feb32ac6-22bb-4a16-afd8-9454bb714b14')
+    @decorators.idempotent_id('feb32ac6-22bb-4a16-afd8-9454bb714b14')
     def test_index_max_size(self):
         images_list = self.client.list_images(size_max=42)['images']
         for image in images_list:
@@ -249,7 +249,7 @@
         self.assertTrue(self.size42_set <= result_set)
         self.assertFalse(self.created_set - self.size42_set <= result_set)
 
-    @test.idempotent_id('6ffc16d0-4cbf-4401-95c8-4ac63eac34d8')
+    @decorators.idempotent_id('6ffc16d0-4cbf-4401-95c8-4ac63eac34d8')
     def test_index_min_size(self):
         images_list = self.client.list_images(size_min=142)['images']
         for image in images_list:
@@ -258,7 +258,7 @@
         self.assertTrue(self.size142_set <= result_set)
         self.assertFalse(self.size42_set <= result_set)
 
-    @test.idempotent_id('e5dc26d9-9aa2-48dd-bda5-748e1445da98')
+    @decorators.idempotent_id('e5dc26d9-9aa2-48dd-bda5-748e1445da98')
     def test_index_status_active_detail(self):
         images_list = self.client.list_images(detail=True,
                                               status='active',
@@ -271,7 +271,7 @@
             top_size = size
             self.assertEqual(image['status'], 'active')
 
-    @test.idempotent_id('097af10a-bae8-4342-bff4-edf89969ed2a')
+    @decorators.idempotent_id('097af10a-bae8-4342-bff4-edf89969ed2a')
     def test_index_name(self):
         images_list = self.client.list_images(
             detail=True,
@@ -305,7 +305,7 @@
                                  properties={'key1': 'value1'})
         return image['id']
 
-    @test.idempotent_id('01752c1c-0275-4de3-9e5b-876e44541928')
+    @decorators.idempotent_id('01752c1c-0275-4de3-9e5b-876e44541928')
     def test_list_image_metadata(self):
         # All metadata key/value pairs for an image should be returned
         resp = self.client.check_image(self.image_id)
@@ -313,7 +313,7 @@
         expected = {'key1': 'value1'}
         self.assertEqual(expected, resp_metadata['properties'])
 
-    @test.idempotent_id('d6d7649c-08ce-440d-9ea7-e3dda552f33c')
+    @decorators.idempotent_id('d6d7649c-08ce-440d-9ea7-e3dda552f33c')
     def test_update_image_metadata(self):
         # The metadata for the image should match the updated values
         req_metadata = {'key1': 'alt1', 'key2': 'value2'}
diff --git a/tempest/api/image/v1/test_images_negative.py b/tempest/api/image/v1/test_images_negative.py
index 3493cc2..abec82a 100644
--- a/tempest/api/image/v1/test_images_negative.py
+++ b/tempest/api/image/v1/test_images_negative.py
@@ -16,6 +16,7 @@
 
 from tempest.api.image 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
 
@@ -24,7 +25,7 @@
     """Here are negative tests for the deletion and creation of images."""
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('036ede36-6160-4463-8c01-c781eee6369d')
+    @decorators.idempotent_id('036ede36-6160-4463-8c01-c781eee6369d')
     def test_register_with_invalid_container_format(self):
         # Negative tests for invalid data supplied to POST /images
         self.assertRaises(lib_exc.BadRequest, self.client.create_image,
@@ -33,7 +34,7 @@
                                    'x-image-meta-disk_format': 'vhd'})
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('993face5-921d-4e84-aabf-c1bba4234a67')
+    @decorators.idempotent_id('993face5-921d-4e84-aabf-c1bba4234a67')
     def test_register_with_invalid_disk_format(self):
         self.assertRaises(lib_exc.BadRequest, self.client.create_image,
                           headers={'x-image-meta-name': 'test',
@@ -41,7 +42,7 @@
                                    'x-image-meta-disk_format': 'wrong'})
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ec652588-7e3c-4b67-a2f2-0fa96f57c8fc')
+    @decorators.idempotent_id('ec652588-7e3c-4b67-a2f2-0fa96f57c8fc')
     def test_delete_non_existent_image(self):
         # Return an error while trying to delete a non-existent image
 
@@ -50,13 +51,13 @@
                           non_existent_image_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('04f72aa3-fcec-45a3-81a3-308ef7cc82bc')
+    @decorators.idempotent_id('04f72aa3-fcec-45a3-81a3-308ef7cc82bc')
     def test_delete_image_blank_id(self):
         # Return an error while trying to delete an image with blank Id
         self.assertRaises(lib_exc.NotFound, self.client.delete_image, '')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('950e5054-a3c7-4dee-ada5-e576f1087abd')
+    @decorators.idempotent_id('950e5054-a3c7-4dee-ada5-e576f1087abd')
     def test_delete_image_non_hex_string_id(self):
         # Return an error while trying to delete an image with non hex id
         invalid_image_id = data_utils.rand_uuid()[:-1] + "j"
@@ -64,13 +65,13 @@
                           invalid_image_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('4ed757cd-450c-44b1-9fd1-c819748c650d')
+    @decorators.idempotent_id('4ed757cd-450c-44b1-9fd1-c819748c650d')
     def test_delete_image_negative_image_id(self):
         # Return an error while trying to delete an image with negative id
         self.assertRaises(lib_exc.NotFound, self.client.delete_image, -1)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a4a448ab-3db2-4d2d-b9b2-6a1271241dfe')
+    @decorators.idempotent_id('a4a448ab-3db2-4d2d-b9b2-6a1271241dfe')
     def test_delete_image_id_over_character_limit(self):
         # Return an error while trying to delete image with id over limit
         overlimit_image_id = data_utils.rand_uuid() + "1"
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 36dc6c3..56b3517 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -22,6 +22,7 @@
 from tempest.api.image 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
@@ -32,7 +33,7 @@
     """Here we test the basic operations of images"""
 
     @test.attr(type='smoke')
-    @test.idempotent_id('139b765e-7f3d-4b3d-8b37-3ca3876ee318')
+    @decorators.idempotent_id('139b765e-7f3d-4b3d-8b37-3ca3876ee318')
     def test_register_upload_get_image_file(self):
         """Here we test these functionalities
 
@@ -74,7 +75,7 @@
         self.assertEqual(file_content, body.data)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('f848bb94-1c6e-45a4-8726-39e3a5b23535')
+    @decorators.idempotent_id('f848bb94-1c6e-45a4-8726-39e3a5b23535')
     def test_delete_image(self):
         # Deletes an image by image_id
 
@@ -96,7 +97,7 @@
         self.assertNotIn(image['id'], images_id)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('f66891a7-a35c-41a8-b590-a065c2a1caa6')
+    @decorators.idempotent_id('f66891a7-a35c-41a8-b590-a065c2a1caa6')
     def test_update_image(self):
         # Updates an image by image_id
 
@@ -194,7 +195,7 @@
         msg = 'The list of images was not sorted correctly.'
         self.assertEqual(sorted(sorted_list, reverse=desc), sorted_list, msg)
 
-    @test.idempotent_id('1e341d7a-90a9-494c-b143-2cdf2aeb6aee')
+    @decorators.idempotent_id('1e341d7a-90a9-494c-b143-2cdf2aeb6aee')
     def test_list_no_params(self):
         # Simple test to see all fixture images returned
         images_list = self.client.list_images()['images']
@@ -203,25 +204,25 @@
         for image in self.created_images:
             self.assertIn(image, image_list)
 
-    @test.idempotent_id('9959ca1d-1aa7-4b7a-a1ea-0fff0499b37e')
+    @decorators.idempotent_id('9959ca1d-1aa7-4b7a-a1ea-0fff0499b37e')
     def test_list_images_param_container_format(self):
         # Test to get all images with a specific container_format
         params = {"container_format": self.test_data['container_format']}
         self._list_by_param_value_and_assert(params)
 
-    @test.idempotent_id('4a4735a7-f22f-49b6-b0d9-66e1ef7453eb')
+    @decorators.idempotent_id('4a4735a7-f22f-49b6-b0d9-66e1ef7453eb')
     def test_list_images_param_disk_format(self):
         # Test to get all images with disk_format = raw
         params = {"disk_format": "raw"}
         self._list_by_param_value_and_assert(params)
 
-    @test.idempotent_id('7a95bb92-d99e-4b12-9718-7bc6ab73e6d2')
+    @decorators.idempotent_id('7a95bb92-d99e-4b12-9718-7bc6ab73e6d2')
     def test_list_images_param_visibility(self):
         # Test to get all images with visibility = private
         params = {"visibility": "private"}
         self._list_by_param_value_and_assert(params)
 
-    @test.idempotent_id('cf1b9a48-8340-480e-af7b-fe7e17690876')
+    @decorators.idempotent_id('cf1b9a48-8340-480e-af7b-fe7e17690876')
     def test_list_images_param_size(self):
         # Test to get all images by size
         image_id = self.created_images[0]
@@ -231,7 +232,7 @@
         params = {"size": image['size']}
         self._list_by_param_value_and_assert(params)
 
-    @test.idempotent_id('4ad8c157-971a-4ba8-aa84-ed61154b1e7f')
+    @decorators.idempotent_id('4ad8c157-971a-4ba8-aa84-ed61154b1e7f')
     def test_list_images_param_min_max_size(self):
         # Test to get all images with size between 2000 to 3000
         image_id = self.created_images[0]
@@ -249,13 +250,13 @@
             self.assertLessEqual(image_size, params['size_max'],
                                  "Failed to get images by size_max")
 
-    @test.idempotent_id('7fc9e369-0f58-4d05-9aa5-0969e2d59d15')
+    @decorators.idempotent_id('7fc9e369-0f58-4d05-9aa5-0969e2d59d15')
     def test_list_images_param_status(self):
         # Test to get all active images
         params = {"status": "active"}
         self._list_by_param_value_and_assert(params)
 
-    @test.idempotent_id('e914a891-3cc8-4b40-ad32-e0a39ffbddbb')
+    @decorators.idempotent_id('e914a891-3cc8-4b40-ad32-e0a39ffbddbb')
     def test_list_images_param_limit(self):
         # Test to get images by limit
         params = {"limit": 1}
@@ -264,7 +265,7 @@
         self.assertEqual(len(images_list), params['limit'],
                          "Failed to get images by limit")
 
-    @test.idempotent_id('e9a44b91-31c8-4b40-a332-e0a39ffb4dbb')
+    @decorators.idempotent_id('e9a44b91-31c8-4b40-a332-e0a39ffb4dbb')
     def test_list_image_param_owner(self):
         # Test to get images by owner
         image_id = self.created_images[0]
@@ -274,13 +275,13 @@
         params = {"owner": image['owner']}
         self._list_by_param_value_and_assert(params)
 
-    @test.idempotent_id('55c8f5f5-bfed-409d-a6d5-4caeda985d7b')
+    @decorators.idempotent_id('55c8f5f5-bfed-409d-a6d5-4caeda985d7b')
     def test_list_images_param_name(self):
         # Test to get images by name
         params = {'name': self.test_data['name']}
         self._list_by_param_value_and_assert(params)
 
-    @test.idempotent_id('aa8ac4df-cff9-418b-8d0f-dd9c67b072c9')
+    @decorators.idempotent_id('aa8ac4df-cff9-418b-8d0f-dd9c67b072c9')
     def test_list_images_param_tag(self):
         # Test to get images matching a tag
         params = {'tag': self.test_data['tags'][0]}
@@ -295,24 +296,24 @@
                            observerd_tags=image['tags']))
             self.assertIn(self.test_data['tags'][0], image['tags'], msg)
 
-    @test.idempotent_id('eeadce49-04e0-43b7-aec7-52535d903e7a')
+    @decorators.idempotent_id('eeadce49-04e0-43b7-aec7-52535d903e7a')
     def test_list_images_param_sort(self):
         params = {'sort': 'size:desc'}
         self._list_sorted_by_image_size_and_assert(params, desc=True)
 
-    @test.idempotent_id('9faaa0c2-c3a5-43e1-8f61-61c54b409a49')
+    @decorators.idempotent_id('9faaa0c2-c3a5-43e1-8f61-61c54b409a49')
     def test_list_images_param_sort_key_dir(self):
         params = {'sort_key': 'size', 'sort_dir': 'desc'}
         self._list_sorted_by_image_size_and_assert(params, desc=True)
 
-    @test.idempotent_id('622b925c-479f-4736-860d-adeaf13bc371')
+    @decorators.idempotent_id('622b925c-479f-4736-860d-adeaf13bc371')
     def test_get_image_schema(self):
         # Test to get image schema
         schema = "image"
         body = self.schemas_client.show_schema(schema)
         self.assertEqual("image", body['name'])
 
-    @test.idempotent_id('25c8d7b2-df21-460f-87ac-93130bcdc684')
+    @decorators.idempotent_id('25c8d7b2-df21-460f-87ac-93130bcdc684')
     def test_get_images_schema(self):
         # Test to get images schema
         schema = "images"
@@ -331,7 +332,7 @@
         cls.image_member_client = cls.os.image_member_client_v2
         cls.alt_img_client = cls.os_alt.image_client_v2
 
-    @test.idempotent_id('3fa50be4-8e38-4c02-a8db-7811bb780122')
+    @decorators.idempotent_id('3fa50be4-8e38-4c02-a8db-7811bb780122')
     def test_list_images_param_member_status(self):
         # Create an image to be shared using default visibility
         image_file = six.BytesIO(data_utils.random_bytes(2048))
diff --git a/tempest/api/image/v2/test_images_member.py b/tempest/api/image/v2/test_images_member.py
index 8a4b334..7a495e7 100644
--- a/tempest/api/image/v2/test_images_member.py
+++ b/tempest/api/image/v2/test_images_member.py
@@ -11,12 +11,12 @@
 #    under the License.
 
 from tempest.api.image import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class ImagesMemberTest(base.BaseV2MemberImageTest):
 
-    @test.idempotent_id('5934c6ea-27dc-4d6e-9421-eeb5e045494a')
+    @decorators.idempotent_id('5934c6ea-27dc-4d6e-9421-eeb5e045494a')
     def test_image_share_accept(self):
         image_id = self._create_image()
         member = self.image_member_client.create_image_member(
@@ -39,7 +39,7 @@
         self.assertEqual(member['image_id'], image_id)
         self.assertEqual(member['status'], 'accepted')
 
-    @test.idempotent_id('d9e83e5f-3524-4b38-a900-22abcb26e90e')
+    @decorators.idempotent_id('d9e83e5f-3524-4b38-a900-22abcb26e90e')
     def test_image_share_reject(self):
         image_id = self._create_image()
         member = self.image_member_client.create_image_member(
@@ -55,7 +55,7 @@
                                                          status='rejected')
         self.assertNotIn(image_id, self._list_image_ids_as_alt())
 
-    @test.idempotent_id('a6ee18b9-4378-465e-9ad9-9a6de58a3287')
+    @decorators.idempotent_id('a6ee18b9-4378-465e-9ad9-9a6de58a3287')
     def test_get_image_member(self):
         image_id = self._create_image()
         self.image_member_client.create_image_member(
@@ -73,7 +73,7 @@
         self.assertEqual(image_id, member['image_id'])
         self.assertEqual('accepted', member['status'])
 
-    @test.idempotent_id('72989bc7-2268-48ed-af22-8821e835c914')
+    @decorators.idempotent_id('72989bc7-2268-48ed-af22-8821e835c914')
     def test_remove_image_member(self):
         image_id = self._create_image()
         self.image_member_client.create_image_member(
@@ -87,17 +87,17 @@
                                                      self.alt_tenant_id)
         self.assertNotIn(image_id, self._list_image_ids_as_alt())
 
-    @test.idempotent_id('634dcc3f-f6e2-4409-b8fd-354a0bb25d83')
+    @decorators.idempotent_id('634dcc3f-f6e2-4409-b8fd-354a0bb25d83')
     def test_get_image_member_schema(self):
         body = self.schemas_client.show_schema("member")
         self.assertEqual("member", body['name'])
 
-    @test.idempotent_id('6ae916ef-1052-4e11-8d36-b3ae14853cbb')
+    @decorators.idempotent_id('6ae916ef-1052-4e11-8d36-b3ae14853cbb')
     def test_get_image_members_schema(self):
         body = self.schemas_client.show_schema("members")
         self.assertEqual("members", body['name'])
 
-    @test.idempotent_id('cb961424-3f68-4d21-8e36-30ad66fb6bfb')
+    @decorators.idempotent_id('cb961424-3f68-4d21-8e36-30ad66fb6bfb')
     def test_get_private_image(self):
         image_id = self._create_image()
         member = self.image_member_client.create_image_member(
diff --git a/tempest/api/image/v2/test_images_member_negative.py b/tempest/api/image/v2/test_images_member_negative.py
index fa29a92..ae9630a 100644
--- a/tempest/api/image/v2/test_images_member_negative.py
+++ b/tempest/api/image/v2/test_images_member_negative.py
@@ -11,6 +11,7 @@
 #    under the License.
 
 from tempest.api.image import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -18,7 +19,7 @@
 class ImagesMemberNegativeTest(base.BaseV2MemberImageTest):
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('b79efb37-820d-4cf0-b54c-308b00cf842c')
+    @decorators.idempotent_id('b79efb37-820d-4cf0-b54c-308b00cf842c')
     def test_image_share_invalid_status(self):
         image_id = self._create_image()
         member = self.image_member_client.create_image_member(
@@ -30,7 +31,7 @@
                           status='notavalidstatus')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('27002f74-109e-4a37-acd0-f91cd4597967')
+    @decorators.idempotent_id('27002f74-109e-4a37-acd0-f91cd4597967')
     def test_image_share_owner_cannot_accept(self):
         image_id = self._create_image()
         member = self.image_member_client.create_image_member(
diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_objects.py b/tempest/api/image/v2/test_images_metadefs_namespace_objects.py
index 95d1521..38e56d4 100644
--- a/tempest/api/image/v2/test_images_metadefs_namespace_objects.py
+++ b/tempest/api/image/v2/test_images_metadefs_namespace_objects.py
@@ -13,7 +13,7 @@
 from tempest.api.image import base
 from tempest.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class MetadataNamespaceObjectsTest(base.BaseV2ImageTest):
@@ -28,7 +28,7 @@
                         namespace['namespace'], object_name)
         return namespace_object
 
-    @test.idempotent_id('b1a3775e-3b5c-4f6a-a3b4-1ba3574ae718')
+    @decorators.idempotent_id('b1a3775e-3b5c-4f6a-a3b4-1ba3574ae718')
     def test_create_update_delete_meta_namespace_objects(self):
         # Create a namespace
         namespace = self.create_namespace()
@@ -50,7 +50,7 @@
                 namespace['namespace'])['objects']]
         self.assertNotIn(up_object_name, namespace_objects)
 
-    @test.idempotent_id('a2a3615e-3b5c-3f6a-a2b1-1ba3574ae738')
+    @decorators.idempotent_id('a2a3615e-3b5c-3f6a-a2b1-1ba3574ae738')
     def test_list_meta_namespace_objects(self):
         # Create a namespace object
         namespace = self.create_namespace()
@@ -62,7 +62,7 @@
                 namespace['namespace'])['objects']]
         self.assertIn(meta_namespace_object['name'], namespace_objects)
 
-    @test.idempotent_id('b1a3674e-3b4c-3f6a-a3b4-1ba3573ca768')
+    @decorators.idempotent_id('b1a3674e-3b4c-3f6a-a3b4-1ba3573ca768')
     def test_show_meta_namespace_objects(self):
         # Create a namespace object
         namespace = self.create_namespace()
diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_properties.py b/tempest/api/image/v2/test_images_metadefs_namespace_properties.py
index 7113db4..ead70f2 100644
--- a/tempest/api/image/v2/test_images_metadefs_namespace_properties.py
+++ b/tempest/api/image/v2/test_images_metadefs_namespace_properties.py
@@ -12,13 +12,13 @@
 
 from tempest.api.image import base
 from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class MetadataNamespacePropertiesTest(base.BaseV2ImageTest):
     """Test the Metadata definition namespace property basic functionality"""
 
-    @test.idempotent_id('b1a3765e-3a5d-4f6d-a3a7-3ca3476ae768')
+    @decorators.idempotent_id('b1a3765e-3a5d-4f6d-a3a7-3ca3476ae768')
     def test_basic_meta_def_namespace_property(self):
         # Get the available resource types and use one resource_type
         body = self.resource_types_client.list_resource_types()
diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_tags.py b/tempest/api/image/v2/test_images_metadefs_namespace_tags.py
index 186d9c8..608d9fc 100644
--- a/tempest/api/image/v2/test_images_metadefs_namespace_tags.py
+++ b/tempest/api/image/v2/test_images_metadefs_namespace_tags.py
@@ -13,7 +13,7 @@
 from tempest.api.image import base
 from tempest.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class MetadataNamespaceTagsTest(base.BaseV2ImageTest):
@@ -41,7 +41,7 @@
                         namespace['namespace'])
         return namespace_tags
 
-    @test.idempotent_id('a2a3765e-3a6d-4f6d-a3a7-3cc3476aa876')
+    @decorators.idempotent_id('a2a3765e-3a6d-4f6d-a3a7-3cc3476aa876')
     def test_create_list_delete_namespace_tags(self):
         # Create a namespace
         namespace = self.create_namespace()
@@ -60,7 +60,7 @@
             namespace['namespace'])
         self.assertEqual([], body['tags'])
 
-    @test.idempotent_id('a2a3765e-1a2c-3f6d-a3a7-3cc3466ab875')
+    @decorators.idempotent_id('a2a3765e-1a2c-3f6d-a3a7-3cc3466ab875')
     def test_create_update_delete_tag(self):
         # Create a namespace
         namespace = self.create_namespace()
diff --git a/tempest/api/image/v2/test_images_metadefs_namespaces.py b/tempest/api/image/v2/test_images_metadefs_namespaces.py
index a80a0cf..9fda937 100644
--- a/tempest/api/image/v2/test_images_metadefs_namespaces.py
+++ b/tempest/api/image/v2/test_images_metadefs_namespaces.py
@@ -16,14 +16,14 @@
 from tempest.api.image import base
 from tempest.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 
 class MetadataNamespacesTest(base.BaseV2ImageTest):
     """Test the Metadata definition Namespaces basic functionality"""
 
-    @test.idempotent_id('319b765e-7f3d-4b3d-8b37-3ca3876ee768')
+    @decorators.idempotent_id('319b765e-7f3d-4b3d-8b37-3ca3876ee768')
     def test_basic_metadata_definition_namespaces(self):
         # get the available resource types and use one resource_type
         body = self.resource_types_client.list_resource_types()
diff --git a/tempest/api/image/v2/test_images_metadefs_resource_types.py b/tempest/api/image/v2/test_images_metadefs_resource_types.py
index 3dd432b..c60b3f7 100644
--- a/tempest/api/image/v2/test_images_metadefs_resource_types.py
+++ b/tempest/api/image/v2/test_images_metadefs_resource_types.py
@@ -14,13 +14,13 @@
 #    under the License.
 
 from tempest.api.image import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class MetadataResourceTypesTest(base.BaseV2ImageTest):
     """Test the Metadata definition resource types basic functionality"""
 
-    @test.idempotent_id('6f358a4e-5ef0-11e6-a795-080027d0d606')
+    @decorators.idempotent_id('6f358a4e-5ef0-11e6-a795-080027d0d606')
     def test_basic_meta_def_resource_type_association(self):
         # Get the available resource types and use one resource_type
         body = self.resource_types_client.list_resource_types()
diff --git a/tempest/api/image/v2/test_images_metadefs_schema.py b/tempest/api/image/v2/test_images_metadefs_schema.py
index 7edf1af..95cc310 100644
--- a/tempest/api/image/v2/test_images_metadefs_schema.py
+++ b/tempest/api/image/v2/test_images_metadefs_schema.py
@@ -14,67 +14,67 @@
 #    under the License.
 
 from tempest.api.image import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class MetadataSchemaTest(base.BaseV2ImageTest):
     """Test to get metadata schema"""
 
-    @test.idempotent_id('e9e44891-3cb8-3b40-a532-e0a39fea3dab')
+    @decorators.idempotent_id('e9e44891-3cb8-3b40-a532-e0a39fea3dab')
     def test_get_metadata_namespace_schema(self):
         # Test to get namespace schema
         body = self.schemas_client.show_schema("metadefs/namespace")
         self.assertEqual("namespace", body['name'])
 
-    @test.idempotent_id('ffe44891-678b-3ba0-a3e2-e0a3967b3aeb')
+    @decorators.idempotent_id('ffe44891-678b-3ba0-a3e2-e0a3967b3aeb')
     def test_get_metadata_namespaces_schema(self):
         # Test to get namespaces schema
         body = self.schemas_client.show_schema("metadefs/namespaces")
         self.assertEqual("namespaces", body['name'])
 
-    @test.idempotent_id('fde34891-678b-3b40-ae32-e0a3e67b6beb')
+    @decorators.idempotent_id('fde34891-678b-3b40-ae32-e0a3e67b6beb')
     def test_get_metadata_resource_type_schema(self):
         # Test to get resource_type schema
         body = self.schemas_client.show_schema("metadefs/resource_type")
         self.assertEqual("resource_type_association", body['name'])
 
-    @test.idempotent_id('dfe4a891-b38b-3bf0-a3b2-e03ee67b3a3a')
+    @decorators.idempotent_id('dfe4a891-b38b-3bf0-a3b2-e03ee67b3a3a')
     def test_get_metadata_resources_types_schema(self):
         # Test to get resource_types schema
         body = self.schemas_client.show_schema("metadefs/resource_types")
         self.assertEqual("resource_type_associations", body['name'])
 
-    @test.idempotent_id('dff4a891-b38b-3bf0-a3b2-e03ee67b3a3b')
+    @decorators.idempotent_id('dff4a891-b38b-3bf0-a3b2-e03ee67b3a3b')
     def test_get_metadata_object_schema(self):
         # Test to get object schema
         body = self.schemas_client.show_schema("metadefs/object")
         self.assertEqual("object", body['name'])
 
-    @test.idempotent_id('dee4a891-b38b-3bf0-a3b2-e03ee67b3a3c')
+    @decorators.idempotent_id('dee4a891-b38b-3bf0-a3b2-e03ee67b3a3c')
     def test_get_metadata_objects_schema(self):
         # Test to get objects schema
         body = self.schemas_client.show_schema("metadefs/objects")
         self.assertEqual("objects", body['name'])
 
-    @test.idempotent_id('dae4a891-b38b-3bf0-a3b2-e03ee67b3a3d')
+    @decorators.idempotent_id('dae4a891-b38b-3bf0-a3b2-e03ee67b3a3d')
     def test_get_metadata_property_schema(self):
         # Test to get property schema
         body = self.schemas_client.show_schema("metadefs/property")
         self.assertEqual("property", body['name'])
 
-    @test.idempotent_id('dce4a891-b38b-3bf0-a3b2-e03ee67b3a3e')
+    @decorators.idempotent_id('dce4a891-b38b-3bf0-a3b2-e03ee67b3a3e')
     def test_get_metadata_properties_schema(self):
         # Test to get properties schema
         body = self.schemas_client.show_schema("metadefs/properties")
         self.assertEqual("properties", body['name'])
 
-    @test.idempotent_id('dde4a891-b38b-3bf0-a3b2-e03ee67b3a3e')
+    @decorators.idempotent_id('dde4a891-b38b-3bf0-a3b2-e03ee67b3a3e')
     def test_get_metadata_tag_schema(self):
         # Test to get tag schema
         body = self.schemas_client.show_schema("metadefs/tag")
         self.assertEqual("tag", body['name'])
 
-    @test.idempotent_id('cde4a891-b38b-3bf0-a3b2-e03ee67b3a3a')
+    @decorators.idempotent_id('cde4a891-b38b-3bf0-a3b2-e03ee67b3a3a')
     def test_get_metadata_tags_schema(self):
         # Test to get tags schema
         body = self.schemas_client.show_schema("metadefs/tags")
diff --git a/tempest/api/image/v2/test_images_negative.py b/tempest/api/image/v2/test_images_negative.py
index cd1bca0..04c752a 100644
--- a/tempest/api/image/v2/test_images_negative.py
+++ b/tempest/api/image/v2/test_images_negative.py
@@ -16,6 +16,7 @@
 
 from tempest.api.image 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
 
@@ -34,7 +35,7 @@
      """
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('668743d5-08ad-4480-b2b8-15da34f81d9f')
+    @decorators.idempotent_id('668743d5-08ad-4480-b2b8-15da34f81d9f')
     def test_get_non_existent_image(self):
         # get the non-existent image
         non_existent_id = data_utils.rand_uuid()
@@ -42,14 +43,14 @@
                           non_existent_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ef45000d-0a72-4781-866d-4cb7bf2562ad')
+    @decorators.idempotent_id('ef45000d-0a72-4781-866d-4cb7bf2562ad')
     def test_get_image_null_id(self):
         # get image with image_id = NULL
         image_id = ""
         self.assertRaises(lib_exc.NotFound, self.client.show_image, image_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e57fc127-7ba0-4693-92d7-1d8a05ebcba9')
+    @decorators.idempotent_id('e57fc127-7ba0-4693-92d7-1d8a05ebcba9')
     def test_get_delete_deleted_image(self):
         # get and delete the deleted image
         # create and delete image
@@ -68,7 +69,7 @@
                           image['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('6fe40f1c-57bd-4918-89cc-8500f850f3de')
+    @decorators.idempotent_id('6fe40f1c-57bd-4918-89cc-8500f850f3de')
     def test_delete_non_existing_image(self):
         # delete non-existent image
         non_existent_image_id = data_utils.rand_uuid()
@@ -76,7 +77,7 @@
                           non_existent_image_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('32248db1-ab88-4821-9604-c7c369f1f88c')
+    @decorators.idempotent_id('32248db1-ab88-4821-9604-c7c369f1f88c')
     def test_delete_image_null_id(self):
         # delete image with image_id=NULL
         image_id = ""
@@ -84,7 +85,7 @@
                           image_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('292bd310-369b-41c7-a7a3-10276ef76753')
+    @decorators.idempotent_id('292bd310-369b-41c7-a7a3-10276ef76753')
     def test_register_with_invalid_container_format(self):
         # Negative tests for invalid data supplied to POST /images
         self.assertRaises(lib_exc.BadRequest, self.client.create_image,
@@ -92,7 +93,7 @@
                           disk_format='vhd')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('70c6040c-5a97-4111-9e13-e73665264ce1')
+    @decorators.idempotent_id('70c6040c-5a97-4111-9e13-e73665264ce1')
     def test_register_with_invalid_disk_format(self):
         self.assertRaises(lib_exc.BadRequest, self.client.create_image,
                           name='test', container_format='bare',
diff --git a/tempest/api/image/v2/test_images_tags.py b/tempest/api/image/v2/test_images_tags.py
index 03f29bd..fd9591f 100644
--- a/tempest/api/image/v2/test_images_tags.py
+++ b/tempest/api/image/v2/test_images_tags.py
@@ -14,12 +14,12 @@
 
 from tempest.api.image import base
 from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class ImagesTagsTest(base.BaseV2ImageTest):
 
-    @test.idempotent_id('10407036-6059-4f95-a2cd-cbbbee7ed329')
+    @decorators.idempotent_id('10407036-6059-4f95-a2cd-cbbbee7ed329')
     def test_update_delete_tags_for_image(self):
         image = self.create_image(container_format='bare',
                                   disk_format='raw',
diff --git a/tempest/api/image/v2/test_images_tags_negative.py b/tempest/api/image/v2/test_images_tags_negative.py
index af4ffcf..2a08f3a 100644
--- a/tempest/api/image/v2/test_images_tags_negative.py
+++ b/tempest/api/image/v2/test_images_tags_negative.py
@@ -14,6 +14,7 @@
 
 from tempest.api.image 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
 
@@ -21,7 +22,7 @@
 class ImagesTagsNegativeTest(base.BaseV2ImageTest):
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('8cd30f82-6f9a-4c6e-8034-c1b51fba43d9')
+    @decorators.idempotent_id('8cd30f82-6f9a-4c6e-8034-c1b51fba43d9')
     def test_update_tags_for_non_existing_image(self):
         # Update tag with non existing image.
         tag = data_utils.rand_name('tag')
@@ -30,7 +31,7 @@
                           non_exist_image, tag)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('39c023a2-325a-433a-9eea-649bf1414b19')
+    @decorators.idempotent_id('39c023a2-325a-433a-9eea-649bf1414b19')
     def test_delete_non_existing_tag(self):
         # Delete non existing tag.
         image = self.create_image(container_format='bare',
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
index 61f8e15..6389489 100644
--- a/tempest/api/network/admin/test_agent_management.py
+++ b/tempest/api/network/admin/test_agent_management.py
@@ -14,6 +14,7 @@
 
 from tempest.api.network import base
 from tempest.common import tempest_fixtures as fixtures
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -33,7 +34,7 @@
         agents = body['agents']
         cls.agent = agents[0]
 
-    @test.idempotent_id('9c80f04d-11f3-44a4-8738-ed2f879b0ff4')
+    @decorators.idempotent_id('9c80f04d-11f3-44a4-8738-ed2f879b0ff4')
     def test_list_agent(self):
         body = self.admin_agents_client.list_agents()
         agents = body['agents']
@@ -45,18 +46,18 @@
             agent.pop('configurations', None)
         self.assertIn(self.agent, agents)
 
-    @test.idempotent_id('e335be47-b9a1-46fd-be30-0874c0b751e6')
+    @decorators.idempotent_id('e335be47-b9a1-46fd-be30-0874c0b751e6')
     def test_list_agents_non_admin(self):
         body = self.agents_client.list_agents()
         self.assertEqual(len(body["agents"]), 0)
 
-    @test.idempotent_id('869bc8e8-0fda-4a30-9b71-f8a7cf58ca9f')
+    @decorators.idempotent_id('869bc8e8-0fda-4a30-9b71-f8a7cf58ca9f')
     def test_show_agent(self):
         body = self.admin_agents_client.show_agent(self.agent['id'])
         agent = body['agent']
         self.assertEqual(agent['id'], self.agent['id'])
 
-    @test.idempotent_id('371dfc5b-55b9-4cb5-ac82-c40eadaac941')
+    @decorators.idempotent_id('371dfc5b-55b9-4cb5-ac82-c40eadaac941')
     def test_update_agent_status(self):
         origin_status = self.agent['admin_state_up']
         # Try to update the 'admin_state_up' to the original
@@ -67,7 +68,7 @@
         updated_status = body['agent']['admin_state_up']
         self.assertEqual(origin_status, updated_status)
 
-    @test.idempotent_id('68a94a14-1243-46e6-83bf-157627e31556')
+    @decorators.idempotent_id('68a94a14-1243-46e6-83bf-157627e31556')
     def test_update_agent_description(self):
         self.useFixture(fixtures.LockFixture('agent_description'))
         description = 'description for update agent.'
diff --git a/tempest/api/network/admin/test_dhcp_agent_scheduler.py b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
index b3555b6..868771f 100644
--- a/tempest/api/network/admin/test_dhcp_agent_scheduler.py
+++ b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
@@ -13,6 +13,7 @@
 #    under the License.
 
 from tempest.api.network import base
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -34,12 +35,12 @@
         cls.subnet = cls.create_subnet(cls.network)
         cls.port = cls.create_port(cls.network)
 
-    @test.idempotent_id('5032b1fe-eb42-4a64-8f3b-6e189d8b5c7d')
+    @decorators.idempotent_id('5032b1fe-eb42-4a64-8f3b-6e189d8b5c7d')
     def test_list_dhcp_agent_hosting_network(self):
         self.admin_networks_client.list_dhcp_agents_on_hosting_network(
             self.network['id'])
 
-    @test.idempotent_id('30c48f98-e45d-4ffb-841c-b8aad57c7587')
+    @decorators.idempotent_id('30c48f98-e45d-4ffb-841c-b8aad57c7587')
     def test_list_networks_hosted_by_one_dhcp(self):
         body = self.admin_networks_client.list_dhcp_agents_on_hosting_network(
             self.network['id'])
@@ -58,7 +59,7 @@
             network_ids.append(network['id'])
         return network_id in network_ids
 
-    @test.idempotent_id('a0856713-6549-470c-a656-e97c8df9a14d')
+    @decorators.idempotent_id('a0856713-6549-470c-a656-e97c8df9a14d')
     def test_add_remove_network_from_dhcp_agent(self):
         # The agent is now bound to the network, we can free the port
         self.ports_client.delete_port(self.port['id'])
diff --git a/tempest/api/network/admin/test_external_network_extension.py b/tempest/api/network/admin/test_external_network_extension.py
index 2d53265..dc440d3 100644
--- a/tempest/api/network/admin/test_external_network_extension.py
+++ b/tempest/api/network/admin/test_external_network_extension.py
@@ -13,7 +13,7 @@
 from tempest.api.network import base
 from tempest.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
-from tempest import test
+from tempest.lib import decorators
 
 
 class ExternalNetworksTestJSON(base.BaseAdminNetworkTest):
@@ -33,7 +33,7 @@
             self.admin_networks_client.delete_network, network['id'])
         return network
 
-    @test.idempotent_id('462be770-b310-4df9-9c42-773217e4c8b1')
+    @decorators.idempotent_id('462be770-b310-4df9-9c42-773217e4c8b1')
     def test_create_external_network(self):
         # Create a network as an admin user specifying the
         # external network extension attribute
@@ -42,7 +42,7 @@
         self.assertIsNotNone(ext_network['id'])
         self.assertTrue(ext_network['router:external'])
 
-    @test.idempotent_id('4db5417a-e11c-474d-a361-af00ebef57c5')
+    @decorators.idempotent_id('4db5417a-e11c-474d-a361-af00ebef57c5')
     def test_update_external_network(self):
         # Update a network as an admin user specifying the
         # external network extension attribute
@@ -55,7 +55,7 @@
         # Verify that router:external parameter was updated
         self.assertTrue(updated_network['router:external'])
 
-    @test.idempotent_id('39be4c9b-a57e-4ff9-b7c7-b218e209dfcc')
+    @decorators.idempotent_id('39be4c9b-a57e-4ff9-b7c7-b218e209dfcc')
     def test_list_external_networks(self):
         # Create external_net
         external_network = self._create_network()
@@ -72,7 +72,7 @@
             elif net['id'] == external_network['id']:
                 self.assertTrue(net['router:external'])
 
-    @test.idempotent_id('2ac50ab2-7ebd-4e27-b3ce-a9e399faaea2')
+    @decorators.idempotent_id('2ac50ab2-7ebd-4e27-b3ce-a9e399faaea2')
     def test_show_external_networks_attribute(self):
         # Create external_net
         external_network = self._create_network()
@@ -90,7 +90,7 @@
         self.assertEqual(self.network['id'], show_net['id'])
         self.assertFalse(show_net['router:external'])
 
-    @test.idempotent_id('82068503-2cf2-4ed4-b3be-ecb89432e4bb')
+    @decorators.idempotent_id('82068503-2cf2-4ed4-b3be-ecb89432e4bb')
     def test_delete_external_networks_with_floating_ip(self):
         # Verifies external network can be deleted while still holding
         # (unassociated) floating IPs
diff --git a/tempest/api/network/admin/test_external_networks_negative.py b/tempest/api/network/admin/test_external_networks_negative.py
index 94d65c3..743089a 100644
--- a/tempest/api/network/admin/test_external_networks_negative.py
+++ b/tempest/api/network/admin/test_external_networks_negative.py
@@ -16,6 +16,7 @@
 from tempest.api.network import base
 from tempest import config
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -25,7 +26,7 @@
 class ExternalNetworksAdminNegativeTestJSON(base.BaseAdminNetworkTest):
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d402ae6c-0be0-4d8e-833b-a738895d98d0')
+    @decorators.idempotent_id('d402ae6c-0be0-4d8e-833b-a738895d98d0')
     def test_create_port_with_precreated_floatingip_as_fixed_ip(self):
         # NOTE: External networks can be used to create both floating-ip as
         # well as instance-ip. So, creating an instance-ip with a value of a
diff --git a/tempest/api/network/admin/test_floating_ips_admin_actions.py b/tempest/api/network/admin/test_floating_ips_admin_actions.py
index a32e7da..c36323a 100644
--- a/tempest/api/network/admin/test_floating_ips_admin_actions.py
+++ b/tempest/api/network/admin/test_floating_ips_admin_actions.py
@@ -15,6 +15,7 @@
 
 from tempest.api.network import base
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -47,7 +48,7 @@
         cls.create_router_interface(cls.router['id'], cls.subnet['id'])
         cls.port = cls.create_port(cls.network)
 
-    @test.idempotent_id('64f2100b-5471-4ded-b46c-ddeeeb4f231b')
+    @decorators.idempotent_id('64f2100b-5471-4ded-b46c-ddeeeb4f231b')
     def test_list_floating_ips_from_admin_and_nonadmin(self):
         # Create floating ip from admin user
         floating_ip_admin = self.admin_floating_ips_client.create_floatingip(
@@ -78,7 +79,7 @@
                          floating_ip_ids)
         self.assertNotIn(floating_ip_alt['id'], floating_ip_ids)
 
-    @test.idempotent_id('32727cc3-abe2-4485-a16e-48f2d54c14f2')
+    @decorators.idempotent_id('32727cc3-abe2-4485-a16e-48f2d54c14f2')
     def test_create_list_show_floating_ip_with_tenant_id_by_admin(self):
         # Creates a floating IP
         body = self.admin_floating_ips_client.create_floatingip(
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index c2ff038..5a54ae0 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -14,6 +14,7 @@
 
 from tempest.api.network import base
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions
 from tempest import test
 
@@ -103,11 +104,11 @@
                                                        port_id=cls.port['id'])
         super(L3AgentSchedulerTestJSON, cls).resource_cleanup()
 
-    @test.idempotent_id('b7ce6e89-e837-4ded-9b78-9ed3c9c6a45a')
+    @decorators.idempotent_id('b7ce6e89-e837-4ded-9b78-9ed3c9c6a45a')
     def test_list_routers_on_l3_agent(self):
         self.admin_agents_client.list_routers_on_l3_agent(self.agent['id'])
 
-    @test.idempotent_id('9464e5e7-8625-49c3-8fd1-89c52be59d66')
+    @decorators.idempotent_id('9464e5e7-8625-49c3-8fd1-89c52be59d66')
     def test_add_list_remove_router_on_l3_agent(self):
         l3_agent_ids = list()
         self.admin_agents_client.create_router_on_l3_agent(
diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py
index beb6ce6..435e672 100644
--- a/tempest/api/network/admin/test_negative_quotas.py
+++ b/tempest/api/network/admin/test_negative_quotas.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest.api.network import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -38,7 +39,7 @@
             msg = "quotas extension not enabled."
             raise cls.skipException(msg)
 
-    @test.idempotent_id('644f4e1b-1bf9-4af0-9fd8-eb56ac0f51cf')
+    @decorators.idempotent_id('644f4e1b-1bf9-4af0-9fd8-eb56ac0f51cf')
     def test_network_quota_exceeding(self):
         # Set the network quota to two
         self.admin_quotas_client.update_quotas(self.networks_client.tenant_id,
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 8695ebd..7b6ebef 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -16,6 +16,7 @@
 from tempest.api.network import base
 from tempest.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -78,7 +79,7 @@
         for q in non_default_quotas['quotas']:
             self.assertNotEqual(project_id, q['tenant_id'])
 
-    @test.idempotent_id('2390f766-836d-40ef-9aeb-e810d78207fb')
+    @decorators.idempotent_id('2390f766-836d-40ef-9aeb-e810d78207fb')
     def test_quotas(self):
         new_quotas = {'network': 0, 'port': 0}
         self._check_quotas(new_quotas)
diff --git a/tempest/api/network/admin/test_routers_dvr.py b/tempest/api/network/admin/test_routers_dvr.py
index aaac921..78ca494 100644
--- a/tempest/api/network/admin/test_routers_dvr.py
+++ b/tempest/api/network/admin/test_routers_dvr.py
@@ -17,6 +17,7 @@
 
 from tempest.api.network import base_routers as base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -42,7 +43,7 @@
             msg = "'distributed' flag not found. DVR Possibly not enabled"
             raise cls.skipException(msg)
 
-    @test.idempotent_id('08a2a0a8-f1e4-4b34-8e30-e522e836c44e')
+    @decorators.idempotent_id('08a2a0a8-f1e4-4b34-8e30-e522e836c44e')
     def test_distributed_router_creation(self):
         """Test distributed router creation
 
@@ -61,7 +62,7 @@
                         router['router']['id'])
         self.assertTrue(router['router']['distributed'])
 
-    @test.idempotent_id('8a0a72b4-7290-4677-afeb-b4ffe37bc352')
+    @decorators.idempotent_id('8a0a72b4-7290-4677-afeb-b4ffe37bc352')
     def test_centralized_router_creation(self):
         """Test centralized router creation
 
@@ -81,7 +82,7 @@
                         router['router']['id'])
         self.assertFalse(router['router']['distributed'])
 
-    @test.idempotent_id('acd43596-c1fb-439d-ada8-31ad48ae3c2e')
+    @decorators.idempotent_id('acd43596-c1fb-439d-ada8-31ad48ae3c2e')
     @testtools.skipUnless(test.is_extension_enabled('l3-ha', 'network'),
                           'HA routers are not available.')
     def test_centralized_router_update_to_dvr(self):
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/network/test_allowed_address_pair.py b/tempest/api/network/test_allowed_address_pair.py
index 92dfc56..a90e4bf 100644
--- a/tempest/api/network/test_allowed_address_pair.py
+++ b/tempest/api/network/test_allowed_address_pair.py
@@ -18,6 +18,7 @@
 
 from tempest.api.network import base
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -56,7 +57,7 @@
         cls.ip_address = port['fixed_ips'][0]['ip_address']
         cls.mac_address = port['mac_address']
 
-    @test.idempotent_id('86c3529b-1231-40de-803c-00e40882f043')
+    @decorators.idempotent_id('86c3529b-1231-40de-803c-00e40882f043')
     def test_create_list_port_with_address_pair(self):
         # Create port with allowed address pair attribute
         allowed_address_pairs = [{'ip_address': self.ip_address,
@@ -94,18 +95,18 @@
         six.assertCountEqual(self, allowed_address_pair,
                              allowed_address_pairs)
 
-    @test.idempotent_id('9599b337-272c-47fd-b3cf-509414414ac4')
+    @decorators.idempotent_id('9599b337-272c-47fd-b3cf-509414414ac4')
     def test_update_port_with_address_pair(self):
         # Update port with allowed address pair
         self._update_port_with_address(self.ip_address)
 
-    @test.idempotent_id('4d6d178f-34f6-4bff-a01c-0a2f8fe909e4')
+    @decorators.idempotent_id('4d6d178f-34f6-4bff-a01c-0a2f8fe909e4')
     def test_update_port_with_cidr_address_pair(self):
         # Update allowed address pair with cidr
         cidr = str(netaddr.IPNetwork(CONF.network.project_network_cidr))
         self._update_port_with_address(cidr)
 
-    @test.idempotent_id('b3f20091-6cd5-472b-8487-3516137df933')
+    @decorators.idempotent_id('b3f20091-6cd5-472b-8487-3516137df933')
     def test_update_port_with_multiple_ip_mac_address_pair(self):
         # Create an ip _address and mac_address through port create
         resp = self.ports_client.create_port(network_id=self.network['id'])
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index 3c96a93..fa4010d 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -20,8 +20,8 @@
 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.lib import exceptions as lib_exc
-from tempest import test
 
 CONF = config.CONF
 
@@ -95,7 +95,7 @@
                                                    port_mac).format()
         return real_ip, eui_ip
 
-    @test.idempotent_id('e5517e62-6f16-430d-a672-f80875493d4c')
+    @decorators.idempotent_id('e5517e62-6f16-430d-a672-f80875493d4c')
     def test_dhcpv6_stateless_eui64(self):
         # NOTE: When subnets configured with RAs SLAAC (AOM=100) and DHCP
         # stateless (AOM=110) both for radvd and dnsmasq, port shall receive
@@ -113,7 +113,7 @@
                               'ipv6_ra_mode=%s and ipv6_address_mode=%s') % (
                                  real_ip, eui_ip, ra_mode, add_mode))
 
-    @test.idempotent_id('ae2f4a5d-03ff-4c42-a3b0-ce2fcb7ea832')
+    @decorators.idempotent_id('ae2f4a5d-03ff-4c42-a3b0-ce2fcb7ea832')
     def test_dhcpv6_stateless_no_ra(self):
         # NOTE: When subnets configured with dnsmasq SLAAC and DHCP stateless
         # and there is no radvd, port shall receive IP address calculated
@@ -134,7 +134,7 @@
                                  ra_mode if ra_mode else "Off",
                                  add_mode if add_mode else "Off"))
 
-    @test.idempotent_id('81f18ef6-95b5-4584-9966-10d480b7496a')
+    @decorators.idempotent_id('81f18ef6-95b5-4584-9966-10d480b7496a')
     def test_dhcpv6_invalid_options(self):
         """Different configurations for radvd and dnsmasq are not allowed"""
         for ra_mode, add_mode in (
@@ -152,7 +152,7 @@
                               self.network,
                               **kwargs)
 
-    @test.idempotent_id('21635b6f-165a-4d42-bf49-7d195e47342f')
+    @decorators.idempotent_id('21635b6f-165a-4d42-bf49-7d195e47342f')
     def test_dhcpv6_stateless_no_ra_no_dhcp(self):
         # NOTE: If no radvd option and no dnsmasq option is configured
         # port shall receive IP from fixed IPs list of subnet.
@@ -164,7 +164,7 @@
                              'but shall be taken from fixed IPs') % (
                                 real_ip, eui_ip))
 
-    @test.idempotent_id('4544adf7-bb5f-4bdc-b769-b3e77026cef2')
+    @decorators.idempotent_id('4544adf7-bb5f-4bdc-b769-b3e77026cef2')
     def test_dhcpv6_two_subnets(self):
         # NOTE: When one IPv6 subnet configured with dnsmasq SLAAC or DHCP
         # stateless and other IPv6 is with DHCP stateful, port shall receive
@@ -213,7 +213,7 @@
                 self.assertIn(netaddr.IPAddress(real_dhcp_ip),
                               netaddr.IPNetwork(subnet_dhcp['cidr']), msg)
 
-    @test.idempotent_id('4256c61d-c538-41ea-9147-3c450c36669e')
+    @decorators.idempotent_id('4256c61d-c538-41ea-9147-3c450c36669e')
     def test_dhcpv6_64_subnets(self):
         # NOTE: When one IPv6 subnet configured with dnsmasq SLAAC or DHCP
         # stateless and other IPv4 is with DHCP of IPv4, port shall receive
@@ -256,7 +256,7 @@
                 self.assertIn(netaddr.IPAddress(real_dhcp_ip),
                               netaddr.IPNetwork(subnet_dhcp['cidr']), msg)
 
-    @test.idempotent_id('4ab211a0-276f-4552-9070-51e27f58fecf')
+    @decorators.idempotent_id('4ab211a0-276f-4552-9070-51e27f58fecf')
     def test_dhcp_stateful(self):
         # NOTE: With all options below, DHCPv6 shall allocate address from
         # subnet pool to port.
@@ -277,7 +277,7 @@
             self.assertIn(netaddr.IPAddress(port_ip),
                           netaddr.IPNetwork(subnet['cidr']), msg)
 
-    @test.idempotent_id('51a5e97f-f02e-4e4e-9a17-a69811d300e3')
+    @decorators.idempotent_id('51a5e97f-f02e-4e4e-9a17-a69811d300e3')
     def test_dhcp_stateful_fixedips(self):
         # NOTE: With all options below, port shall be able to get
         # requested IP from fixed IP range not depending on
@@ -305,7 +305,7 @@
                               "port create request: %s") % (
                                  port_ip, ip))
 
-    @test.idempotent_id('98244d88-d990-4570-91d4-6b25d70d08af')
+    @decorators.idempotent_id('98244d88-d990-4570-91d4-6b25d70d08af')
     def test_dhcp_stateful_fixedips_outrange(self):
         # NOTE: When port gets IP address from fixed IP range it
         # shall be checked if it's from subnets range.
@@ -322,7 +322,7 @@
                           fixed_ips=[{'subnet_id': subnet['id'],
                                       'ip_address': ip}])
 
-    @test.idempotent_id('57b8302b-cba9-4fbb-8835-9168df029051')
+    @decorators.idempotent_id('57b8302b-cba9-4fbb-8835-9168df029051')
     def test_dhcp_stateful_fixedips_duplicate(self):
         # NOTE: When port gets IP address from fixed IP range it
         # shall be checked if it's not duplicate.
@@ -352,7 +352,7 @@
         body = self.ports_client.show_port(port['port_id'])
         return subnet, body['port']
 
-    @test.idempotent_id('e98f65db-68f4-4330-9fea-abd8c5192d4d')
+    @decorators.idempotent_id('e98f65db-68f4-4330-9fea-abd8c5192d4d')
     def test_dhcp_stateful_router(self):
         # NOTE: With all options below the router interface shall
         # receive DHCPv6 IP address from allocation pool.
diff --git a/tempest/api/network/test_extensions.py b/tempest/api/network/test_extensions.py
index 84150b4..2662e9c 100644
--- a/tempest/api/network/test_extensions.py
+++ b/tempest/api/network/test_extensions.py
@@ -15,6 +15,7 @@
 
 
 from tempest.api.network import base
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -29,7 +30,7 @@
     """
 
     @test.attr(type='smoke')
-    @test.idempotent_id('ef28c7e6-e646-4979-9d67-deb207bc5564')
+    @decorators.idempotent_id('ef28c7e6-e646-4979-9d67-deb207bc5564')
     def test_list_show_extensions(self):
         # List available extensions for the project
         expected_alias = ['security-group', 'l3_agent_scheduler',
diff --git a/tempest/api/network/test_extra_dhcp_options.py b/tempest/api/network/test_extra_dhcp_options.py
index 062bc69..52507f9 100644
--- a/tempest/api/network/test_extra_dhcp_options.py
+++ b/tempest/api/network/test_extra_dhcp_options.py
@@ -15,6 +15,7 @@
 
 from tempest.api.network import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -54,7 +55,7 @@
             {'opt_value': cls.ip_server, 'opt_name': 'server-ip-address'}
         ]
 
-    @test.idempotent_id('d2c17063-3767-4a24-be4f-a23dbfa133c9')
+    @decorators.idempotent_id('d2c17063-3767-4a24-be4f-a23dbfa133c9')
     def test_create_list_port_with_extra_dhcp_options(self):
         # Create a port with Extra DHCP Options
         body = self.ports_client.create_port(
@@ -70,7 +71,7 @@
         self.assertTrue(port)
         self._confirm_extra_dhcp_options(port[0], self.extra_dhcp_opts)
 
-    @test.idempotent_id('9a6aebf4-86ee-4f47-b07a-7f7232c55607')
+    @decorators.idempotent_id('9a6aebf4-86ee-4f47-b07a-7f7232c55607')
     def test_update_show_port_with_extra_dhcp_options(self):
         # Update port with extra dhcp options
         name = data_utils.rand_name('new-port-name')
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index efe8982..23614d6 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -16,6 +16,7 @@
 from tempest.api.network import base
 from tempest.common.utils import net_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -61,7 +62,7 @@
             cls.create_port(cls.network)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('62595970-ab1c-4b7f-8fcc-fddfe55e8718')
+    @decorators.idempotent_id('62595970-ab1c-4b7f-8fcc-fddfe55e8718')
     def test_create_list_show_update_delete_floating_ip(self):
         # Creates a floating IP
         body = self.floating_ips_client.create_floatingip(
@@ -116,7 +117,7 @@
         self.assertIsNone(updated_floating_ip['fixed_ip_address'])
         self.assertIsNone(updated_floating_ip['router_id'])
 
-    @test.idempotent_id('e1f6bffd-442f-4668-b30e-df13f2705e77')
+    @decorators.idempotent_id('e1f6bffd-442f-4668-b30e-df13f2705e77')
     def test_floating_ip_delete_port(self):
         # Create a floating IP
         body = self.floating_ips_client.create_floatingip(
@@ -142,7 +143,7 @@
         self.assertIsNone(shown_floating_ip['fixed_ip_address'])
         self.assertIsNone(shown_floating_ip['router_id'])
 
-    @test.idempotent_id('1bb2f731-fe5a-4b8c-8409-799ade1bed4d')
+    @decorators.idempotent_id('1bb2f731-fe5a-4b8c-8409-799ade1bed4d')
     def test_floating_ip_update_different_router(self):
         # Associate a floating IP to a port on a router
         body = self.floating_ips_client.create_floatingip(
@@ -168,7 +169,7 @@
         self.assertIsNotNone(updated_floating_ip['fixed_ip_address'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('36de4bd0-f09c-43e3-a8e1-1decc1ffd3a5')
+    @decorators.idempotent_id('36de4bd0-f09c-43e3-a8e1-1decc1ffd3a5')
     def test_create_floating_ip_specifying_a_fixed_ip_address(self):
         body = self.floating_ips_client.create_floatingip(
             floating_network_id=self.ext_net_id,
@@ -185,7 +186,7 @@
             port_id=None)
         self.assertIsNone(floating_ip['floatingip']['port_id'])
 
-    @test.idempotent_id('45c4c683-ea97-41ef-9c51-5e9802f2f3d7')
+    @decorators.idempotent_id('45c4c683-ea97-41ef-9c51-5e9802f2f3d7')
     def test_create_update_floatingip_with_port_multiple_ip_address(self):
         # Find out ips that can be used for tests
         list_ips = net_utils.get_unused_ip_addresses(
diff --git a/tempest/api/network/test_floating_ips_negative.py b/tempest/api/network/test_floating_ips_negative.py
index 7ffc30f..9ccda05 100644
--- a/tempest/api/network/test_floating_ips_negative.py
+++ b/tempest/api/network/test_floating_ips_negative.py
@@ -16,6 +16,7 @@
 
 from tempest.api.network import base
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -49,7 +50,7 @@
         cls.port = cls.create_port(cls.network)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('22996ea8-4a81-4b27-b6e1-fa5df92fa5e8')
+    @decorators.idempotent_id('22996ea8-4a81-4b27-b6e1-fa5df92fa5e8')
     def test_create_floatingip_with_port_ext_net_unreachable(self):
         self.assertRaises(
             lib_exc.NotFound, self.floating_ips_client.create_floatingip,
@@ -58,7 +59,7 @@
                                       ['ip_address'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('50b9aeb4-9f0b-48ee-aa31-fa955a48ff54')
+    @decorators.idempotent_id('50b9aeb4-9f0b-48ee-aa31-fa955a48ff54')
     def test_create_floatingip_in_private_network(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.floating_ips_client.create_floatingip,
@@ -68,7 +69,7 @@
                                                     ['ip_address'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('6b3b8797-6d43-4191-985c-c48b773eb429')
+    @decorators.idempotent_id('6b3b8797-6d43-4191-985c-c48b773eb429')
     def test_associate_floatingip_port_ext_net_unreachable(self):
         # Create floating ip
         body = self.floating_ips_client.create_floatingip(
diff --git a/tempest/api/network/test_metering_extensions.py b/tempest/api/network/test_metering_extensions.py
index 299700f..42fa9e4 100644
--- a/tempest/api/network/test_metering_extensions.py
+++ b/tempest/api/network/test_metering_extensions.py
@@ -14,6 +14,7 @@
 
 from tempest.api.network import base
 from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -61,14 +62,14 @@
         rules = client.list_metering_label_rules(id=metering_label_rule_id)
         self.assertEqual(len(rules['metering_label_rules']), 0)
 
-    @test.idempotent_id('e2fb2f8c-45bf-429a-9f17-171c70444612')
+    @decorators.idempotent_id('e2fb2f8c-45bf-429a-9f17-171c70444612')
     def test_list_metering_labels(self):
         # Verify label filtering
         body = self.admin_metering_labels_client.list_metering_labels(id=33)
         metering_labels = body['metering_labels']
         self.assertEqual(0, len(metering_labels))
 
-    @test.idempotent_id('ec8e15ff-95d0-433b-b8a6-b466bddb1e50')
+    @decorators.idempotent_id('ec8e15ff-95d0-433b-b8a6-b466bddb1e50')
     def test_create_delete_metering_label_with_filters(self):
         # Creates a label
         name = data_utils.rand_name('metering-label-')
@@ -84,7 +85,7 @@
                   id=metering_label['id']))
         self.assertEqual(len(labels['metering_labels']), 1)
 
-    @test.idempotent_id('30abb445-0eea-472e-bd02-8649f54a5968')
+    @decorators.idempotent_id('30abb445-0eea-472e-bd02-8649f54a5968')
     def test_show_metering_label(self):
         # Verifies the details of a label
         body = self.admin_metering_labels_client.show_metering_label(
@@ -97,7 +98,7 @@
         self.assertEqual(self.metering_label['description'],
                          metering_label['description'])
 
-    @test.idempotent_id('cc832399-6681-493b-9d79-0202831a1281')
+    @decorators.idempotent_id('cc832399-6681-493b-9d79-0202831a1281')
     def test_list_metering_label_rules(self):
         client = self.admin_metering_label_rules_client
         # Verify rule filtering
@@ -105,7 +106,7 @@
         metering_label_rules = body['metering_label_rules']
         self.assertEqual(0, len(metering_label_rules))
 
-    @test.idempotent_id('f4d547cd-3aee-408f-bf36-454f8825e045')
+    @decorators.idempotent_id('f4d547cd-3aee-408f-bf36-454f8825e045')
     def test_create_delete_metering_label_rule_with_filters(self):
         # Creates a rule
         remote_ip_prefix = ("10.0.1.0/24" if self._ip_version == 4
@@ -123,7 +124,7 @@
         rules = client.list_metering_label_rules(id=metering_label_rule['id'])
         self.assertEqual(len(rules['metering_label_rules']), 1)
 
-    @test.idempotent_id('b7354489-96ea-41f3-9452-bace120fb4a7')
+    @decorators.idempotent_id('b7354489-96ea-41f3-9452-bace120fb4a7')
     def test_show_metering_label_rule(self):
         # Verifies the details of a rule
         client = self.admin_metering_label_rules_client
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 8e2f3f6..1426798 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -21,6 +21,7 @@
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -175,7 +176,7 @@
     """
 
     @test.attr(type='smoke')
-    @test.idempotent_id('0e269138-0da6-4efc-a46d-578161e7b221')
+    @decorators.idempotent_id('0e269138-0da6-4efc-a46d-578161e7b221')
     def test_create_update_delete_network_subnet(self):
         # Create a network
         network = self.create_network()
@@ -197,7 +198,7 @@
         self.assertEqual(updated_subnet['name'], new_name)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('2bf13842-c93f-4a69-83ed-717d2ec3b44e')
+    @decorators.idempotent_id('2bf13842-c93f-4a69-83ed-717d2ec3b44e')
     def test_show_network(self):
         # Verify the details of a network
         body = self.networks_client.show_network(self.network['id'])
@@ -205,7 +206,7 @@
         for key in ['id', 'name']:
             self.assertEqual(network[key], self.network[key])
 
-    @test.idempotent_id('867819bb-c4b6-45f7-acf9-90edcf70aa5e')
+    @decorators.idempotent_id('867819bb-c4b6-45f7-acf9-90edcf70aa5e')
     def test_show_network_fields(self):
         # Verify specific fields of a network
         fields = ['id', 'name']
@@ -221,7 +222,7 @@
         self.assertNotIn('project_id', network)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('f7ffdeda-e200-4a7a-bcbe-05716e86bf43')
+    @decorators.idempotent_id('f7ffdeda-e200-4a7a-bcbe-05716e86bf43')
     def test_list_networks(self):
         # Verify the network exists in the list of all networks
         body = self.networks_client.list_networks()
@@ -229,7 +230,7 @@
                     if network['id'] == self.network['id']]
         self.assertNotEmpty(networks, "Created network not found in the list")
 
-    @test.idempotent_id('6ae6d24f-9194-4869-9c85-c313cb20e080')
+    @decorators.idempotent_id('6ae6d24f-9194-4869-9c85-c313cb20e080')
     def test_list_networks_fields(self):
         # Verify specific fields of the networks
         fields = ['id', 'name']
@@ -242,7 +243,7 @@
             self.assertEqual(sorted(network.keys()), sorted(fields))
 
     @test.attr(type='smoke')
-    @test.idempotent_id('bd635d81-6030-4dd1-b3b9-31ba0cfdf6cc')
+    @decorators.idempotent_id('bd635d81-6030-4dd1-b3b9-31ba0cfdf6cc')
     def test_show_subnet(self):
         # Verify the details of a subnet
         body = self.subnets_client.show_subnet(self.subnet['id'])
@@ -252,7 +253,7 @@
             self.assertIn(key, subnet)
             self.assertEqual(subnet[key], self.subnet[key])
 
-    @test.idempotent_id('270fff0b-8bfc-411f-a184-1e8fd35286f0')
+    @decorators.idempotent_id('270fff0b-8bfc-411f-a184-1e8fd35286f0')
     def test_show_subnet_fields(self):
         # Verify specific fields of a subnet
         fields = ['id', 'network_id']
@@ -264,7 +265,7 @@
             self.assertEqual(subnet[field_name], self.subnet[field_name])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('db68ba48-f4ea-49e9-81d1-e367f6d0b20a')
+    @decorators.idempotent_id('db68ba48-f4ea-49e9-81d1-e367f6d0b20a')
     def test_list_subnets(self):
         # Verify the subnet exists in the list of all subnets
         body = self.subnets_client.list_subnets()
@@ -272,7 +273,7 @@
                    if subnet['id'] == self.subnet['id']]
         self.assertNotEmpty(subnets, "Created subnet not found in the list")
 
-    @test.idempotent_id('842589e3-9663-46b0-85e4-7f01273b0412')
+    @decorators.idempotent_id('842589e3-9663-46b0-85e4-7f01273b0412')
     def test_list_subnets_fields(self):
         # Verify specific fields of subnets
         fields = ['id', 'network_id']
@@ -282,7 +283,7 @@
         for subnet in subnets:
             self.assertEqual(sorted(subnet.keys()), sorted(fields))
 
-    @test.idempotent_id('f04f61a9-b7f3-4194-90b2-9bcf660d1bfe')
+    @decorators.idempotent_id('f04f61a9-b7f3-4194-90b2-9bcf660d1bfe')
     def test_delete_network_with_subnet(self):
         # Creates a network
         network = self.create_network()
@@ -301,35 +302,35 @@
         self.assertRaises(lib_exc.NotFound, self.subnets_client.show_subnet,
                           subnet_id)
 
-    @test.idempotent_id('d2d596e2-8e76-47a9-ac51-d4648009f4d3')
+    @decorators.idempotent_id('d2d596e2-8e76-47a9-ac51-d4648009f4d3')
     def test_create_delete_subnet_without_gateway(self):
         self._create_verify_delete_subnet()
 
-    @test.idempotent_id('9393b468-186d-496d-aa36-732348cd76e7')
+    @decorators.idempotent_id('9393b468-186d-496d-aa36-732348cd76e7')
     def test_create_delete_subnet_with_gw(self):
         self._create_verify_delete_subnet(
             **self.subnet_dict(['gateway']))
 
-    @test.idempotent_id('bec949c4-3147-4ba6-af5f-cd2306118404')
+    @decorators.idempotent_id('bec949c4-3147-4ba6-af5f-cd2306118404')
     def test_create_delete_subnet_with_allocation_pools(self):
         self._create_verify_delete_subnet(
             **self.subnet_dict(['allocation_pools']))
 
-    @test.idempotent_id('8217a149-0c6c-4cfb-93db-0486f707d13f')
+    @decorators.idempotent_id('8217a149-0c6c-4cfb-93db-0486f707d13f')
     def test_create_delete_subnet_with_gw_and_allocation_pools(self):
         self._create_verify_delete_subnet(**self.subnet_dict(
             ['gateway', 'allocation_pools']))
 
-    @test.idempotent_id('d830de0a-be47-468f-8f02-1fd996118289')
+    @decorators.idempotent_id('d830de0a-be47-468f-8f02-1fd996118289')
     def test_create_delete_subnet_with_host_routes_and_dns_nameservers(self):
         self._create_verify_delete_subnet(
             **self.subnet_dict(['host_routes', 'dns_nameservers']))
 
-    @test.idempotent_id('94ce038d-ff0a-4a4c-a56b-09da3ca0b55d')
+    @decorators.idempotent_id('94ce038d-ff0a-4a4c-a56b-09da3ca0b55d')
     def test_create_delete_subnet_with_dhcp_enabled(self):
         self._create_verify_delete_subnet(enable_dhcp=True)
 
-    @test.idempotent_id('3d3852eb-3009-49ec-97ac-5ce83b73010a')
+    @decorators.idempotent_id('3d3852eb-3009-49ec-97ac-5ce83b73010a')
     def test_update_subnet_gw_dns_host_routes_dhcp(self):
         network = self.create_network()
         self.addCleanup(self._delete_network, network)
@@ -362,14 +363,14 @@
 
         self._compare_resource_attrs(updated_subnet, kwargs)
 
-    @test.idempotent_id('a4d9ec4c-0306-4111-a75c-db01a709030b')
+    @decorators.idempotent_id('a4d9ec4c-0306-4111-a75c-db01a709030b')
     def test_create_delete_subnet_all_attributes(self):
         self._create_verify_delete_subnet(
             enable_dhcp=True,
             **self.subnet_dict(['gateway', 'host_routes', 'dns_nameservers']))
 
     @test.attr(type='smoke')
-    @test.idempotent_id('af774677-42a9-4e4b-bb58-16fe6a5bc1ec')
+    @decorators.idempotent_id('af774677-42a9-4e4b-bb58-16fe6a5bc1ec')
     @test.requires_ext(extension='external-net', service='network')
     @testtools.skipUnless(CONF.network.public_network_id,
                           'The public_network_id option must be specified.')
@@ -391,7 +392,7 @@
             network_id=CONF.network.public_network_id)
         self.assertEmpty(body['subnets'], "Public subnets visible")
 
-    @test.idempotent_id('c72c1c0c-2193-4aca-ccc4-b1442640bbbb')
+    @decorators.idempotent_id('c72c1c0c-2193-4aca-ccc4-b1442640bbbb')
     @test.requires_ext(extension="standard-attr-description",
                        service="network")
     def test_create_update_network_description(self):
@@ -453,7 +454,7 @@
             self.assertNotIn(n['id'], ports_list)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('d4f9024d-1e28-4fc1-a6b1-25dbc6fa11e2')
+    @decorators.idempotent_id('d4f9024d-1e28-4fc1-a6b1-25dbc6fa11e2')
     def test_bulk_create_delete_network(self):
         # Creates 2 networks in one request
         network_list = [{'name': data_utils.rand_name('network-')},
@@ -469,7 +470,7 @@
             self.assertIn(n['id'], networks_list)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('8936533b-c0aa-4f29-8e53-6cc873aec489')
+    @decorators.idempotent_id('8936533b-c0aa-4f29-8e53-6cc873aec489')
     def test_bulk_create_delete_subnet(self):
         networks = [self.create_network(), self.create_network()]
         # Creates 2 subnets in one request
@@ -504,7 +505,7 @@
             self.assertIn(n['id'], subnets_list)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('48037ff2-e889-4c3b-b86a-8e3f34d2d060')
+    @decorators.idempotent_id('48037ff2-e889-4c3b-b86a-8e3f34d2d060')
     def test_bulk_create_delete_port(self):
         networks = [self.create_network(), self.create_network()]
         # Creates 2 ports in one request
@@ -537,7 +538,7 @@
 class NetworksIpV6Test(NetworksTest):
     _ip_version = 6
 
-    @test.idempotent_id('e41a4888-65a6-418c-a095-f7c2ef4ad59a')
+    @decorators.idempotent_id('e41a4888-65a6-418c-a095-f7c2ef4ad59a')
     def test_create_delete_subnet_with_gw(self):
         net = netaddr.IPNetwork(CONF.network.project_network_v6_cidr)
         gateway = str(netaddr.IPAddress(net.first + 2))
@@ -546,7 +547,7 @@
         # Verifies Subnet GW in IPv6
         self.assertEqual(subnet['gateway_ip'], gateway)
 
-    @test.idempotent_id('ebb4fd95-524f-46af-83c1-0305b239338f')
+    @decorators.idempotent_id('ebb4fd95-524f-46af-83c1-0305b239338f')
     def test_create_delete_subnet_with_default_gw(self):
         net = netaddr.IPNetwork(CONF.network.project_network_v6_cidr)
         gateway_ip = str(netaddr.IPAddress(net.first + 1))
@@ -555,7 +556,7 @@
         # Verifies Subnet GW in IPv6
         self.assertEqual(subnet['gateway_ip'], gateway_ip)
 
-    @test.idempotent_id('a9653883-b2a4-469b-8c3c-4518430a7e55')
+    @decorators.idempotent_id('a9653883-b2a4-469b-8c3c-4518430a7e55')
     def test_create_list_subnet_with_no_gw64_one_network(self):
         network = self.create_network()
         ipv6_gateway = self.subnet_dict(['gateway'])['gateway']
@@ -594,20 +595,20 @@
             raise cls.skipException("IPv6 extended attributes for "
                                     "subnets not available")
 
-    @test.idempotent_id('da40cd1b-a833-4354-9a85-cd9b8a3b74ca')
+    @decorators.idempotent_id('da40cd1b-a833-4354-9a85-cd9b8a3b74ca')
     def test_create_delete_subnet_with_v6_attributes_stateful(self):
         self._create_verify_delete_subnet(
             gateway=self._subnet_data[self._ip_version]['gateway'],
             ipv6_ra_mode='dhcpv6-stateful',
             ipv6_address_mode='dhcpv6-stateful')
 
-    @test.idempotent_id('176b030f-a923-4040-a755-9dc94329e60c')
+    @decorators.idempotent_id('176b030f-a923-4040-a755-9dc94329e60c')
     def test_create_delete_subnet_with_v6_attributes_slaac(self):
         self._create_verify_delete_subnet(
             ipv6_ra_mode='slaac',
             ipv6_address_mode='slaac')
 
-    @test.idempotent_id('7d410310-8c86-4902-adf9-865d08e31adb')
+    @decorators.idempotent_id('7d410310-8c86-4902-adf9-865d08e31adb')
     def test_create_delete_subnet_with_v6_attributes_stateless(self):
         self._create_verify_delete_subnet(
             ipv6_ra_mode='dhcpv6-stateless',
@@ -633,7 +634,7 @@
             self.networks_client.delete_network,
             slaac_network['id'])
 
-    @test.idempotent_id('88554555-ebf8-41ef-9300-4926d45e06e9')
+    @decorators.idempotent_id('88554555-ebf8-41ef-9300-4926d45e06e9')
     def test_create_delete_slaac_subnet_with_ports(self):
         """Test deleting subnet with SLAAC ports
 
@@ -643,7 +644,7 @@
         """
         self._test_delete_subnet_with_ports("slaac")
 
-    @test.idempotent_id('2de6ab5a-fcf0-4144-9813-f91a940291f1')
+    @decorators.idempotent_id('2de6ab5a-fcf0-4144-9813-f91a940291f1')
     def test_create_delete_stateless_subnet_with_ports(self):
         """Test deleting subnet with DHCPv6 stateless ports
 
diff --git a/tempest/api/network/test_networks_negative.py b/tempest/api/network/test_networks_negative.py
index d87c2b6..3cc6fb7 100644
--- a/tempest/api/network/test_networks_negative.py
+++ b/tempest/api/network/test_networks_negative.py
@@ -16,6 +16,7 @@
 
 from tempest.api.network 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
 
@@ -23,28 +24,28 @@
 class NetworksNegativeTestJSON(base.BaseNetworkTest):
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9293e937-824d-42d2-8d5b-e985ea67002a')
+    @decorators.idempotent_id('9293e937-824d-42d2-8d5b-e985ea67002a')
     def test_show_non_existent_network(self):
         non_exist_id = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound, self.networks_client.show_network,
                           non_exist_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d746b40c-5e09-4043-99f7-cba1be8b70df')
+    @decorators.idempotent_id('d746b40c-5e09-4043-99f7-cba1be8b70df')
     def test_show_non_existent_subnet(self):
         non_exist_id = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound, self.subnets_client.show_subnet,
                           non_exist_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a954861d-cbfd-44e8-b0a9-7fab111f235d')
+    @decorators.idempotent_id('a954861d-cbfd-44e8-b0a9-7fab111f235d')
     def test_show_non_existent_port(self):
         non_exist_id = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound, self.ports_client.show_port,
                           non_exist_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('98bfe4e3-574e-4012-8b17-b2647063de87')
+    @decorators.idempotent_id('98bfe4e3-574e-4012-8b17-b2647063de87')
     def test_update_non_existent_network(self):
         non_exist_id = data_utils.rand_uuid()
         self.assertRaises(
@@ -52,7 +53,7 @@
             non_exist_id, name="new_name")
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('03795047-4a94-4120-a0a1-bd376e36fd4e')
+    @decorators.idempotent_id('03795047-4a94-4120-a0a1-bd376e36fd4e')
     def test_delete_non_existent_network(self):
         non_exist_id = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound,
@@ -60,21 +61,21 @@
                           non_exist_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('1cc47884-ac52-4415-a31c-e7ce5474a868')
+    @decorators.idempotent_id('1cc47884-ac52-4415-a31c-e7ce5474a868')
     def test_update_non_existent_subnet(self):
         non_exist_id = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound, self.subnets_client.update_subnet,
                           non_exist_id, name='new_name')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a176c859-99fb-42ec-a208-8a85b552a239')
+    @decorators.idempotent_id('a176c859-99fb-42ec-a208-8a85b552a239')
     def test_delete_non_existent_subnet(self):
         non_exist_id = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound,
                           self.subnets_client.delete_subnet, non_exist_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('13d3b106-47e6-4b9b-8d53-dae947f092fe')
+    @decorators.idempotent_id('13d3b106-47e6-4b9b-8d53-dae947f092fe')
     def test_create_port_on_non_existent_network(self):
         non_exist_net_id = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound,
@@ -82,14 +83,14 @@
                           network_id=non_exist_net_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('cf8eef21-4351-4f53-adcd-cc5cb1e76b92')
+    @decorators.idempotent_id('cf8eef21-4351-4f53-adcd-cc5cb1e76b92')
     def test_update_non_existent_port(self):
         non_exist_port_id = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound, self.ports_client.update_port,
                           non_exist_port_id, name='new_name')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('49ec2bbd-ac2e-46fd-8054-798e679ff894')
+    @decorators.idempotent_id('49ec2bbd-ac2e-46fd-8054-798e679ff894')
     def test_delete_non_existent_port(self):
         non_exist_port_id = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound,
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index e7153f0..3908aae 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.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.lib import exceptions
 from tempest import test
 
@@ -52,7 +53,7 @@
         self.assertFalse(port_id in [n['id'] for n in ports_list])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('c72c1c0c-2193-4aca-aaa4-b1442640f51c')
+    @decorators.idempotent_id('c72c1c0c-2193-4aca-aaa4-b1442640f51c')
     def test_create_update_delete_port(self):
         # Verify port creation
         body = self.ports_client.create_port(network_id=self.network['id'])
@@ -69,7 +70,7 @@
         self.assertEqual(updated_port['name'], new_name)
         self.assertFalse(updated_port['admin_state_up'])
 
-    @test.idempotent_id('67f1b811-f8db-43e2-86bd-72c074d4a42c')
+    @decorators.idempotent_id('67f1b811-f8db-43e2-86bd-72c074d4a42c')
     def test_create_bulk_port(self):
         network1 = self.network
         network2 = self.create_network()
@@ -100,7 +101,7 @@
         return cidr
 
     @test.attr(type='smoke')
-    @test.idempotent_id('0435f278-40ae-48cb-a404-b8a087bc09b1')
+    @decorators.idempotent_id('0435f278-40ae-48cb-a404-b8a087bc09b1')
     def test_create_port_in_allowed_allocation_pools(self):
         network = self.create_network()
         net_id = network['id']
@@ -125,7 +126,7 @@
         self.assertIn(ip_address, ip_range)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('c9a685bd-e83f-499c-939f-9f7863ca259f')
+    @decorators.idempotent_id('c9a685bd-e83f-499c-939f-9f7863ca259f')
     def test_show_port(self):
         # Verify the details of port
         body = self.ports_client.show_port(self.port['id'])
@@ -141,7 +142,7 @@
                                               'created_at',
                                               'updated_at']))
 
-    @test.idempotent_id('45fcdaf2-dab0-4c13-ac6c-fcddfb579dbd')
+    @decorators.idempotent_id('45fcdaf2-dab0-4c13-ac6c-fcddfb579dbd')
     def test_show_port_fields(self):
         # Verify specific fields of a port
         fields = ['id', 'mac_address']
@@ -153,7 +154,7 @@
             self.assertEqual(port[field_name], self.port[field_name])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('cf95b358-3e92-4a29-a148-52445e1ac50e')
+    @decorators.idempotent_id('cf95b358-3e92-4a29-a148-52445e1ac50e')
     def test_list_ports(self):
         # Verify the port exists in the list of all ports
         body = self.ports_client.list_ports()
@@ -161,7 +162,7 @@
                  if port['id'] == self.port['id']]
         self.assertNotEmpty(ports, "Created port not found in the list")
 
-    @test.idempotent_id('e7fe260b-1e79-4dd3-86d9-bec6a7959fc5')
+    @decorators.idempotent_id('e7fe260b-1e79-4dd3-86d9-bec6a7959fc5')
     def test_port_list_filter_by_ip(self):
         # Create network and subnet
         network = self.create_network()
@@ -192,7 +193,7 @@
         self.assertIn(port_1_fixed_ip, port_ips)
         self.assertIn(network['id'], port_net_ids)
 
-    @test.idempotent_id('5ad01ed0-0e6e-4c5d-8194-232801b15c72')
+    @decorators.idempotent_id('5ad01ed0-0e6e-4c5d-8194-232801b15c72')
     def test_port_list_filter_by_router_id(self):
         # Create a router
         network = self.create_network()
@@ -214,7 +215,7 @@
         self.assertEqual(ports[0]['id'], port['port']['id'])
         self.assertEqual(ports[0]['device_id'], router['id'])
 
-    @test.idempotent_id('ff7f117f-f034-4e0e-abff-ccef05c454b4')
+    @decorators.idempotent_id('ff7f117f-f034-4e0e-abff-ccef05c454b4')
     def test_list_ports_fields(self):
         # Verify specific fields of ports
         fields = ['id', 'mac_address']
@@ -225,7 +226,7 @@
         for port in ports:
             self.assertEqual(sorted(fields), sorted(port.keys()))
 
-    @test.idempotent_id('63aeadd4-3b49-427f-a3b1-19ca81f06270')
+    @decorators.idempotent_id('63aeadd4-3b49-427f-a3b1-19ca81f06270')
     def test_create_update_port_with_second_ip(self):
         # Create a network with two subnets
         network = self.create_network()
@@ -307,7 +308,7 @@
         for security_group in security_groups_list:
             self.assertIn(security_group, port_show['security_groups'])
 
-    @test.idempotent_id('58091b66-4ff4-4cc1-a549-05d60c7acd1a')
+    @decorators.idempotent_id('58091b66-4ff4-4cc1-a549-05d60c7acd1a')
     @testtools.skipUnless(
         test.is_extension_enabled('security-group', 'network'),
         'security-group extension not enabled.')
@@ -315,7 +316,7 @@
         self._update_port_with_security_groups(
             [data_utils.rand_name('secgroup')])
 
-    @test.idempotent_id('edf6766d-3d40-4621-bc6e-2521a44c257d')
+    @decorators.idempotent_id('edf6766d-3d40-4621-bc6e-2521a44c257d')
     @testtools.skipUnless(
         test.is_extension_enabled('security-group', 'network'),
         'security-group extension not enabled.')
@@ -324,7 +325,7 @@
             [data_utils.rand_name('secgroup'),
              data_utils.rand_name('secgroup')])
 
-    @test.idempotent_id('13e95171-6cbd-489c-9d7c-3f9c58215c18')
+    @decorators.idempotent_id('13e95171-6cbd-489c-9d7c-3f9c58215c18')
     def test_create_show_delete_port_user_defined_mac(self):
         # Create a port for a legal mac
         body = self.ports_client.create_port(network_id=self.network['id'])
@@ -342,7 +343,7 @@
                          show_port['mac_address'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('4179dcb9-1382-4ced-84fe-1b91c54f5735')
+    @decorators.idempotent_id('4179dcb9-1382-4ced-84fe-1b91c54f5735')
     @testtools.skipUnless(
         test.is_extension_enabled('security-group', 'network'),
         'security-group extension not enabled.')
@@ -365,7 +366,7 @@
         cls.network = cls.create_network()
         cls.host_id = socket.gethostname()
 
-    @test.idempotent_id('8e8569c1-9ac7-44db-8bc1-f5fb2814f29b')
+    @decorators.idempotent_id('8e8569c1-9ac7-44db-8bc1-f5fb2814f29b')
     def test_create_port_binding_ext_attr(self):
         post_body = {"network_id": self.network['id'],
                      "binding:host_id": self.host_id}
@@ -376,7 +377,7 @@
         self.assertIsNotNone(host_id)
         self.assertEqual(self.host_id, host_id)
 
-    @test.idempotent_id('6f6c412c-711f-444d-8502-0ac30fbf5dd5')
+    @decorators.idempotent_id('6f6c412c-711f-444d-8502-0ac30fbf5dd5')
     def test_update_port_binding_ext_attr(self):
         post_body = {"network_id": self.network['id']}
         body = self.admin_ports_client.create_port(**post_body)
@@ -389,7 +390,7 @@
         self.assertIsNotNone(host_id)
         self.assertEqual(self.host_id, host_id)
 
-    @test.idempotent_id('1c82a44a-6c6e-48ff-89e1-abe7eaf8f9f8')
+    @decorators.idempotent_id('1c82a44a-6c6e-48ff-89e1-abe7eaf8f9f8')
     def test_list_ports_binding_ext_attr(self):
         # Create a new port
         post_body = {"network_id": self.network['id']}
@@ -414,7 +415,7 @@
                          '%s' % (port['id'], ports_list))
         self.assertEqual(self.host_id, listed_port[0]['binding:host_id'])
 
-    @test.idempotent_id('b54ac0ff-35fc-4c79-9ca3-c7dbd4ea4f13')
+    @decorators.idempotent_id('b54ac0ff-35fc-4c79-9ca3-c7dbd4ea4f13')
     def test_show_port_binding_ext_attr(self):
         body = self.admin_ports_client.create_port(
             network_id=self.network['id'])
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 101e4dd..524ab9e 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -18,6 +18,7 @@
 from tempest.api.network import base_routers as base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -40,7 +41,7 @@
                            CONF.network.project_network_v6_cidr)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('f64403e2-8483-4b34-8ccd-b09a87bcc68c')
+    @decorators.idempotent_id('f64403e2-8483-4b34-8ccd-b09a87bcc68c')
     def test_create_show_list_update_delete_router(self):
         # Create a router
         router = self._create_router(
@@ -69,7 +70,7 @@
             router['id'])['router']
         self.assertEqual(router_show['name'], updated_name)
 
-    @test.idempotent_id('e54dd3a3-4352-4921-b09d-44369ae17397')
+    @decorators.idempotent_id('e54dd3a3-4352-4921-b09d-44369ae17397')
     def test_create_router_setting_project_id(self):
         # Test creating router from admin user setting project_id.
         project = data_utils.rand_name('test_tenant_')
@@ -86,7 +87,7 @@
                         create_body['router']['id'])
         self.assertEqual(project_id, create_body['router']['tenant_id'])
 
-    @test.idempotent_id('847257cc-6afd-4154-b8fb-af49f5670ce8')
+    @decorators.idempotent_id('847257cc-6afd-4154-b8fb-af49f5670ce8')
     @test.requires_ext(extension='ext-gw-mode', service='network')
     def test_create_router_with_default_snat_value(self):
         # Create a router with default snat rule
@@ -96,7 +97,7 @@
             router['id'], {'network_id': CONF.network.public_network_id,
                            'enable_snat': True})
 
-    @test.idempotent_id('ea74068d-09e9-4fd7-8995-9b6a1ace920f')
+    @decorators.idempotent_id('ea74068d-09e9-4fd7-8995-9b6a1ace920f')
     @test.requires_ext(extension='ext-gw-mode', service='network')
     def test_create_router_with_snat_explicit(self):
         name = data_utils.rand_name('snat-router')
@@ -115,7 +116,7 @@
                                         exp_ext_gw_info=external_gateway_info)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('b42e6e39-2e37-49cc-a6f4-8467e940900a')
+    @decorators.idempotent_id('b42e6e39-2e37-49cc-a6f4-8467e940900a')
     def test_add_remove_router_interface_with_subnet_id(self):
         network = self.create_network()
         subnet = self.create_subnet(network)
@@ -134,7 +135,7 @@
                          router['id'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('2b7d2f37-6748-4d78-92e5-1d590234f0d5')
+    @decorators.idempotent_id('2b7d2f37-6748-4d78-92e5-1d590234f0d5')
     def test_add_remove_router_interface_with_port_id(self):
         network = self.create_network()
         self.create_subnet(network)
@@ -182,7 +183,7 @@
             subnet_id = fixed_ip['subnet_id']
             self.assertIn(subnet_id, public_subnet_ids)
 
-    @test.idempotent_id('6cc285d8-46bf-4f36-9b1a-783e3008ba79')
+    @decorators.idempotent_id('6cc285d8-46bf-4f36-9b1a-783e3008ba79')
     def test_update_router_set_gateway(self):
         router = self._create_router()
         self.routers_client.update_router(
@@ -195,7 +196,7 @@
             {'network_id': CONF.network.public_network_id})
         self._verify_gateway_port(router['id'])
 
-    @test.idempotent_id('b386c111-3b21-466d-880c-5e72b01e1a33')
+    @decorators.idempotent_id('b386c111-3b21-466d-880c-5e72b01e1a33')
     @test.requires_ext(extension='ext-gw-mode', service='network')
     def test_update_router_set_gateway_with_snat_explicit(self):
         router = self._create_router()
@@ -210,7 +211,7 @@
              'enable_snat': True})
         self._verify_gateway_port(router['id'])
 
-    @test.idempotent_id('96536bc7-8262-4fb2-9967-5c46940fa279')
+    @decorators.idempotent_id('96536bc7-8262-4fb2-9967-5c46940fa279')
     @test.requires_ext(extension='ext-gw-mode', service='network')
     def test_update_router_set_gateway_without_snat(self):
         router = self._create_router()
@@ -225,7 +226,7 @@
              'enable_snat': False})
         self._verify_gateway_port(router['id'])
 
-    @test.idempotent_id('ad81b7ee-4f81-407b-a19c-17e623f763e8')
+    @decorators.idempotent_id('ad81b7ee-4f81-407b-a19c-17e623f763e8')
     def test_update_router_unset_gateway(self):
         router = self._create_router(
             external_network_id=CONF.network.public_network_id)
@@ -238,7 +239,7 @@
             device_id=router['id'])
         self.assertFalse(list_body['ports'])
 
-    @test.idempotent_id('f2faf994-97f4-410b-a831-9bc977b64374')
+    @decorators.idempotent_id('f2faf994-97f4-410b-a831-9bc977b64374')
     @test.requires_ext(extension='ext-gw-mode', service='network')
     def test_update_router_reset_gateway_without_snat(self):
         router = self._create_router(
@@ -254,7 +255,7 @@
              'enable_snat': False})
         self._verify_gateway_port(router['id'])
 
-    @test.idempotent_id('c86ac3a8-50bd-4b00-a6b8-62af84a0765c')
+    @decorators.idempotent_id('c86ac3a8-50bd-4b00-a6b8-62af84a0765c')
     @test.requires_ext(extension='extraroute', service='network')
     def test_update_delete_extra_route(self):
         # Create different cidr for each subnet to avoid cidr duplicate
@@ -316,7 +317,7 @@
     def _delete_extra_routes(self, router_id):
         self.routers_client.update_router(router_id, routes=None)
 
-    @test.idempotent_id('a8902683-c788-4246-95c7-ad9c6d63a4d9')
+    @decorators.idempotent_id('a8902683-c788-4246-95c7-ad9c6d63a4d9')
     def test_update_router_admin_state(self):
         router = self._create_router()
         self.assertFalse(router['admin_state_up'])
@@ -328,7 +329,7 @@
         self.assertTrue(show_body['router']['admin_state_up'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('802c73c9-c937-4cef-824b-2191e24a6aab')
+    @decorators.idempotent_id('802c73c9-c937-4cef-824b-2191e24a6aab')
     def test_add_multiple_router_interfaces(self):
         network01 = self.create_network(
             network_name=data_utils.rand_name('router-network01-'))
@@ -347,7 +348,7 @@
         self._verify_router_interface(router['id'], subnet02['id'],
                                       interface02['port_id'])
 
-    @test.idempotent_id('96522edf-b4b5-45d9-8443-fa11c26e6eff')
+    @decorators.idempotent_id('96522edf-b4b5-45d9-8443-fa11c26e6eff')
     def test_router_interface_port_update_with_fixed_ip(self):
         network = self.create_network()
         subnet = self.create_subnet(network)
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index b3983de..2bda431 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -18,6 +18,7 @@
 from tempest.api.network import base_routers as 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
 
@@ -44,7 +45,7 @@
                            CONF.network.project_network_v6_cidr)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('37a94fc0-a834-45b9-bd23-9a81d2fd1e22')
+    @decorators.idempotent_id('37a94fc0-a834-45b9-bd23-9a81d2fd1e22')
     def test_router_add_gateway_invalid_network_returns_404(self):
         self.assertRaises(lib_exc.NotFound,
                           self.routers_client.update_router,
@@ -53,7 +54,7 @@
                               'network_id': self.router['id']})
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('11836a18-0b15-4327-a50b-f0d9dc66bddd')
+    @decorators.idempotent_id('11836a18-0b15-4327-a50b-f0d9dc66bddd')
     def test_router_add_gateway_net_not_external_returns_400(self):
         alt_network = self.create_network()
         sub_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
@@ -65,7 +66,7 @@
                               'network_id': alt_network['id']})
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('957751a3-3c68-4fa2-93b6-eb52ea10db6e')
+    @decorators.idempotent_id('957751a3-3c68-4fa2-93b6-eb52ea10db6e')
     def test_add_router_interfaces_on_overlapping_subnets_returns_400(self):
         network01 = self.create_network(
             network_name=data_utils.rand_name('router-network01-'))
@@ -81,7 +82,7 @@
                           subnet02['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('04df80f9-224d-47f5-837a-bf23e33d1c20')
+    @decorators.idempotent_id('04df80f9-224d-47f5-837a-bf23e33d1c20')
     def test_router_remove_interface_in_use_returns_409(self):
         self.routers_client.add_router_interface(self.router['id'],
                                                  subnet_id=self.subnet['id'])
@@ -90,21 +91,21 @@
                           self.router['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('c2a70d72-8826-43a7-8208-0209e6360c47')
+    @decorators.idempotent_id('c2a70d72-8826-43a7-8208-0209e6360c47')
     def test_show_non_existent_router_returns_404(self):
         router = data_utils.rand_name('non_exist_router')
         self.assertRaises(lib_exc.NotFound, self.routers_client.show_router,
                           router)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('b23d1569-8b0c-4169-8d4b-6abd34fad5c7')
+    @decorators.idempotent_id('b23d1569-8b0c-4169-8d4b-6abd34fad5c7')
     def test_update_non_existent_router_returns_404(self):
         router = data_utils.rand_name('non_exist_router')
         self.assertRaises(lib_exc.NotFound, self.routers_client.update_router,
                           router, name="new_name")
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('c7edc5ad-d09d-41e6-a344-5c0c31e2e3e4')
+    @decorators.idempotent_id('c7edc5ad-d09d-41e6-a344-5c0c31e2e3e4')
     def test_delete_non_existent_router_returns_404(self):
         router = data_utils.rand_name('non_exist_router')
         self.assertRaises(lib_exc.NotFound, self.routers_client.delete_router,
@@ -132,7 +133,7 @@
         cls.subnet = cls.create_subnet(cls.network)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('4990b055-8fc7-48ab-bba7-aa28beaad0b9')
+    @decorators.idempotent_id('4990b055-8fc7-48ab-bba7-aa28beaad0b9')
     def test_router_create_tenant_distributed_returns_forbidden(self):
         self.assertRaises(lib_exc.Forbidden, self.create_router,
                           distributed=True)
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index be01852..607baf0 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -16,6 +16,7 @@
 from tempest.api.network import base_security_groups as base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -67,7 +68,7 @@
                              (key, value))
 
     @test.attr(type='smoke')
-    @test.idempotent_id('e30abd17-fef9-4739-8617-dc26da88e686')
+    @decorators.idempotent_id('e30abd17-fef9-4739-8617-dc26da88e686')
     def test_list_security_groups(self):
         # Verify the security group belonging to project exist in list
         body = self.security_groups_client.list_security_groups()
@@ -80,7 +81,7 @@
         self.assertIsNotNone(found, msg)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('bfd128e5-3c92-44b6-9d66-7fe29d22c802')
+    @decorators.idempotent_id('bfd128e5-3c92-44b6-9d66-7fe29d22c802')
     def test_create_list_update_show_delete_security_group(self):
         group_create_body, name = self._create_security_group()
 
@@ -109,7 +110,7 @@
                          new_description)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('cfb99e0e-7410-4a3d-8a0c-959a63ee77e9')
+    @decorators.idempotent_id('cfb99e0e-7410-4a3d-8a0c-959a63ee77e9')
     def test_create_show_delete_security_group_rule(self):
         group_create_body, _ = self._create_security_group()
 
@@ -142,7 +143,7 @@
             self.assertIn(rule_create_body['security_group_rule']['id'],
                           rule_list)
 
-    @test.idempotent_id('87dfbcf9-1849-43ea-b1e4-efa3eeae9f71')
+    @decorators.idempotent_id('87dfbcf9-1849-43ea-b1e4-efa3eeae9f71')
     def test_create_security_group_rule_with_additional_args(self):
         """Verify security group rule with additional arguments works.
 
@@ -160,7 +161,7 @@
                                                 port_range_min,
                                                 port_range_max)
 
-    @test.idempotent_id('c9463db8-b44d-4f52-b6c0-8dbda99f26ce')
+    @decorators.idempotent_id('c9463db8-b44d-4f52-b6c0-8dbda99f26ce')
     def test_create_security_group_rule_with_icmp_type_code(self):
         """Verify security group rule for icmp protocol works.
 
@@ -180,7 +181,7 @@
                                                     self.ethertype, protocol,
                                                     icmp_type, icmp_code)
 
-    @test.idempotent_id('c2ed2deb-7a0c-44d8-8b4c-a5825b5c310b')
+    @decorators.idempotent_id('c2ed2deb-7a0c-44d8-8b4c-a5825b5c310b')
     def test_create_security_group_rule_with_remote_group_id(self):
         # Verify creating security group rule with remote_group_id works
         sg1_body, _ = self._create_security_group()
@@ -198,7 +199,7 @@
                                                 port_range_max,
                                                 remote_group_id=remote_id)
 
-    @test.idempotent_id('16459776-5da2-4634-bce4-4b55ee3ec188')
+    @decorators.idempotent_id('16459776-5da2-4634-bce4-4b55ee3ec188')
     def test_create_security_group_rule_with_remote_ip_prefix(self):
         # Verify creating security group rule with remote_ip_prefix works
         sg1_body, _ = self._create_security_group()
@@ -215,7 +216,7 @@
                                                 port_range_max,
                                                 remote_ip_prefix=ip_prefix)
 
-    @test.idempotent_id('0a307599-6655-4220-bebc-fd70c64f2290')
+    @decorators.idempotent_id('0a307599-6655-4220-bebc-fd70c64f2290')
     def test_create_security_group_rule_with_protocol_integer_value(self):
         # Verify creating security group rule with the
         # protocol as integer value
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index a3b0a82..f46b873 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -16,6 +16,7 @@
 from tempest.api.network import base_security_groups as base
 from tempest import config
 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
 
@@ -33,7 +34,7 @@
             raise cls.skipException(msg)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('424fd5c3-9ddc-486a-b45f-39bf0c820fc6')
+    @decorators.idempotent_id('424fd5c3-9ddc-486a-b45f-39bf0c820fc6')
     def test_show_non_existent_security_group(self):
         non_exist_id = data_utils.rand_uuid()
         self.assertRaises(
@@ -41,7 +42,7 @@
             non_exist_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('4c094c09-000b-4e41-8100-9617600c02a6')
+    @decorators.idempotent_id('4c094c09-000b-4e41-8100-9617600c02a6')
     def test_show_non_existent_security_group_rule(self):
         non_exist_id = data_utils.rand_uuid()
         self.assertRaises(
@@ -50,7 +51,7 @@
             non_exist_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('1f1bb89d-5664-4956-9fcd-83ee0fa603df')
+    @decorators.idempotent_id('1f1bb89d-5664-4956-9fcd-83ee0fa603df')
     def test_delete_non_existent_security_group(self):
         non_exist_id = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound,
@@ -59,7 +60,7 @@
                           )
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('981bdc22-ce48-41ed-900a-73148b583958')
+    @decorators.idempotent_id('981bdc22-ce48-41ed-900a-73148b583958')
     def test_create_security_group_rule_with_bad_protocol(self):
         group_create_body, _ = self._create_security_group()
 
@@ -72,7 +73,7 @@
             protocol=pname, direction='ingress', ethertype=self.ethertype)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5f8daf69-3c5f-4aaa-88c9-db1d66f68679')
+    @decorators.idempotent_id('5f8daf69-3c5f-4aaa-88c9-db1d66f68679')
     def test_create_security_group_rule_with_bad_remote_ip_prefix(self):
         group_create_body, _ = self._create_security_group()
 
@@ -87,7 +88,7 @@
                 remote_ip_prefix=remote_ip_prefix)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('4bf786fd-2f02-443c-9716-5b98e159a49a')
+    @decorators.idempotent_id('4bf786fd-2f02-443c-9716-5b98e159a49a')
     def test_create_security_group_rule_with_non_existent_remote_groupid(self):
         group_create_body, _ = self._create_security_group()
         non_exist_id = data_utils.rand_uuid()
@@ -103,7 +104,7 @@
                 remote_group_id=remote_group_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('b5c4b247-6b02-435b-b088-d10d45650881')
+    @decorators.idempotent_id('b5c4b247-6b02-435b-b088-d10d45650881')
     def test_create_security_group_rule_with_remote_ip_and_group(self):
         sg1_body, _ = self._create_security_group()
         sg2_body, _ = self._create_security_group()
@@ -119,7 +120,7 @@
             remote_group_id=sg2_body['security_group']['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5666968c-fff3-40d6-9efc-df1c8bd01abb')
+    @decorators.idempotent_id('5666968c-fff3-40d6-9efc-df1c8bd01abb')
     def test_create_security_group_rule_with_bad_ethertype(self):
         group_create_body, _ = self._create_security_group()
 
@@ -132,7 +133,7 @@
             protocol='udp', direction='ingress', ethertype=ethertype)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0d9c7791-f2ad-4e2f-ac73-abf2373b0d2d')
+    @decorators.idempotent_id('0d9c7791-f2ad-4e2f-ac73-abf2373b0d2d')
     def test_create_security_group_rule_with_invalid_ports(self):
         group_create_body, _ = self._create_security_group()
 
@@ -166,7 +167,7 @@
             self.assertIn(msg, str(ex))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('2323061e-9fbf-4eb0-b547-7e8fafc90849')
+    @decorators.idempotent_id('2323061e-9fbf-4eb0-b547-7e8fafc90849')
     def test_create_additional_default_security_group_fails(self):
         # Create security group named 'default', it should be failed.
         name = 'default'
@@ -175,7 +176,7 @@
                           name=name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('8fde898f-ce88-493b-adc9-4e4692879fc5')
+    @decorators.idempotent_id('8fde898f-ce88-493b-adc9-4e4692879fc5')
     def test_create_duplicate_security_group_rule_fails(self):
         # Create duplicate security group rule, it should fail.
         body, _ = self._create_security_group()
@@ -201,7 +202,7 @@
             port_range_min=min_port, port_range_max=max_port)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('be308db6-a7cf-4d5c-9baf-71bafd73f35e')
+    @decorators.idempotent_id('be308db6-a7cf-4d5c-9baf-71bafd73f35e')
     def test_create_security_group_rule_with_non_existent_security_group(self):
         # Create security group rules with not existing security group.
         non_existent_sg = data_utils.rand_uuid()
@@ -217,7 +218,7 @@
     _project_network_cidr = CONF.network.project_network_v6_cidr
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7607439c-af73-499e-bf64-f687fd12a842')
+    @decorators.idempotent_id('7607439c-af73-499e-bf64-f687fd12a842')
     def test_create_security_group_rule_wrong_ip_prefix_version(self):
         group_create_body, _ = self._create_security_group()
 
diff --git a/tempest/api/network/test_service_providers.py b/tempest/api/network/test_service_providers.py
index be17b3e..b90c81b 100644
--- a/tempest/api/network/test_service_providers.py
+++ b/tempest/api/network/test_service_providers.py
@@ -13,12 +13,13 @@
 import testtools
 
 from tempest.api.network import base
+from tempest.lib import decorators
 from tempest import test
 
 
 class ServiceProvidersTest(base.BaseNetworkTest):
 
-    @test.idempotent_id('2cbbeea9-f010-40f6-8df5-4eaa0c918ea6')
+    @decorators.idempotent_id('2cbbeea9-f010-40f6-8df5-4eaa0c918ea6')
     @testtools.skipUnless(
         test.is_extension_enabled('service-type', 'network'),
         'service-type extension not enabled.')
diff --git a/tempest/api/network/test_subnetpools_extensions.py b/tempest/api/network/test_subnetpools_extensions.py
index d574d72..d9599c4 100644
--- a/tempest/api/network/test_subnetpools_extensions.py
+++ b/tempest/api/network/test_subnetpools_extensions.py
@@ -16,6 +16,7 @@
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -46,7 +47,7 @@
             raise cls.skipException(msg)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('62595970-ab1c-4b7f-8fcc-fddfe55e9811')
+    @decorators.idempotent_id('62595970-ab1c-4b7f-8fcc-fddfe55e9811')
     def test_create_list_show_update_delete_subnetpools(self):
         subnetpool_name = data_utils.rand_name('subnetpools')
         # create subnet pool
diff --git a/tempest/api/network/test_versions.py b/tempest/api/network/test_versions.py
index 9cf93f6..4f6d5ac 100644
--- a/tempest/api/network/test_versions.py
+++ b/tempest/api/network/test_versions.py
@@ -13,12 +13,13 @@
 # under the License.
 
 from tempest.api.network import base
+from tempest.lib import decorators
 from tempest import test
 
 
 class NetworksApiDiscovery(base.BaseNetworkTest):
     @test.attr(type='smoke')
-    @test.idempotent_id('cac8a836-c2e0-4304-b556-cd299c7281d1')
+    @decorators.idempotent_id('cac8a836-c2e0-4304-b556-cd299c7281d1')
     def test_api_version_resources(self):
         """Test that GET / returns expected resources.
 
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index e0216fd..642c1ac 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -16,8 +16,8 @@
 import time
 
 from tempest.common import custom_matchers
+from tempest.common.utils import data_utils
 from tempest import config
-from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_exc
 import tempest.test
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..2e617f3 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.object_storage import base
-from tempest.lib.common.utils import data_utils
+from tempest.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,20 +160,20 @@
         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()
         object_name, _ = self.create_object(container_name)
 
-        params = {'end_marker': 'ZzzzObject1234567890'}
+        params = {'end_marker': object_name + 'zzzz'}
         resp, object_list = self.container_client.list_container_contents(
             container_name,
             params=params)
         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,11 +242,12 @@
         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()
-        object_name = data_utils.rand_name(name='Swift/TestObject')
+        object_name = data_utils.rand_name(name='TestObject')
+        object_name = 'Swift/' + object_name
         self.create_object(container_name, object_name)
 
         params = {'path': 'Swift'}
@@ -255,7 +257,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 +272,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 +288,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 +298,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 +321,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 +338,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 +356,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 +371,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..ebbb84e 100644
--- a/tempest/api/object_storage/test_container_services_negative.py
+++ b/tempest/api/object_storage/test_container_services_negative.py
@@ -16,8 +16,9 @@
 import testtools
 
 from tempest.api.object_storage import base
+from tempest.common.utils import data_utils
 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/api/volume/v2/test_volumes_snapshots_list.py b/tempest/api/volume/v2/test_volumes_snapshots_list.py
index 8f68322..3deb437 100644
--- a/tempest/api/volume/v2/test_volumes_snapshots_list.py
+++ b/tempest/api/volume/v2/test_volumes_snapshots_list.py
@@ -13,11 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import operator
-
 from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -58,38 +56,38 @@
         self.assertEqual(sorted(sorted_list, reverse=(sort_dir == 'desc')),
                          sorted_list, msg)
 
-    @test.idempotent_id('c5513ada-64c1-4d28-83b9-af3307ec1388')
+    @decorators.idempotent_id('c5513ada-64c1-4d28-83b9-af3307ec1388')
     def test_snapshot_list_param_sort_id_asc(self):
         self._list_snapshots_param_sort(sort_key='id', sort_dir='asc')
 
-    @test.idempotent_id('8a7fe058-0b41-402a-8afd-2dbc5a4a718b')
+    @decorators.idempotent_id('8a7fe058-0b41-402a-8afd-2dbc5a4a718b')
     def test_snapshot_list_param_sort_id_desc(self):
         self._list_snapshots_param_sort(sort_key='id', sort_dir='desc')
 
-    @test.idempotent_id('4052c3a0-2415-440a-a8cc-305a875331b0')
+    @decorators.idempotent_id('4052c3a0-2415-440a-a8cc-305a875331b0')
     def test_snapshot_list_param_sort_created_at_asc(self):
         self._list_snapshots_param_sort(sort_key='created_at', sort_dir='asc')
 
-    @test.idempotent_id('dcbbe24a-f3c0-4ec8-9274-55d48db8d1cf')
+    @decorators.idempotent_id('dcbbe24a-f3c0-4ec8-9274-55d48db8d1cf')
     def test_snapshot_list_param_sort_created_at_desc(self):
         self._list_snapshots_param_sort(sort_key='created_at', sort_dir='desc')
 
-    @test.idempotent_id('d58b5fed-0c37-42d3-8c5d-39014ac13c00')
+    @decorators.idempotent_id('d58b5fed-0c37-42d3-8c5d-39014ac13c00')
     def test_snapshot_list_param_sort_name_asc(self):
         self._list_snapshots_param_sort(sort_key='display_name',
                                         sort_dir='asc')
 
-    @test.idempotent_id('96ba6f4d-1f18-47e1-b4bc-76edc6c21250')
+    @decorators.idempotent_id('96ba6f4d-1f18-47e1-b4bc-76edc6c21250')
     def test_snapshot_list_param_sort_name_desc(self):
         self._list_snapshots_param_sort(sort_key='display_name',
                                         sort_dir='desc')
 
-    @test.idempotent_id('05489dde-44bc-4961-a1f5-3ce7ee7824f7')
+    @decorators.idempotent_id('05489dde-44bc-4961-a1f5-3ce7ee7824f7')
     def test_snapshot_list_param_marker(self):
         # The list of snapshots should end before the provided marker
         params = {'marker': self.snapshot_id_list[1]}
         snap_list = self.snapshots_client.list_snapshots(**params)['snapshots']
-        fetched_list_id = map(operator.itemgetter('id'), snap_list)
+        fetched_list_id = [snap['id'] for snap in snap_list]
         # Verify the list of snapshots ends before the provided
         # marker(second snapshot), therefore only the first snapshot
         # should displayed.
diff --git a/tempest/clients.py b/tempest/clients.py
index 18116f3..cdd6925 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -31,14 +31,6 @@
 
     default_params = config.service_client_config()
 
-    # TODO(jordanP): remove this once no Tempest plugin use that class
-    # variable.
-    default_params_with_timeout_values = {
-        'build_interval': CONF.compute.build_interval,
-        'build_timeout': CONF.compute.build_timeout
-    }
-    default_params_with_timeout_values.update(default_params)
-
     def __init__(self, credentials, scope='project'):
         """Initialization of Manager class.
 
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 4f2fe67..55bc93e 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -17,10 +17,10 @@
 from oslo_utils import excutils
 
 from tempest.common import fixed_network
+from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common import rest_client
-from tempest.lib.common.utils import data_utils
 
 CONF = config.CONF
 
@@ -30,8 +30,7 @@
 def create_test_server(clients, validatable=False, validation_resources=None,
                        tenant_network=None, wait_until=None,
                        volume_backed=False, name=None, flavor=None,
-                       image_id=None, delete_vol_on_termination=True,
-                       **kwargs):
+                       image_id=None, **kwargs):
     """Common wrapper utility returning a test server.
 
     This method is a common wrapper returning a test server that can be
@@ -44,16 +43,30 @@
     :param tenant_network: Tenant network to be used for creating a server.
     :param wait_until: Server status to wait for the server to reach after
         its creation.
-    :param volume_backed: Whether the instance is volume backed or not.
+    :param volume_backed: Whether the server is volume backed or not.
+                          If this is true, a volume will be created and
+                          create server will be requested with
+                          'block_device_mapping_v2' populated with below
+                          values:
+                          --------------------------------------------
+                          bd_map_v2 = [{
+                              'uuid': volume['volume']['id'],
+                              'source_type': 'volume',
+                              'destination_type': 'volume',
+                              'boot_index': 0,
+                              'delete_on_termination': True}]
+                          kwargs['block_device_mapping_v2'] = bd_map_v2
+                          ---------------------------------------------
+                          If server needs to be booted from volume with other
+                          combination of bdm inputs than mentioned above, then
+                          pass the bdm inputs explicitly as kwargs and image_id
+                          as empty string ('').
     :param name: Name of the server to be provisioned. If not defined a random
         string ending with '-instance' will be generated.
     :param flavor: Flavor of the server to be provisioned. If not defined,
         CONF.compute.flavor_ref will be used instead.
     :param image_id: ID of the image to be used to provision the server. If not
         defined, CONF.compute.image_ref will be used instead.
-    :param delete_vol_on_termination: Controls whether the backing volume
-        should be deleted when the server is deleted. Only applies to volume
-        backed servers.
     :returns: a tuple
     """
 
@@ -103,12 +116,14 @@
     if volume_backed:
         volume_name = data_utils.rand_name(__name__ + '-volume')
         volumes_client = clients.volumes_v2_client
-        if CONF.volume_feature_enabled.api_v1:
+        name_field = 'name'
+        if not CONF.volume_feature_enabled.api_v2:
             volumes_client = clients.volumes_client
-        volume = volumes_client.create_volume(
-            display_name=volume_name,
-            imageRef=image_id,
-            size=CONF.volume.volume_size)
+            name_field = 'display_name'
+        params = {name_field: volume_name,
+                  'imageRef': image_id,
+                  'size': CONF.volume.volume_size}
+        volume = volumes_client.create_volume(**params)
         waiters.wait_for_volume_status(volumes_client,
                                        volume['volume']['id'], 'available')
 
@@ -117,7 +132,7 @@
             'source_type': 'volume',
             'destination_type': 'volume',
             'boot_index': 0,
-            'delete_on_termination': delete_vol_on_termination}]
+            'delete_on_termination': True}]
         kwargs['block_device_mapping_v2'] = bd_map_v2
 
         # Since this is boot from volume an image does not need
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index 8303caf..b7b02ab 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):
@@ -205,7 +218,7 @@
                        'within the required time (%s s).' %
                        (volume_id, new_volume_type, current_volume_type,
                         client.build_timeout))
-            raise exceptions.TimeoutException(message)
+            raise lib_exc.TimeoutException(message)
 
 
 def wait_for_snapshot_status(client, snapshot_id, status):
diff --git a/tempest/config.py b/tempest/config.py
index fe8c175..75ec46a 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -1035,32 +1035,6 @@
 """)
 ]
 
-input_scenario_group = cfg.OptGroup(name="input-scenario",
-                                    title="Filters and values for"
-                                          " input scenarios[DEPRECATED]")
-
-
-InputScenarioGroup = [
-    cfg.StrOpt('image_regex',
-               default='^cirros-0.3.1-x86_64-uec$',
-               help="Matching images become parameters for scenario tests",
-               deprecated_for_removal=True),
-    cfg.StrOpt('flavor_regex',
-               default='^m1.nano$',
-               help="Matching flavors become parameters for scenario tests",
-               deprecated_for_removal=True),
-    cfg.StrOpt('non_ssh_image_regex',
-               default='^.*[Ww]in.*$',
-               help="SSH verification in tests is skipped"
-                    "for matching images",
-               deprecated_for_removal=True),
-    cfg.StrOpt('ssh_user_regex',
-               default="[[\"^.*[Cc]irros.*$\", \"cirros\"]]",
-               help="List of user mapped to regex "
-                    "to matching image names.",
-               deprecated_for_removal=True),
-]
-
 DefaultGroup = [
     cfg.StrOpt('resources_prefix',
                default='tempest',
@@ -1090,7 +1064,6 @@
     (scenario_group, ScenarioGroup),
     (service_available_group, ServiceAvailableGroup),
     (debug_group, DebugGroup),
-    (input_scenario_group, InputScenarioGroup),
     (None, DefaultGroup)
 ]
 
@@ -1152,7 +1125,6 @@
         self.scenario = _CONF.scenario
         self.service_available = _CONF.service_available
         self.debug = _CONF.debug
-        self.input_scenario = _CONF['input-scenario']
         logging.tempest_set_log_file('tempest.log')
 
     def __init__(self, parse_conf=True, config_path=None):
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/aggregates.py b/tempest/lib/api_schema/response/compute/v2_1/aggregates.py
index 1a9fe41..3289a34 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/aggregates.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/aggregates.py
@@ -14,17 +14,19 @@
 
 import copy
 
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
 # create-aggregate api doesn't have 'hosts' and 'metadata' attributes.
 aggregate_for_create = {
     'type': 'object',
     'properties': {
         'availability_zone': {'type': ['string', 'null']},
-        'created_at': {'type': 'string'},
+        'created_at': parameter_types.date_time,
         'deleted': {'type': 'boolean'},
-        'deleted_at': {'type': ['string', 'null']},
+        'deleted_at': parameter_types.date_time_or_null,
         'id': {'type': 'integer'},
         'name': {'type': 'string'},
-        'updated_at': {'type': ['string', 'null']}
+        'updated_at': parameter_types.date_time_or_null
     },
     'additionalProperties': False,
     'required': ['availability_zone', 'created_at', 'deleted',
@@ -69,9 +71,7 @@
 # The 'updated_at' attribute of 'update_aggregate' can't be null.
 update_aggregate = copy.deepcopy(get_aggregate)
 update_aggregate['response_body']['properties']['aggregate']['properties'][
-    'updated_at'] = {
-        'type': 'string'
-    }
+    'updated_at'] = parameter_types.date_time
 
 delete_aggregate = {
     'status_code': [200]
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 d9aebce..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
@@ -14,6 +14,8 @@
 
 import copy
 
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
 
 base = {
     'status_code': [200],
@@ -49,7 +51,7 @@
 }
 
 detail = {
-    'type': 'object',
+    'type': ['object', 'null'],
     'patternProperties': {
         # NOTE: Here is for a hostname
         '^[a-zA-Z0-9-_.]+$': {
@@ -61,7 +63,7 @@
                     'properties': {
                         'available': {'type': 'boolean'},
                         'active': {'type': 'boolean'},
-                        'updated_at': {'type': ['string', 'null']}
+                        'updated_at': parameter_types.date_time_or_null
                     },
                     'additionalProperties': False,
                     'required': ['available', 'active', 'updated_at']
diff --git a/tempest/lib/api_schema/response/compute/v2_1/extensions.py b/tempest/lib/api_schema/response/compute/v2_1/extensions.py
index a6a455c..b5962d7 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/extensions.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/extensions.py
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
 list_extensions = {
     'status_code': [200],
     'response_body': {
@@ -22,10 +24,7 @@
                 'items': {
                     'type': 'object',
                     'properties': {
-                        'updated': {
-                            'type': 'string',
-                            'format': 'data-time'
-                        },
+                        'updated': parameter_types.date_time,
                         'name': {'type': 'string'},
                         'links': {'type': 'array'},
                         'namespace': {
diff --git a/tempest/lib/api_schema/response/compute/v2_1/images.py b/tempest/lib/api_schema/response/compute/v2_1/images.py
index f65b9d8..156ff4a 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/images.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/images.py
@@ -26,10 +26,10 @@
     'properties': {
         'id': {'type': 'string'},
         'status': {'enum': image_status_enums},
-        'updated': {'type': 'string'},
+        'updated': parameter_types.date_time,
         'links': image_links,
         'name': {'type': ['string', 'null']},
-        'created': {'type': 'string'},
+        'created': parameter_types.date_time,
         'minDisk': {'type': 'integer'},
         'minRam': {'type': 'integer'},
         'progress': {'type': 'integer'},
diff --git a/tempest/lib/api_schema/response/compute/v2_1/keypairs.py b/tempest/lib/api_schema/response/compute/v2_1/keypairs.py
index 9c04c79..2828097 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/keypairs.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/keypairs.py
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
 get_keypair = {
     'status_code': [200],
     'response_body': {
@@ -25,9 +27,9 @@
                     'fingerprint': {'type': 'string'},
                     'user_id': {'type': 'string'},
                     'deleted': {'type': 'boolean'},
-                    'created_at': {'type': 'string'},
-                    'updated_at': {'type': ['string', 'null']},
-                    'deleted_at': {'type': ['string', 'null']},
+                    'created_at': parameter_types.date_time,
+                    'updated_at': parameter_types.date_time_or_null,
+                    'deleted_at': parameter_types.date_time_or_null,
                     'id': {'type': 'integer'}
 
                 },
diff --git a/tempest/lib/api_schema/response/compute/v2_1/migrations.py b/tempest/lib/api_schema/response/compute/v2_1/migrations.py
index b7d66ea..c50286d 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/migrations.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/migrations.py
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
 list_migrations = {
     'status_code': [200],
     'response_body': {
@@ -32,8 +34,8 @@
                         'dest_host': {'type': ['string', 'null']},
                         'old_instance_type_id': {'type': ['integer', 'null']},
                         'new_instance_type_id': {'type': ['integer', 'null']},
-                        'created_at': {'type': 'string'},
-                        'updated_at': {'type': ['string', 'null']}
+                        'created_at': parameter_types.date_time,
+                        'updated_at': parameter_types.date_time_or_null
                     },
                     'additionalProperties': False,
                     'required': [
diff --git a/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py b/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py
index 3cc5ca4..a3c9099 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py
@@ -81,6 +81,16 @@
     }
 }
 
+date_time = {
+    'type': 'string',
+    'format': 'iso8601-date-time'
+}
+
+date_time_or_null = {
+    'type': ['string', 'null'],
+    'format': 'iso8601-date-time'
+}
+
 response_header = {
     'connection': {'type': 'string'},
     'content-length': {'type': 'string'},
@@ -89,9 +99,14 @@
     'x-compute-request-id': {'type': 'string'},
     'vary': {'type': 'string'},
     'x-openstack-nova-api-version': {'type': 'string'},
+    # NOTE(gmann): Validating this as string only as this
+    # date in header is returned in different format than
+    # ISO 8601 date time format which is not consistent with
+    # other date-time format in nova.
+    # This API is already deprecated so not worth to fix
+    # on nova side.
     'date': {
-        'type': 'string',
-        'format': 'data-time'
+        'type': 'string'
     }
 }
 
diff --git a/tempest/lib/api_schema/response/compute/v2_1/servers.py b/tempest/lib/api_schema/response/compute/v2_1/servers.py
index 1264416..4ccca6f 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/servers.py
@@ -118,8 +118,8 @@
         },
         'user_id': {'type': 'string'},
         'tenant_id': {'type': 'string'},
-        'created': {'type': 'string'},
-        'updated': {'type': 'string'},
+        'created': parameter_types.date_time,
+        'updated': parameter_types.date_time,
         'progress': {'type': 'integer'},
         'metadata': {'type': 'object'},
         'links': parameter_types.links,
@@ -402,7 +402,7 @@
         'request_id': {'type': 'string'},
         'user_id': {'type': 'string'},
         'project_id': {'type': 'string'},
-        'start_time': {'type': 'string'},
+        'start_time': parameter_types.date_time,
         'message': {'type': ['string', 'null']},
         'instance_uuid': {'type': 'string'}
     },
@@ -417,8 +417,8 @@
         'type': 'object',
         'properties': {
             'event': {'type': 'string'},
-            'start_time': {'type': 'string'},
-            'finish_time': {'type': 'string'},
+            'start_time': parameter_types.date_time,
+            'finish_time': parameter_types.date_time,
             'result': {'type': 'string'},
             'traceback': {'type': ['string', 'null']}
         },
diff --git a/tempest/lib/api_schema/response/compute/v2_1/services.py b/tempest/lib/api_schema/response/compute/v2_1/services.py
index ddef7b2..6949f86 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/services.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/services.py
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
 list_services = {
     'status_code': [200],
     'response_body': {
@@ -29,7 +31,7 @@
                         'state': {'type': 'string'},
                         'binary': {'type': 'string'},
                         'status': {'type': 'string'},
-                        'updated_at': {'type': ['string', 'null']},
+                        'updated_at': parameter_types.date_time_or_null,
                         'disabled_reason': {'type': ['string', 'null']}
                     },
                     'additionalProperties': False,
diff --git a/tempest/lib/api_schema/response/compute/v2_1/snapshots.py b/tempest/lib/api_schema/response/compute/v2_1/snapshots.py
index 01a524b..826f854 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/snapshots.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/snapshots.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
 common_snapshot_info = {
     'type': 'object',
     'properties': {
@@ -20,7 +22,7 @@
         'volumeId': {'type': 'string'},
         'status': {'type': 'string'},
         'size': {'type': 'integer'},
-        'createdAt': {'type': 'string'},
+        'createdAt': parameter_types.date_time,
         'displayName': {'type': ['string', 'null']},
         'displayDescription': {'type': ['string', 'null']}
     },
diff --git a/tempest/lib/api_schema/response/compute/v2_1/tenant_usages.py b/tempest/lib/api_schema/response/compute/v2_1/tenant_usages.py
index d51ef12..b531d2e 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/tenant_usages.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/tenant_usages.py
@@ -14,24 +14,21 @@
 
 import copy
 
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
 _server_usages = {
     'type': 'array',
     'items': {
         'type': 'object',
         'properties': {
-            'ended_at': {
-                'oneOf': [
-                    {'type': 'string'},
-                    {'type': 'null'}
-                ]
-            },
+            'ended_at': parameter_types.date_time_or_null,
             'flavor': {'type': 'string'},
             'hours': {'type': 'number'},
             'instance_id': {'type': 'string'},
             'local_gb': {'type': 'integer'},
             'memory_mb': {'type': 'integer'},
             'name': {'type': 'string'},
-            'started_at': {'type': 'string'},
+            'started_at': parameter_types.date_time,
             'state': {'type': 'string'},
             'tenant_id': {'type': 'string'},
             'uptime': {'type': 'integer'},
@@ -47,8 +44,8 @@
     'type': 'object',
     'properties': {
         'server_usages': _server_usages,
-        'start': {'type': 'string'},
-        'stop': {'type': 'string'},
+        'start': parameter_types.date_time,
+        'stop': parameter_types.date_time,
         'tenant_id': {'type': 'string'},
         'total_hours': {'type': 'number'},
         'total_local_gb_usage': {'type': 'number'},
diff --git a/tempest/lib/api_schema/response/compute/v2_1/versions.py b/tempest/lib/api_schema/response/compute/v2_1/versions.py
index 08a9fab..7f56239 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/versions.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/versions.py
@@ -14,6 +14,8 @@
 
 import copy
 
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
 
 _version = {
     'type': 'object',
@@ -33,7 +35,7 @@
             }
         },
         'status': {'type': 'string'},
-        'updated': {'type': 'string', 'format': 'date-time'},
+        'updated': parameter_types.date_time,
         'version': {'type': 'string'},
         'min_version': {'type': 'string'},
         'media-types': {
diff --git a/tempest/lib/api_schema/response/compute/v2_1/volumes.py b/tempest/lib/api_schema/response/compute/v2_1/volumes.py
index bb34acb..c35dae9 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/volumes.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/volumes.py
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
 create_get_volume = {
     'status_code': [200],
     'response_body': {
@@ -24,7 +26,7 @@
                     'status': {'type': 'string'},
                     'displayName': {'type': ['string', 'null']},
                     'availabilityZone': {'type': 'string'},
-                    'createdAt': {'type': 'string'},
+                    'createdAt': parameter_types.date_time,
                     'displayDescription': {'type': ['string', 'null']},
                     'volumeType': {'type': ['string', 'null']},
                     'snapshotId': {'type': ['string', 'null']},
@@ -75,7 +77,7 @@
                         'status': {'type': 'string'},
                         'displayName': {'type': ['string', 'null']},
                         'availabilityZone': {'type': 'string'},
-                        'createdAt': {'type': 'string'},
+                        'createdAt': parameter_types.date_time,
                         'displayDescription': {'type': ['string', 'null']},
                         'volumeType': {'type': ['string', 'null']},
                         'snapshotId': {'type': ['string', 'null']},
diff --git a/tempest/lib/cmd/check_uuid.py b/tempest/lib/cmd/check_uuid.py
index 2fe957b..283b10f 100755
--- a/tempest/lib/cmd/check_uuid.py
+++ b/tempest/lib/cmd/check_uuid.py
@@ -27,6 +27,7 @@
 import six.moves.urllib.parse as urlparse
 
 # TODO(oomichi): Need to remove this after switching all modules to decorators
+# on all OpenStack projects because they runs check-uuid on their own gates.
 OLD_DECORATOR_MODULE = 'test'
 
 DECORATOR_MODULE = 'decorators'
@@ -120,7 +121,7 @@
 
     @staticmethod
     def _get_idempotent_id(test_node):
-        """Return key-value dict with all metadata from @test.idempotent_id"""
+        "Return key-value dict with metadata from @decorators.idempotent_id"
         idempotent_id = None
         for decorator in test_node.decorator_list:
             if (hasattr(decorator, 'func') and
@@ -308,7 +309,8 @@
         Returns true if untagged tests exist.
         """
         def report(module_name, test_name, tests):
-            error_str = "%s:%s\nmissing @test.idempotent_id('...')\n%s\n" % (
+            error_str = ("%s:%s\nmissing @decorators.idempotent_id"
+                         "('...')\n%s\n") % (
                 tests[module_name]['source_path'],
                 tests[module_name]['tests'][test_name].lineno,
                 test_name
@@ -356,7 +358,8 @@
     else:
         errors = checker.report_untagged(untagged) or errors
     if errors:
-        sys.exit("@test.idempotent_id existence and uniqueness checks failed\n"
+        sys.exit("@decorators.idempotent_id existence and uniqueness checks "
+                 "failed\n"
                  "Run 'tox -v -euuidgen' to automatically fix tests with\n"
                  "missing @test.idempotent_id decorators.")
 
diff --git a/tempest/lib/common/jsonschema_validator.py b/tempest/lib/common/jsonschema_validator.py
new file mode 100644
index 0000000..bbdf382
--- /dev/null
+++ b/tempest/lib/common/jsonschema_validator.py
@@ -0,0 +1,39 @@
+# Copyright 2016 NEC Corporation.
+# All Rights Reserved.
+#
+#    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 jsonschema
+from oslo_utils import timeutils
+
+# JSON Schema validator and format checker used for JSON Schema validation
+JSONSCHEMA_VALIDATOR = jsonschema.Draft4Validator
+FORMAT_CHECKER = jsonschema.draft4_format_checker
+
+
+# NOTE(gmann): Add customized format checker for 'date-time' format because:
+# 1. jsonschema needs strict_rfc3339 or isodate module to be installed
+#    for proper date-time checking as per rfc3339.
+# 2. Nova or other OpenStack components handle the date time format as
+#    ISO 8601 which is defined in oslo_utils.timeutils
+# so this checker will validate the date-time as defined in
+# oslo_utils.timeutils
+@FORMAT_CHECKER.checks('iso8601-date-time')
+def _validate_datetime_format(instance):
+    try:
+        if isinstance(instance, jsonschema.compat.str_types):
+            timeutils.parse_isotime(instance)
+    except ValueError:
+        return False
+    else:
+        return True
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index 2c36f55..f5bff20 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -25,6 +25,7 @@
 import six
 
 from tempest.lib.common import http
+from tempest.lib.common import jsonschema_validator
 from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions
 
@@ -38,8 +39,8 @@
 HTTP_REDIRECTION = (300, 301, 302, 303, 304, 305, 306, 307)
 
 # JSON Schema validator and format checker used for JSON Schema validation
-JSONSCHEMA_VALIDATOR = jsonschema.Draft4Validator
-FORMAT_CHECKER = jsonschema.draft4_format_checker
+JSONSCHEMA_VALIDATOR = jsonschema_validator.JSONSCHEMA_VALIDATOR
+FORMAT_CHECKER = jsonschema_validator.FORMAT_CHECKER
 
 
 class RestClient(object):
@@ -616,6 +617,7 @@
         :raises BadRequest: If a 400 response code is received
         :raises Gone: If a 410 response code is received
         :raises Conflict: If a 409 response code is received
+        :raises PreconditionFailed: If a 412 response code is received
         :raises OverLimit: If a 413 response code is received and over_limit is
                           not in the response body
         :raises RateLimitExceeded: If a 413 response code is received and
@@ -774,6 +776,11 @@
                 resp_body = self._parse_resp(resp_body)
             raise exceptions.Conflict(resp_body, resp=resp)
 
+        if resp.status == 412:
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
+            raise exceptions.PreconditionFailed(resp_body, resp=resp)
+
         if resp.status == 413:
             if parse_resp:
                 resp_body = self._parse_resp(resp_body)
diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py
index 4226cd6..5e65bee 100644
--- a/tempest/lib/common/ssh.py
+++ b/tempest/lib/common/ssh.py
@@ -37,7 +37,30 @@
 
     def __init__(self, host, username, password=None, timeout=300, pkey=None,
                  channel_timeout=10, look_for_keys=False, key_filename=None,
-                 port=22):
+                 port=22, proxy_client=None):
+        """SSH client.
+
+        Many of parameters are just passed to the underlying implementation
+        as it is.  See the paramiko documentation for more details.
+        http://docs.paramiko.org/en/2.1/api/client.html#paramiko.client.SSHClient.connect
+
+        :param host: Host to login.
+        :param username: SSH username.
+        :param password: SSH password, or a password to unlock private key.
+        :param timeout: Timeout in seconds, including retries.
+            Default is 300 seconds.
+        :param pkey: Private key.
+        :param channel_timeout: Channel timeout in seconds, passed to the
+            paramiko.  Default is 10 seconds.
+        :param look_for_keys: Whether or not to search for private keys
+            in ``~/.ssh``.  Default is False.
+        :param key_filename: Filename for private key to use.
+        :param port: SSH port number.
+        :param proxy_client: Another SSH client to provide a transport
+            for ssh-over-ssh.  The default is None, which means
+            not to use ssh-over-ssh.
+        :type proxy_client: ``tempest.lib.common.ssh.Client`` object
+        """
         self.host = host
         self.username = username
         self.port = port
@@ -51,6 +74,8 @@
         self.timeout = int(timeout)
         self.channel_timeout = float(channel_timeout)
         self.buf_size = 1024
+        self.proxy_client = proxy_client
+        self._proxy_conn = None
 
     def _get_ssh_connection(self, sleep=1.5, backoff=1):
         """Returns an ssh connection to the specified host."""
@@ -59,6 +84,10 @@
         ssh.set_missing_host_key_policy(
             paramiko.AutoAddPolicy())
         _start_time = time.time()
+        if self.proxy_client is not None:
+            proxy_chan = self._get_proxy_channel()
+        else:
+            proxy_chan = None
         if self.pkey is not None:
             LOG.info("Creating ssh connection to '%s:%d' as '%s'"
                      " with public key authentication",
@@ -74,7 +103,8 @@
                             password=self.password,
                             look_for_keys=self.look_for_keys,
                             key_filename=self.key_filename,
-                            timeout=self.channel_timeout, pkey=self.pkey)
+                            timeout=self.channel_timeout, pkey=self.pkey,
+                            sock=proxy_chan)
                 LOG.info("ssh connection to %s@%s successfully created",
                          self.username, self.host)
                 return ssh
@@ -175,3 +205,14 @@
         """Raises an exception when we can not connect to server via ssh."""
         connection = self._get_ssh_connection()
         connection.close()
+
+    def _get_proxy_channel(self):
+        conn = self.proxy_client._get_ssh_connection()
+        # Keep a reference to avoid g/c
+        # https://github.com/paramiko/paramiko/issues/440
+        self._proxy_conn = conn
+        transport = conn.get_transport()
+        chan = transport.open_session()
+        cmd = 'nc %s %s' % (self.host, self.port)
+        chan.exec_command(cmd)
+        return chan
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
index 108ba70..af3acbf 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -101,6 +101,11 @@
     message = "The requested resource is no longer available"
 
 
+class PreconditionFailed(ClientRestClientException):
+    status_code = 412
+    message = "Precondition Failed"
+
+
 class RateLimitExceeded(ClientRestClientException):
     status_code = 413
     message = "Rate limit exceeded"
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index 50ce32e..f16ef88 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -30,6 +30,8 @@
 
 
 class ServersClient(base_compute_client.BaseComputeClient):
+    """Service client for the resource /servers"""
+
     schema_versions_info = [
         {'min': None, 'max': '2.2', 'schema': schema},
         {'min': '2.3', 'max': '2.8', 'schema': schemav23},
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 8c930c3..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)
@@ -728,7 +726,7 @@
 
         self.assertEqual(network['name'], name)
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.networks_client.delete_network,
+                        networks_client.delete_network,
                         network['id'])
         return network
 
@@ -881,7 +879,7 @@
         )
         floating_ip = result['floatingip']
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.floating_ips_client.delete_floatingip,
+                        client.delete_floatingip,
                         floating_ip['id'])
         return floating_ip
 
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..5565cb8 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
 
@@ -240,9 +241,11 @@
         self.assertIn(tenant.router['id'], seen_router_ids)
 
         myport = (tenant.router['id'], tenant.subnet['id'])
-        router_ports = [(i['device_id'], i['fixed_ips'][0]['subnet_id']) for i
-                        in self._list_ports()
-                        if net_info.is_router_interface_port(i)]
+        router_ports = [
+            (i['device_id'], f['subnet_id'])
+            for i in self._list_ports(device_id=tenant.router['id'])
+            if net_info.is_router_interface_port(i)
+            for f in i['fixed_ips']]
 
         self.assertIn(myport, router_ports)
 
@@ -262,7 +265,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 +461,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 +482,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 +496,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 +549,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 +582,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 +621,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..ddbaf5a 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
@@ -44,8 +45,6 @@
 
     def setUp(self):
         super(TestServerBasicOps, self).setUp()
-        self.image_ref = CONF.compute.image_ref
-        self.flavor_ref = CONF.compute.flavor_ref
         self.run_ssh = CONF.validation.run_validation
         self.ssh_user = CONF.validation.image_ssh_user
 
@@ -124,7 +123,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):
@@ -132,13 +131,10 @@
         security_group = self._create_security_group()
         self.md = {'meta1': 'data1', 'meta2': 'data2', 'metaN': 'dataN'}
         self.instance = self.create_server(
-            image_id=self.image_ref,
-            flavor=self.flavor_ref,
             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..db91a21 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,9 +75,10 @@
             # 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']
+            # ensure server is located on the requested host
+            self.assertEqual(host['host_name'], server['OS-EXT-SRV-ATTR:host'])
             servers.append(server)
 
         # make sure we really have the number of servers we think we should
diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py
index 7f04b0d..d88a639 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
 
@@ -54,10 +55,8 @@
         security_groups = [{'name': security_group['name']}]
 
         server = self.create_server(
-            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 +72,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..2ce8532 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
@@ -46,10 +47,8 @@
 
         # boot an instance and create a timestamp file in it
         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 +61,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..f00270d 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import time
-
 from oslo_log import log as logging
 import testtools
 
@@ -63,21 +61,17 @@
         snapshot_name = data_utils.rand_name('scenario-snapshot')
         snapshot = self.snapshots_client.create_snapshot(
             volume_id=volume['id'], display_name=snapshot_name)['snapshot']
-
-        def cleaner():
-            self.snapshots_client.delete_snapshot(snapshot['id'])
-            try:
-                while self.snapshots_client.show_snapshot(
-                        snapshot['id'])['snapshot']:
-                    time.sleep(1)
-            except lib_exc.NotFound:
-                pass
-        self.addCleanup(cleaner)
+        self.addCleanup(self.snapshots_client.wait_for_resource_deletion,
+                        snapshot['id'])
+        self.addCleanup(self.snapshots_client.delete_snapshot, snapshot['id'])
         waiters.wait_for_volume_status(self.volumes_client,
                                        volume['id'], 'available')
         waiters.wait_for_snapshot_status(self.snapshots_client,
                                          snapshot['id'], 'available')
-        self.assertEqual(snapshot_name, snapshot['display_name'])
+        if 'display_name' in snapshot:
+            self.assertEqual(snapshot_name, snapshot['display_name'])
+        else:
+            self.assertEqual(snapshot_name, snapshot['name'])
         return snapshot
 
     def _wait_for_volume_available_on_the_system(self, ip_address,
@@ -94,8 +88,7 @@
                                           CONF.compute.build_interval):
             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')
@@ -107,10 +100,8 @@
         # boot an instance and create a timestamp file in it
         volume = self.create_volume()
         server = self.create_server(
-            image_id=CONF.compute.image_ref,
             key_name=keypair['name'],
-            security_groups=security_group,
-            wait_until='ACTIVE')
+            security_groups=[{'name': security_group['name']}])
 
         # create and add floating IP to server1
         ip_for_server = self.get_server_ip(server)
@@ -137,7 +128,7 @@
         server_from_snapshot = self.create_server(
             image_id=snapshot_image['id'],
             key_name=keypair['name'],
-            security_groups=security_group)
+            security_groups=[{'name': security_group['name']}])
 
         # create and add floating IP to server_from_snapshot
         ip_for_snapshot = self.get_server_ip(server_from_snapshot)
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 2c8b618..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
 
@@ -40,20 +41,23 @@
             self.__class__.__name__ + '-volume-origin')
         return self.create_volume(name=vol_name, imageRef=img_uuid)
 
-    def _get_bdm(self, vol_id, delete_on_termination=False):
+    def _get_bdm(self, source_id, source_type, delete_on_termination=False):
         # NOTE(gfidente): the syntax for block_device_mapping is
         # dev_name=id:type:size:delete_on_terminate
         # where type needs to be "snap" if the server is booted
         # from a snapshot, size instead can be safely left empty
+
         bd_map = [{
             'device_name': 'vda',
-            'volume_id': vol_id,
+            '{}_id'.format(source_type): source_id,
             'delete_on_termination': str(int(delete_on_termination))}]
         return {'block_device_mapping': bd_map}
 
-    def _boot_instance_from_volume(self, vol_id, keypair=None,
-                                   security_group=None,
-                                   delete_on_termination=False):
+    def _boot_instance_from_resource(self, source_id,
+                                     source_type,
+                                     keypair=None,
+                                     security_group=None,
+                                     delete_on_termination=False):
         create_kwargs = dict()
         if keypair:
             create_kwargs['key_name'] = keypair['name']
@@ -61,11 +65,11 @@
             create_kwargs['security_groups'] = [
                 {'name': security_group['name']}]
         create_kwargs.update(self._get_bdm(
-            vol_id, delete_on_termination=delete_on_termination))
-        return self.create_server(
-            image_id='',
-            wait_until='ACTIVE',
-            **create_kwargs)
+            source_id,
+            source_type,
+            delete_on_termination=delete_on_termination))
+
+        return self.create_server(image_id='', **create_kwargs)
 
     def _create_snapshot_from_volume(self, vol_id):
         snap_name = data_utils.rand_name(
@@ -92,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):
@@ -116,8 +120,11 @@
         # create an instance from volume
         LOG.info("Booting instance 1 from volume")
         volume_origin = self._create_volume_from_image()
-        instance_1st = self._boot_instance_from_volume(volume_origin['id'],
-                                                       keypair, security_group)
+        instance_1st = self._boot_instance_from_resource(
+            source_id=volume_origin['id'],
+            source_type='volume',
+            keypair=keypair,
+            security_group=security_group)
         LOG.info("Booted first instance: %s", instance_1st)
 
         # write content to volume on instance
@@ -131,8 +138,11 @@
         self._delete_server(instance_1st)
 
         # create a 2nd instance from volume
-        instance_2nd = self._boot_instance_from_volume(volume_origin['id'],
-                                                       keypair, security_group)
+        instance_2nd = self._boot_instance_from_resource(
+            source_id=volume_origin['id'],
+            source_type='volume',
+            keypair=keypair,
+            security_group=security_group)
         LOG.info("Booted second instance %s", instance_2nd)
 
         # check the content of written file
@@ -152,8 +162,10 @@
                                     size=snapshot['size'])
         LOG.info("Booting third instance from snapshot")
         server_from_snapshot = (
-            self._boot_instance_from_volume(volume['id'],
-                                            keypair, security_group))
+            self._boot_instance_from_resource(source_id=volume['id'],
+                                              source_type='volume',
+                                              keypair=keypair,
+                                              security_group=security_group))
         LOG.info("Booted third instance %s", server_from_snapshot)
 
         # check the content of written file
@@ -164,13 +176,51 @@
                                         private_key=keypair['private_key'])
         self.assertEqual(timestamp, timestamp3)
 
-    @test.idempotent_id('36c34c67-7b54-4b59-b188-02a2f458a63b')
+    @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
+        boot_volume = self._create_volume_from_image()
+
+        # Create a snapshot
+        boot_snapshot = self._create_snapshot_from_volume(boot_volume['id'])
+
+        # Create a server from a volume snapshot
+        server = self._boot_instance_from_resource(
+            source_id=boot_snapshot['id'],
+            source_type='snapshot',
+            delete_on_termination=True)
+
+        server_info = self.servers_client.show_server(server['id'])['server']
+
+        # The created volume when creating a server from a snapshot
+        created_volume = server_info['os-extended-volumes:volumes_attached']
+
+        self.assertNotEmpty(created_volume, "No volume attachment found.")
+
+        created_volume_info = self.volumes_client.show_volume(
+            created_volume[0]['id'])['volume']
+
+        # Verify the server was created from the snapshot
+        self.assertEqual(
+            boot_volume['volume_image_metadata']['image_id'],
+            created_volume_info['volume_image_metadata']['image_id'])
+        self.assertEqual(boot_snapshot['id'],
+                         created_volume_info['snapshot_id'])
+        self.assertEqual(server['id'],
+                         created_volume_info['attachments'][0]['server_id'])
+        self.assertEqual(created_volume[0]['id'],
+                         created_volume_info['attachments'][0]['volume_id'])
+
+    @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
         volume_origin = self._create_volume_from_image()
-        instance = self._boot_instance_from_volume(volume_origin['id'],
-                                                   delete_on_termination=True)
+        instance = self._boot_instance_from_resource(
+            source_id=volume_origin['id'],
+            source_type='volume',
+            delete_on_termination=True)
         # create EBS image
         image = self.create_server_snapshot(instance)
 
@@ -178,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
@@ -187,10 +236,10 @@
 
 
 class TestVolumeBootPatternV2(TestVolumeBootPattern):
-    def _get_bdm(self, vol_id, delete_on_termination=False):
+    def _get_bdm(self, source_id, source_type, delete_on_termination=False):
         bd_map_v2 = [{
-            'uuid': vol_id,
-            'source_type': 'volume',
+            'uuid': source_id,
+            'source_type': source_type,
             'destination_type': 'volume',
             'boot_index': 0,
             'delete_on_termination': delete_on_termination}]
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/test.py b/tempest/test.py
index 039afa1..06de520 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -39,7 +39,11 @@
 
 CONF = config.CONF
 
-idempotent_id = decorators.idempotent_id
+# TODO(oomichi): This test.idempotent_id should be removed after all projects
+# switch to use decorators.idempotent_id.
+idempotent_id = debtcollector.moves.moved_function(
+    decorators.idempotent_id, 'idempotent_id', __name__,
+    version='Mitaka', removal_version='?')
 
 
 def attr(**kwargs):
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/common/test_jsonschema_validator.py b/tempest/tests/lib/common/test_jsonschema_validator.py
new file mode 100644
index 0000000..8694f3d
--- /dev/null
+++ b/tempest/tests/lib/common/test_jsonschema_validator.py
@@ -0,0 +1,83 @@
+# Copyright 2016 NEC Corporation.  All rights reserved.
+#
+#    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.
+
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions
+from tempest.tests import base
+from tempest.tests.lib import fake_http
+
+
+class TestJSONSchemaDateTimeFormat(base.TestCase):
+    date_time_schema = [
+        {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'date-time': parameter_types.date_time
+                }
+            }
+        },
+        {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'date-time': parameter_types.date_time_or_null
+                }
+            }
+        }
+    ]
+
+    def test_valid_date_time_format(self):
+        valid_instances = ['2016-10-02T10:00:00-05:00',
+                           '2016-10-02T10:00:00+09:00',
+                           '2016-10-02T15:00:00Z',
+                           '2016-10-02T15:00:00.05Z']
+        resp = fake_http.fake_http_response('', status=200)
+        for instance in valid_instances:
+            body = {'date-time': instance}
+            for schema in self.date_time_schema:
+                rest_client.RestClient.validate_response(schema, resp, body)
+
+    def test_invalid_date_time_format(self):
+        invalid_instances = ['2016-10-02 T10:00:00-05:00',
+                             '2016-10-02T 15:00:00',
+                             '2016-10-02T15:00:00.05 Z',
+                             '2016-10-02:15:00:00.05Z',
+                             'T15:00:00.05Z',
+                             '2016:10:02T15:00:00',
+                             '2016-10-02T15-00-00',
+                             '2016-10-02T15.05Z',
+                             '09MAR2015 11:15',
+                             '13 Oct 2015 05:55:36 GMT',
+                             '']
+        resp = fake_http.fake_http_response('', status=200)
+        for instance in invalid_instances:
+            body = {'date-time': instance}
+            for schema in self.date_time_schema:
+                self.assertRaises(exceptions.InvalidHTTPResponseBody,
+                                  rest_client.RestClient.validate_response,
+                                  schema, resp, body)
+
+    def test_date_time_or_null_format(self):
+        instance = None
+        resp = fake_http.fake_http_response('', status=200)
+        body = {'date-time': instance}
+        rest_client.RestClient.validate_response(self.date_time_schema[1],
+                                                 resp, body)
+        self.assertRaises(exceptions.InvalidHTTPResponseBody,
+                          rest_client.RestClient.validate_response,
+                          self.date_time_schema[0], resp, body)
diff --git a/tempest/tests/lib/services/compute/test_servers_client.py b/tempest/tests/lib/services/compute/test_servers_client.py
index 93550fd..adfaaf2 100644
--- a/tempest/tests/lib/services/compute/test_servers_client.py
+++ b/tempest/tests/lib/services/compute/test_servers_client.py
@@ -154,7 +154,7 @@
         "request_id": "16fb98f-46ca-475e-917e-2563e5a8cd19",
         "user_id": "16fb98f-46ca-475e-917e-2563e5a8cd12",
         "project_id": "16fb98f-46ca-475e-917e-2563e5a8cd34",
-        "start_time": "09MAR2015 11:15",
+        "start_time": "2016-10-02T10:00:00-05:00",
         "message": "fake-msg",
         "instance_uuid": "16fb98f-46ca-475e-917e-2563e5a8cd12"
     }
@@ -166,8 +166,8 @@
 
     FAKE_INSTANCE_ACTION_EVENTS = {
         "event": "fake-event",
-        "start_time": "09MAR2015 11:15",
-        "finish_time": "09MAR2015 11:15",
+        "start_time": "2016-10-02T10:00:00-05:00",
+        "finish_time": "2016-10-02T10:00:00-05:00",
         "result": "fake-result",
         "traceback": "fake-trace-back"
     }
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)
diff --git a/tempest/tests/lib/test_rest_client.py b/tempest/tests/lib/test_rest_client.py
index e6cf047..4a83631 100644
--- a/tempest/tests/lib/test_rest_client.py
+++ b/tempest/tests/lib/test_rest_client.py
@@ -337,6 +337,10 @@
     def test_response_410(self):
         self._test_error_checker(exceptions.Gone, self.set_data("410"))
 
+    def test_response_412(self):
+        self._test_error_checker(exceptions.PreconditionFailed,
+                                 self.set_data("412"))
+
     def test_response_413(self):
         self._test_error_checker(exceptions.OverLimit, self.set_data("413"))
 
@@ -460,7 +464,7 @@
 
     def test_response_bigger_than_400(self):
         # Any response code, that bigger than 400, and not in
-        # (401, 403, 404, 409, 413, 422, 500, 501)
+        # (401, 403, 404, 409, 412, 413, 422, 500, 501)
         self._test_error_checker(exceptions.UnexpectedResponseCode,
                                  self.set_data("402"))
 
diff --git a/tempest/tests/lib/test_ssh.py b/tempest/tests/lib/test_ssh.py
index 8a0a84c..a16da1c 100644
--- a/tempest/tests/lib/test_ssh.py
+++ b/tempest/tests/lib/test_ssh.py
@@ -75,7 +75,54 @@
             key_filename=None,
             look_for_keys=False,
             timeout=10.0,
-            password=None
+            password=None,
+            sock=None
+        )]
+        self.assertEqual(expected_connect, client_mock.connect.mock_calls)
+        self.assertEqual(0, s_mock.call_count)
+
+    def test_get_ssh_connection_over_ssh(self):
+        c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
+        proxy_client_mock = mock.MagicMock()
+        proxy_client_mock.connect.return_value = True
+        s_mock = self.patch('time.sleep')
+
+        c_mock.side_effect = [client_mock, proxy_client_mock]
+        aa_mock.return_value = mock.sentinel.aa
+
+        proxy_client = ssh.Client('proxy-host', 'proxy-user', timeout=2)
+        client = ssh.Client('localhost', 'root', timeout=2,
+                            proxy_client=proxy_client)
+        client._get_ssh_connection(sleep=1)
+
+        aa_mock.assert_has_calls([mock.call(), mock.call()])
+        proxy_client_mock.set_missing_host_key_policy.assert_called_once_with(
+            mock.sentinel.aa)
+        proxy_expected_connect = [mock.call(
+            'proxy-host',
+            port=22,
+            username='proxy-user',
+            pkey=None,
+            key_filename=None,
+            look_for_keys=False,
+            timeout=10.0,
+            password=None,
+            sock=None
+        )]
+        self.assertEqual(proxy_expected_connect,
+                         proxy_client_mock.connect.mock_calls)
+        client_mock.set_missing_host_key_policy.assert_called_once_with(
+            mock.sentinel.aa)
+        expected_connect = [mock.call(
+            'localhost',
+            port=22,
+            username='root',
+            pkey=None,
+            key_filename=None,
+            look_for_keys=False,
+            timeout=10.0,
+            password=None,
+            sock=proxy_client_mock.get_transport().open_session()
         )]
         self.assertEqual(expected_connect, client_mock.connect.mock_calls)
         self.assertEqual(0, s_mock.call_count)