Merge "Test live migration back and forth"
diff --git a/HACKING.rst b/HACKING.rst
index a209b3f..c0a857c 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -170,7 +170,7 @@
 All negative tests should be based on `API-WG guideline`_ . Such negative
 tests can block any changes from accurate failure code to invalid one.
 
-.. _API-WG guideline: https://github.com/openstack/api-wg/blob/master/guidelines/http.rst#failure-code-clarifications
+.. _API-WG guideline: http://specs.openstack.org/openstack/api-wg/guidelines/http.html#failure-code-clarifications
 
 If facing some gray area which is not clarified on the above guideline, propose
 a new guideline to the API-WG. With a proposal to the API-WG we will be able to
@@ -246,7 +246,7 @@
 to the config variables in tempest/config.py then the sample config file must be
 regenerated. This can be done running::
 
-  tox -egenconfig
+  tox -e genconfig
 
 Unit Tests
 ----------
@@ -313,7 +313,7 @@
 qualified test name and track test functionality through refactoring. The
 format of the metadata looks like::
 
-    @test.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997')
+    @decorators.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997')
     def test_list_servers_with_detail(self):
         # The created server should be in the detailed list of all servers
         ...
diff --git a/README.rst b/README.rst
index 281516b..ac93992 100644
--- a/README.rst
+++ b/README.rst
@@ -4,7 +4,6 @@
 
 .. image:: http://governance.openstack.org/badges/tempest.svg
     :target: http://governance.openstack.org/reference/tags/index.html
-    :remote:
 
 .. Change things from this point on
 
@@ -105,7 +104,7 @@
     $ tempest run
 
    from the Tempest workspace directory. Or you can use the ``--workspace``
-   argument to run in the workspace you created regarless of your current
+   argument to run in the workspace you created regardless of your current
    working directory. For example::
 
     $ tempest run --workspace cloud-01
@@ -173,7 +172,7 @@
 You can generate a new sample tempest.conf file, run the following
 command from the top level of the Tempest directory::
 
-    $ tox -egenconfig
+    $ tox -e genconfig
 
 The most important pieces that are needed are the user ids, openstack
 endpoint, and basic flavors and images needed to run tests.
@@ -209,15 +208,9 @@
 Python 3.x
 ----------
 
-Starting during the Liberty release development cycle work began on enabling
-Tempest to run under both Python 2.7 and Python 3.4. Tempest strives to fully
-support running with Python 3.4 and newer. A gating unit test job was added to
-also run Tempest's unit tests under Python 3. This means that the Tempest
-code at least imports under Python 3.4 and things that have unit test coverage
-will work on Python 3.4. However, because large parts of Tempest are
-self-verifying there might be uncaught issues running on Python 3. So until
-there is a gating job which does a full Tempest run using Python 3 there
-isn't any guarantee that running Tempest under Python 3 is bug free.
+Starting during the Pike cycle Tempest has a gating CI job that runs tempest
+with Python 3. Any tempest release after 15.0.0 should fully support running
+under Python 3 as well as Python 2.7.
 
 Legacy run method
 -----------------
@@ -263,15 +256,13 @@
 
     $ testr run tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_reboot_non_existent_server
 
-Alternatively, you can use the run_tempest.sh script which will create a venv
-and run the tests or use tox to do the same. Tox also contains several existing
-job configurations. For example::
+Tox also contains several existing job configurations. For example::
 
-    $ tox -efull
+    $ tox -e full
 
 which will run the same set of tests as the OpenStack gate. (it's exactly how
 the gate invokes Tempest) Or::
 
-    $ tox -esmoke
+    $ tox -e smoke
 
 to run the tests tagged as smoke.
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 04ddfdf..2597f04 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -140,9 +140,8 @@
 git_cmd = ["git", "log", "--pretty=format:'%ad, commit %h'", "--date=local",
    "-n1"]
 try:
-    html_last_updated_fmt = subprocess.Popen(git_cmd,
-                                             stdout=subprocess.PIPE).\
-                                             communicate()[0]
+    html_last_updated_fmt = str(
+        subprocess.Popen(git_cmd, stdout=subprocess.PIPE).communicate()[0])
 except Exception:
     warnings.warn('Cannot get last updated time from git repository. '
                   'Not setting "html_last_updated_fmt".')
@@ -184,123 +183,5 @@
 # This is the file name suffix for HTML files (e.g. ".xhtml").
 #html_file_suffix = None
 
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'Tempestdoc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-#'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
-  ('index', 'Tempest.tex', u'Tempest Documentation',
-   u'OpenStack QA Team', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# If true, show page references after internal links.
-#latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
-    ('index', 'tempest', u'Tempest Documentation',
-     [u'OpenStack QA Team'], 1)
-]
-
-# If true, show URL addresses after external links.
-#man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-#  dir menu entry, description, category)
-texinfo_documents = [
-  ('index', 'Tempest', u'Tempest Documentation',
-   u'OpenStack QA Team', 'Tempest', 'One line description of project.',
-   'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
-
-# If false, no module index is generated.
-#texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
-
-
-# -- Options for Epub output ---------------------------------------------------
-
-# Bibliographic Dublin Core info.
-epub_title = u'Tempest'
-epub_author = u'Sean Dague'
-epub_publisher = u'OpenStack QA Team'
-epub_copyright = u'2013, OpenStack QA Team'
-
-# The language of the text. It defaults to the language option
-# or en if the language is not set.
-#epub_language = ''
-
-# The scheme of the identifier. Typical schemes are ISBN or URL.
-#epub_scheme = ''
-
-# The unique identifier of the text. This can be a ISBN number
-# or the project homepage.
-#epub_identifier = ''
-
-# A unique identification for the text.
-#epub_uid = ''
-
-# A tuple containing the cover image and cover page html template filenames.
-#epub_cover = ()
-
-# HTML files that should be inserted before the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-#epub_pre_files = []
-
-# HTML files shat should be inserted after the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-#epub_post_files = []
-
-# A list of files that should not be packed into the epub file.
-#epub_exclude_files = []
-
-# The depth of the table of contents in toc.ncx.
-#epub_tocdepth = 3
-
-# Allow duplicate toc entries.
-#epub_tocdup = True
+# A list of warning types to suppress arbitrary warning messages.
+suppress_warnings = ['image.nonlocal_uri']
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index 18269bf..2314222 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -9,6 +9,8 @@
 config file which explains the purpose of each individual option. You can see
 the sample config file here: :ref:`tempest-sampleconf`
 
+.. _tempest_cred_provider_conf:
+
 Test Credentials
 ----------------
 
@@ -232,6 +234,9 @@
 
 Enabling Remote Access to Created Servers
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. _tempest_conf_network_allocation:
+
 Network Creation/Usage for Servers
 """"""""""""""""""""""""""""""""""
 When Tempest creates servers for testing, some tests require being able to
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 896cd98..1264ecc 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -67,7 +67,8 @@
    HACKING
    REVIEWING
    microversion_testing
-   test-removal
+   test_removal
+   write_tests
 
 -------
 Plugins
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..adbd2dc 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -243,3 +243,13 @@
  * `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
+
+* Volume
+
+ * `3.3`_
+
+ .. _3.3:  https://docs.openstack.org/developer/cinder/devref/api_microversion_history.html#id4
diff --git a/doc/source/plugin.rst b/doc/source/plugin.rst
index 6b30825..b3af92f 100644
--- a/doc/source/plugin.rst
+++ b/doc/source/plugin.rst
@@ -1,3 +1,5 @@
+.. _tempest_plugin:
+
 =============================
 Tempest Test Plugin Interface
 =============================
diff --git a/doc/source/test-removal.rst b/doc/source/test_removal.rst
similarity index 86%
rename from doc/source/test-removal.rst
rename to doc/source/test_removal.rst
index 79a5846..d06e4ba 100644
--- a/doc/source/test-removal.rst
+++ b/doc/source/test_removal.rst
@@ -38,8 +38,10 @@
  #. The test proposed for removal has a failure rate <  0.50% in the gate over
     the past release (the value and interval will likely be adjusted in the
     future)
- #. There must not be an external user/consumer of tempest that depends on the
-    test proposed for removal
+
+    .. _`prong #3`:
+ #. There must not be an external user/consumer of tempest
+    that depends on the test proposed for removal
 
 The answers to 1 and 2 are easy to verify. For 1 just provide a link to the new
 test location. If you are linking to the tempest removal patch please also put
@@ -62,7 +64,7 @@
 
 SELECT * from tests where test_id like "%test_id%";
 (where $test_id is the full test_id, but truncated to the class because of
-setupClass or tearDownClass failures)
+setUpClass or tearDownClass failures)
 
 You can access the infra mysql subunit2sql db w/ read-only permissions with:
 
@@ -80,7 +82,7 @@
  #. run the query: MySQL [subunit2sql]> select * from tests where test_id like
     "tempest.api.compute.admin.test_flavors_negative.FlavorsAdminNegativeTestJSON%";
     which will return a table of all the tests in the class (but it will also
-    catch failures in setupClass and tearDownClass)
+    catch failures in setUpClass and tearDownClass)
  #. paste the output table with numbers and the mysql command you ran to
     generate it into the etherpad.
 
@@ -133,6 +135,10 @@
  #. A revert for a patch which added a broken test, or testing which didn't
     actually run in the gate (basically any revert for something which
     shouldn't have been added)
+ #. Tests that would become out of scope as a consequence of an API change,
+    as described in `API Compatibility`_.
+    Such tests cannot live in Tempest because of the branchless nature of
+    Tempest. Such test must still honor `prong #3`_.
 
 For the first exception type the only types of testing in tree which have been
 declared out of scope at this point are:
@@ -149,7 +155,7 @@
 Tempest Scope
 ^^^^^^^^^^^^^
 
-Also starting in the liberty cycle tempest has defined a set of projects which
+Starting in the liberty cycle tempest has defined a set of projects which
 are defined as in scope for direct testing in tempest. As of today that list
 is:
 
@@ -166,3 +172,17 @@
 to maintain continuity after migrating the tests out of tempest.
 
 .. _tempest plugin mechanism: http://docs.openstack.org/developer/tempest/plugin.html
+
+API Compatibility
+"""""""""""""""""
+
+If an API introduces a non-discoverable, backward incompatible change, and
+such change is not backported to all versions supported by Tempest, tests for
+that API cannot live in Tempest anymore.
+This is because tests would not be able to know or control which API response
+to expect, and thus would not be able to enforce a specific behavior.
+
+If a test exists in Tempest that would meet this criteria as consequence of a
+change, the test must be removed according to the procedure discussed into
+this document. The API change should not be merged until all conditions
+required for test removal can be met.
diff --git a/doc/source/write_tests.rst b/doc/source/write_tests.rst
new file mode 100644
index 0000000..768bf0f
--- /dev/null
+++ b/doc/source/write_tests.rst
@@ -0,0 +1,243 @@
+.. _tempest_test_writing:
+
+Tempest Test Writing Guide
+==========================
+
+This guide serves as a starting point for developers working on writing new
+Tempest tests. At a high level tests in Tempest are just tests that conform to
+the standard python `unit test`_ framework. But there are several aspects of
+that are unique to tempest and it's role as an integration test suite running
+against a real cloud.
+
+.. _unit test: https://docs.python.org/3.6/library/unittest.html
+
+.. note:: This guide is for writing tests in the tempest repository. While many
+          parts of this guide are also applicable to tempest plugins, not all
+          the APIs mentioned are considered stable or recommended for use in
+          plugins. Please refer to :ref:`tempest_plugin` for details about
+          writing plugins
+
+
+Adding a New TestCase
+=====================
+
+The base unit of testing in Tempest is the `TestCase`_ (also called the test
+class). Each TestCase contains test methods which are the individual tests that
+will be executed by the test runner. But, the TestCase is the smallest self
+contained unit for tests from the tempest perspective. It's also the level at
+which tempest is parallel safe. In other words, multiple TestCases can be
+executed in parallel, but individual test methods in the same TestCase can not.
+Also, all test methods within a TestCase are assumed to be executed serially. As
+such you can use the test case to store variables that are shared between
+methods.
+
+.. _TestCase: https://docs.python.org/3.6/library/unittest.html#unittest.TestCase
+
+In standard unittest the lifecycle of a TestCase can be described in the
+following phases:
+
+ #. setUpClass
+ #. setUp
+ #. Test Execution
+ #. tearDown
+ #. doCleanups
+ #. tearDownClass
+
+setUpClass
+----------
+
+The setUpClass phase is the first phase executed by the test runner and is used
+to perform any setup required for all the test methods to be executed. In
+Tempest this is a very important step and will automatically do the necessary
+setup for interacting with the configured cloud.
+
+To accomplish this you do **not** define a setUpClass function, instead there
+are a number of predefined phases to setUpClass that are used. The phases are:
+
+ * skip_checks
+ * setup_credentials
+ * setup_clients
+ * resource_setup
+
+which is executed in that order. An example of a TestCase which defines all
+of these would be::
+
+  from tempest import config
+  from tempest import test
+
+  CONF = config.CONF
+
+
+  class TestExampleCase(test.BaseTestCase):
+
+    @classmethod
+    def skip_checks(cls):
+        """This section is used to evaluate config early and skip all test
+           methods based on these checks
+        """
+        super(TestExampleCase, cls).skip_checks()
+        if not CONF.section.foo
+            cls.skip('A helpful message')
+
+    @classmethod
+    def setup_credentials(cls):
+        """This section is used to do any manual credential allocation and also
+           in the case of dynamic credentials to override the default network
+           resource creation/auto allocation
+        """
+        # This call is used to tell the credential allocator to not create any
+        # network resources for this test case. It also enables selective
+        # creation of other neutron resources. NOTE: it must go before the
+        # super call
+        cls.set_network_resources()
+        super(TestExampleCase, cls).setup_credentials()
+
+    @classmethod
+    def setup_clients(cls):
+        """This section is used to setup client aliases from the manager object
+           or to initialize any additional clients. Except in a few very
+           specific situations you should not need to use this.
+        """
+        super(TestExampleCase, cls).setup_clients()
+        cls.servers_client = cls.os.servers_client
+
+    @classmethod
+    def resource_setup(cls):
+        """This section is used to create any resources or objects which are
+           going to be used and shared by **all** test methods in the
+           TestCase. Note then anything created in this section must also be
+           destroyed in the corresponding resource_cleanup() method (which will
+           be run during tearDownClass())
+        """
+        super(TestExampleCase, cls).resource_setup()
+        cls.shared_server = cls.servers_client.create_server(...)
+
+
+Allocating Credentials
+''''''''''''''''''''''
+
+Since Tempest tests are all about testing a running cloud, every test will need
+credentials to be able to make API requests against the cloud. Since this is
+critical to operation and, when running in parallel, easy to make a mistake,
+the base TestCase class will automatically allocate a regular user for each
+TestCase during the setup_credentials() phase. During this process it will also
+initialize a client manager object using those credentials, which will be your
+entry point into interacting with the cloud. For more details on how credentials
+are allocated the :ref:`tempest_cred_provider_conf` section of the Tempest
+Configuration Guide provides more details on the operation of this.
+
+There are some cases when you need more than a single set of credentials, or
+credentials with a more specialized set of roles. To accomplish this you have
+to set a class variable ``credentials`` on the TestCase directly. For example::
+
+    from tempest import test
+
+    class TestExampleAdmin(test.BaseTestCase):
+
+        credentials = ['primary', 'admin']
+
+    @classmethod
+    def skip_checks(cls):
+    ...
+
+In this example the ``TestExampleAdmin`` TestCase will allocate 2 sets of
+credentials, one regular user and one admin user. The corresponding manager
+objects will be set as class variables cls.os and cls.os_adm respectively. You
+can also allocate a second user by putting **'alt'** in the list too. A set of
+alt credentials are the same as primary but can be used for tests cases that
+need a second user/project.
+
+You can also specify credentials with specific roles assigned. This is useful
+for cases where there are specific RBAC requirements hard coded into an API.
+The canonical example of this are swift tests which often want to test swift's
+concepts of operator and reseller_admin. An actual example from tempest on how
+to do this is::
+
+    class PublicObjectTest(base.BaseObjectTest):
+
+        credentials = [['operator', CONF.object_storage.operator_role],
+                       ['operator_alt', CONF.object_storage.operator_role]]
+
+        @classmethod
+        def setup_credentials(cls):
+            super(PublicObjectTest, cls).setup_credentials()
+            ...
+
+In this case the manager objects will be set to ``cls.os_roles_operator`` and
+``cls.os_roles_operator_alt`` respectively.
+
+
+There is no limit to how many credentials you can allocate in this manner,
+however in almost every case you should **not** need more than 3 sets of
+credentials per test case.
+
+To figure out the mapping of manager objects set on the TestCase and the
+requested credentials you can reference:
+
++-------------------+---------------------+
+| Credentials Entry | Manager Variable    |
++===================+=====================+
+| primary           | cls.os              |
++-------------------+---------------------+
+| admin             | cls.os_adm          |
++-------------------+---------------------+
+| alt               | cls.os_alt          |
++-------------------+---------------------+
+| [$label, $role]   | cls.os_roles_$label |
++-------------------+---------------------+
+
+By default cls.os is available since it is allocated in the base tempest test
+class. (located in tempest/test.py) If your TestCase inherits from a different
+direct parent class (it'll still inherit from the BaseTestCase, just not
+directly) be sure to check if that class overrides allocated credentials.
+
+Dealing with Network Allocation
+'''''''''''''''''''''''''''''''
+
+When neutron is enabled and a testing requires networking this isn't normally
+automatically setup when a tenant is created. Since tempest needs isolated
+tenants to function properly it also needs to handle network allocation. By
+default the base test class will allocate a network, subnet, and router
+automatically. (this depends on the configured credential provider, for more
+details see: :ref:`tempest_conf_network_allocation`) However, there are
+situations where you do no need all of these resources allocated. (or your
+TestCase inherits from a class that overrides the default in tempest/test.py)
+There is a class level mechanism to override this allocation and specify which
+resources you need. To do this you need to call `cls.set_network_resources()`
+in the `setup_credentials()` method before the `super()`. For example::
+
+  from tempest import test
+
+
+  class TestExampleCase(test.BaseTestCase):
+
+  @classmethod
+  def setup_credentials(cls):
+      cls.set_network_resources(network=True, subnet=True, router=False)
+      super(TestExampleCase, cls).setup_credentials()
+
+There are 2 quirks with the usage here. First for the set_network_resources
+function to work properly it **must be called before super()**. This is so
+that children classes' settings are always used instead of a parent classes'.
+The other quirk here is that if you do not want to allocate any network
+resources for your test class simply call `set_network_resources()` without
+any arguments. For example::
+
+  from tempest import test
+
+
+  class TestExampleCase(test.BaseTestCase):
+
+  @classmethod
+  def setup_credentials(cls):
+      cls.set_network_resources()
+      super(TestExampleCase, cls).setup_credentials()
+
+This will not allocate any networking resources. This is because by default all
+the arguments default to False.
+
+It's also worth pointing out that it is common for base test classes for
+different services (and scenario tests) to override this setting. When
+inheriting from classes other than the base TestCase in tempest/test.py it is
+worth checking the immediate parent for what is set to determine if your
+class needs to override that setting.
diff --git a/releasenotes/notes/12.2.0-clients_module-16f3025f515bf9ec.yaml b/releasenotes/notes/12.2.0-clients_module-16f3025f515bf9ec.yaml
index 484d543..d07448a 100644
--- a/releasenotes/notes/12.2.0-clients_module-16f3025f515bf9ec.yaml
+++ b/releasenotes/notes/12.2.0-clients_module-16f3025f515bf9ec.yaml
@@ -4,7 +4,7 @@
     plugins to declare and automatically register any service client defined
     in the plugin.
   - tempest.lib exposes a new stable interface, the clients module and
-    ServiceClients class, which provides a convinient way for plugin tests to
+    ServiceClients class, which provides a convenient way for plugin tests to
     access service clients defined in Tempest as well as service clients
     defined in all loaded plugins.
     The new ServiceClients class only exposes for now the service clients
diff --git a/releasenotes/notes/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml b/releasenotes/notes/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml
index 543cf7b..52c04af 100644
--- a/releasenotes/notes/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml
+++ b/releasenotes/notes/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml
@@ -2,4 +2,4 @@
 deprecations:
   - The ``call_until_true`` function is moved from the ``tempest.test`` module
    to the ``tempest.lib.common.utils.test_utils`` module. Backward
-   compatibilty is preserved until Ocata.
+   compatibility is preserved until Ocata.
diff --git a/releasenotes/notes/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml b/releasenotes/notes/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml
index 20f310d..813e47f 100644
--- a/releasenotes/notes/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml
+++ b/releasenotes/notes/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml
@@ -1,5 +1,5 @@
 ---
 upgrade:
-  - the already depreacted tempest-cleanup standalone command has been
+  - the already deprecated tempest-cleanup standalone command has been
     removed. The corresponding functionalities can be accessed through
     the unified `tempest` command (`tempest cleanup`).
diff --git a/releasenotes/notes/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml b/releasenotes/notes/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml
index aa3a78e..389b29f 100644
--- a/releasenotes/notes/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml
+++ b/releasenotes/notes/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml
@@ -1,4 +1,13 @@
 ---
+prelude: >
+  This release is marking the end of Liberty release support in Tempest
 upgrade:
   - The Stress tests framework and all the stress tests have been removed.
+other:
+  - |
+    OpenStack releases supported at this time are **Mitaka** and **Newton**.
 
+    The release under current development as of this tag is Ocata, meaning that
+    every Tempest commit is also tested against master during the Ocata cycle.
+    However, this does not necessarily mean that using Tempest as of this tag
+    will work against a Ocata (or future releases) cloud.
diff --git a/releasenotes/notes/add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml b/releasenotes/notes/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml
similarity index 100%
rename from releasenotes/notes/add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml
rename to releasenotes/notes/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml
diff --git a/releasenotes/notes/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml b/releasenotes/notes/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml
new file mode 100644
index 0000000..eaab1f0
--- /dev/null
+++ b/releasenotes/notes/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml
@@ -0,0 +1,10 @@
+---
+features:
+  - |
+    As in the [doc]:
+    http://developer.openstack.org/api-ref/image/v2/metadefs-index.html,
+    there are some apis are not included, add them.
+
+      * namespace_objects_client(v2)
+      * namespace_tags_client(v2)
+
diff --git a/releasenotes/notes/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml b/releasenotes/notes/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml
new file mode 100644
index 0000000..9116ef8
--- /dev/null
+++ b/releasenotes/notes/15.0.0-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/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml b/releasenotes/notes/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml
new file mode 100644
index 0000000..9a4e6b1
--- /dev/null
+++ b/releasenotes/notes/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml
@@ -0,0 +1,8 @@
+---
+features:
+  - |
+    Define v2 snapshot_manage_client client for the volume service as
+    library interfaces, allowing other projects to use this module as
+    stable libraries without maintenance changes.
+
+    * snapshot_manage_client(v2)
diff --git a/releasenotes/notes/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml b/releasenotes/notes/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml
new file mode 100644
index 0000000..4acdc6d
--- /dev/null
+++ b/releasenotes/notes/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+  - The default value for the ``allow_port_security_disabled`` option in the
+    ``compute-feature-enabled`` section has been changed from ``False``
+    to ``True``.
+deprecations:
+  - The ``allow_port_security_disabled`` option in the
+   ``compute-feature-enabled`` section is now deprecated.
diff --git a/releasenotes/notes/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml b/releasenotes/notes/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml
new file mode 100644
index 0000000..c0a06d1
--- /dev/null
+++ b/releasenotes/notes/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+  - The default value for the ``reseller`` option in the
+    ``identity-feature-enabled`` section has been changed from ``False``
+    to ``True``.
+deprecations:
+  - The ``reseller`` option in the ``identity-feature-enabled`` section is now
+    deprecated.
diff --git a/releasenotes/notes/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml b/releasenotes/notes/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml
new file mode 100644
index 0000000..c80f159
--- /dev/null
+++ b/releasenotes/notes/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+  - The default value for the ``volume_services`` option in the
+    ``volume_feature_enabled`` section has been changed from ``False``
+    to ``True``.
+deprecations:
+  - The ``volume_services`` option in the ``volume_feature_enabled`` section
+    is now deprecated.
diff --git a/releasenotes/notes/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml b/releasenotes/notes/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml
new file mode 100644
index 0000000..8817ed4
--- /dev/null
+++ b/releasenotes/notes/15.0.0-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/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml b/releasenotes/notes/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml
new file mode 100644
index 0000000..b1c0c62
--- /dev/null
+++ b/releasenotes/notes/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml
@@ -0,0 +1,9 @@
+---
+upgrade:
+  - The deprecated compute microversion config options from
+    'compute-feature-enabled' group have been removed. Those config options
+    are available under 'compute' group to configure the min and max
+    microversion for compute service.
+
+    * CONF.compute.min_microversion
+    * CONF.compute.max_microversion
diff --git a/releasenotes/notes/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml b/releasenotes/notes/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml
new file mode 100644
index 0000000..104bf27
--- /dev/null
+++ b/releasenotes/notes/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml
@@ -0,0 +1,25 @@
+---
+prelude: >
+    This release is marking the start of Ocata release support in Tempest
+upgrade:
+  - |
+    Below deprecated config options from compute group have been removed.
+    Corresponding config options already been available in validation group.
+
+    - ``compute.use_floatingip_for_ssh`` (available as ``validation.connect_method``)
+    - ``compute.ssh_auth_method`` (available as ``validation.auth_method``)
+    - ``compute.image_ssh_password`` (available as ``validation.image_ssh_password``)
+    - ``compute.ssh_shell_prologue`` (available as ``validation.ssh_shell_prologue``)
+    - ``compute.ping_size `` (available as ``validation.ping_size``)
+    - ``compute.ping_count `` (available as ``validation.ping_count``)
+    - ``compute.floating_ip_range `` (available as ``validation.floating_ip_range``)
+other:
+  - |
+    OpenStack releases supported at this time are **Mitaka**, **Newton**,
+    and **Ocata**.
+
+    The release under current development as of this tag is Pike,
+    meaning that every Tempest commit is also tested against master during
+    the Pike cycle. However, this does not necessarily mean that using
+    Tempest as of this tag will work against a Pike (or future releases)
+    cloud.
diff --git a/releasenotes/notes/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml b/releasenotes/notes/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml
new file mode 100644
index 0000000..371c061
--- /dev/null
+++ b/releasenotes/notes/15.0.0-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/notes/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml b/releasenotes/notes/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml
new file mode 100644
index 0000000..e445fb3
--- /dev/null
+++ b/releasenotes/notes/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml
@@ -0,0 +1,11 @@
+---
+upgrade:
+  - |
+    Below deprecated network config options have been removed.
+    Those config options already been renamed to below meaningful names.
+
+    - ``tenant_network_cidr`` (removed) -> ``project_network_cidr``
+    - ``tenant_network_mask_bits`` (removed) -> ``project_network_mask_bits``
+    - ``tenant_network_v6_cidr`` (removed) -> ``project_network_v6_cidr``
+    - ``tenant_network_v6_mask_bits`` (removed) -> ``project_network_v6_mask_bits``
+    - ``tenant_networks_reachable`` (removed) -> ``project_networks_reachable``
diff --git a/releasenotes/notes/add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml b/releasenotes/notes/add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml
new file mode 100644
index 0000000..6b45666
--- /dev/null
+++ b/releasenotes/notes/add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml
@@ -0,0 +1,3 @@
+---
+features:
+  - Add a new client to handle the OAUTH consumers feature from the identity API.
diff --git a/releasenotes/notes/add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml b/releasenotes/notes/add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml
new file mode 100644
index 0000000..01136c6
--- /dev/null
+++ b/releasenotes/notes/add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - |
+    Add missing API call, list all role inference rules,
+    to the roles_client library. This feature enables the
+    possibility of listing all role inference rules in the
+    system.
diff --git a/releasenotes/notes/add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml b/releasenotes/notes/add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml
new file mode 100644
index 0000000..848a21b
--- /dev/null
+++ b/releasenotes/notes/add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml
@@ -0,0 +1,3 @@
+---
+features:
+    - Define the compute server evacuate client method in the servers_client library.
diff --git a/releasenotes/notes/add-content-type-without-spaces-b2c9b91b257814f3.yaml b/releasenotes/notes/add-content-type-without-spaces-b2c9b91b257814f3.yaml
new file mode 100644
index 0000000..0075a36
--- /dev/null
+++ b/releasenotes/notes/add-content-type-without-spaces-b2c9b91b257814f3.yaml
@@ -0,0 +1,9 @@
+---
+upgrade:
+  - The ``JSON_ENC`` and ``TXT_ENC`` option in the ``_error_checker``
+    section have been added with additional content-type which are
+    defined in RFC7231 but missing in the currnt rest_client.py file.
+    The lack of these additional content-type will cause defcore test
+    to fail for OpenStack public cloud which uses tomcat module in the
+    api gateway. The additions are ``application/json;charset=utf-8``,
+    ``text/html;charset=utf-8``,``text/plain;charset=utf-8``
\ No newline at end of file
diff --git a/releasenotes/notes/add-list-auth-project-client-5905076d914a3943.yaml b/releasenotes/notes/add-list-auth-project-client-5905076d914a3943.yaml
new file mode 100644
index 0000000..471f8f0
--- /dev/null
+++ b/releasenotes/notes/add-list-auth-project-client-5905076d914a3943.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add the list auth projects API to the identity client library. This feature
+    enables the possibility to list projects that are available to be scoped
+    to based on the X-Auth-Token provided in the request.
diff --git a/releasenotes/notes/add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml b/releasenotes/notes/add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml
new file mode 100644
index 0000000..acc7a41
--- /dev/null
+++ b/releasenotes/notes/add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add versions_client module for image service.
+    This new module provides list_versions() method which shows API versions
+    from Image service.
diff --git a/releasenotes/notes/add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml b/releasenotes/notes/add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml
new file mode 100644
index 0000000..67f9541
--- /dev/null
+++ b/releasenotes/notes/add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add the list security groups by server API to the servers_client
+    library. This feature enables the possibility to list security
+    groups for a server instance.
diff --git a/releasenotes/notes/add-list-version-to-identity-client-944cb7396088a575.yaml b/releasenotes/notes/add-list-version-to-identity-client-944cb7396088a575.yaml
new file mode 100644
index 0000000..dd66ff5
--- /dev/null
+++ b/releasenotes/notes/add-list-version-to-identity-client-944cb7396088a575.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add versions_client module for identity service.
+    This new module provides list_versions() method which shows API versions
+    from Identity service.
diff --git a/releasenotes/notes/add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml b/releasenotes/notes/add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml
new file mode 100644
index 0000000..233cc28
--- /dev/null
+++ b/releasenotes/notes/add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add versions_client module for volume service.
+    This new module provides list_versions() method which shows API versions
+    from Volume service.
diff --git a/releasenotes/notes/add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml b/releasenotes/notes/add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml
new file mode 100644
index 0000000..06f4fcd
--- /dev/null
+++ b/releasenotes/notes/add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Interface show_quota_set of compute quotas_client has been extended to include the
+    argument "detail", which allows for detailed quota set information for a project to be
+    retrieved, if set to True.
diff --git a/releasenotes/notes/add-tempest-lib-remote-client-adbeb3f42a36910b.yaml b/releasenotes/notes/add-tempest-lib-remote-client-adbeb3f42a36910b.yaml
new file mode 100644
index 0000000..1b8cda2
--- /dev/null
+++ b/releasenotes/notes/add-tempest-lib-remote-client-adbeb3f42a36910b.yaml
@@ -0,0 +1,11 @@
+---
+features:
+  - |
+    Add remote_client under tempest.lib.
+    This remote_client under tempest.lib is defined as stable
+    interface, and now this module provides the following
+    essential methods.
+
+    - exec_command
+    - validate_authentication
+    - ping_host
diff --git a/releasenotes/notes/add-tempest-run-combine-option-e94c1049ba8985d5.yaml b/releasenotes/notes/add-tempest-run-combine-option-e94c1049ba8985d5.yaml
new file mode 100644
index 0000000..73900ca
--- /dev/null
+++ b/releasenotes/notes/add-tempest-run-combine-option-e94c1049ba8985d5.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Adds a new cli option to tempest run, --combine, which is used to indicate
+    you want the subunit stream output combined with the previous run's in
+    the testr repository
diff --git a/releasenotes/notes/add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml b/releasenotes/notes/add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml
new file mode 100644
index 0000000..c95e77c
--- /dev/null
+++ b/releasenotes/notes/add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add update encryption type API to the v2 encryption_types_client library.
+    This feature enables the possibility to update an encryption type for an
+    existing volume type.
diff --git a/releasenotes/notes/add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml b/releasenotes/notes/add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml
new file mode 100644
index 0000000..3453050
--- /dev/null
+++ b/releasenotes/notes/add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml
@@ -0,0 +1,9 @@
+---
+features:
+  - |
+    Add the unmanage volume API service method in v2 volumes_client library.
+    Define v2 volume_manage_client client for the volume service as library
+    interfaces, allowing other projects to use this module as stable libraries
+    without maintenance changes.
+
+    * volume_manage_client(v2)
diff --git a/releasenotes/notes/create-server-tags-client-8c0042a77e859af6.yaml b/releasenotes/notes/create-server-tags-client-8c0042a77e859af6.yaml
new file mode 100644
index 0000000..9927971
--- /dev/null
+++ b/releasenotes/notes/create-server-tags-client-8c0042a77e859af6.yaml
@@ -0,0 +1,8 @@
+---
+features:
+  - |
+    Add server tags APIs to the servers_client library.
+    This feature enables the possibility of upating, deleting
+    and checking existence of a tag on a server, as well
+    as updating and deleting all tags on a server.
+
diff --git a/releasenotes/notes/deprecate-deactivate_image-config-7a282c471937bbcb.yaml b/releasenotes/notes/deprecate-deactivate_image-config-7a282c471937bbcb.yaml
new file mode 100644
index 0000000..69c6bb6
--- /dev/null
+++ b/releasenotes/notes/deprecate-deactivate_image-config-7a282c471937bbcb.yaml
@@ -0,0 +1,6 @@
+---
+deprecations:
+  - |
+    The ``deactivate_image`` configuration switch from the ``config`` module
+    is deprecated. It was added to support the older-than-kilo releases
+    which we don't support anymore.
diff --git a/releasenotes/notes/deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml b/releasenotes/notes/deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml
new file mode 100644
index 0000000..c3e43ee
--- /dev/null
+++ b/releasenotes/notes/deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml
@@ -0,0 +1,7 @@
+---
+deprecations:
+  - |
+    The ``dvr_extra_resources`` configuration switch from the ``config`` module
+    is deprecated. It was added to support the Liberty Release which we don't
+    support anymore.
+
diff --git a/releasenotes/notes/deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml b/releasenotes/notes/deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml
new file mode 100644
index 0000000..788bc95
--- /dev/null
+++ b/releasenotes/notes/deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml
@@ -0,0 +1,10 @@
+---
+deprecations:
+  - |
+    Glance v1 APIs are deprecated and v2 are current.
+    Tempest should tests only v2 APIs.
+    Below API version selection config options
+    for glance have been deprecated and will be removed in future.
+
+    * CONF.image_feature_enabled.api_v2
+    * CONF.image_feature_enabled.api_v1
diff --git a/releasenotes/notes/deprecate-resources-prefix-option-ad490c0a30a0266b.yaml b/releasenotes/notes/deprecate-resources-prefix-option-ad490c0a30a0266b.yaml
new file mode 100644
index 0000000..f679208
--- /dev/null
+++ b/releasenotes/notes/deprecate-resources-prefix-option-ad490c0a30a0266b.yaml
@@ -0,0 +1,10 @@
+---
+upgrade:
+  - The default value of rand_name()'s prefix argument is changed
+    to 'tempest' from None to identify resources are created by
+    Tempest.
+deprecations:
+  - The resources_prefix is marked as deprecated because it is
+    enough to set 'tempest' as the prefix on rand_name() to
+    ideintify resources which are created by Tempest and no
+    projects set this option on OpenStack dev community.
diff --git a/releasenotes/notes/deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml b/releasenotes/notes/deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml
new file mode 100644
index 0000000..4d8b941
--- /dev/null
+++ b/releasenotes/notes/deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml
@@ -0,0 +1,5 @@
+---
+deprecations:
+  - The ``skip_unless_attr`` decorator in lib/decorators.py has been deprecated,
+    please use the standard ``testtools.skipUnless`` and ``testtools.skipIf``
+    decorators.
diff --git a/releasenotes/notes/deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml b/releasenotes/notes/deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml
new file mode 100644
index 0000000..6285ea6
--- /dev/null
+++ b/releasenotes/notes/deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml
@@ -0,0 +1,5 @@
+---
+deprecations:
+  - The ``skip_unless_config`` and ``skip_if_config`` decorators in the
+    ``config`` module have been deprecated and will be removed in the Queens
+    dev cycle. Use the ``testtools.skipUnless`` (or a variation of) instead.
diff --git a/releasenotes/notes/deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml b/releasenotes/notes/deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml
new file mode 100644
index 0000000..0660d9c
--- /dev/null
+++ b/releasenotes/notes/deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml
@@ -0,0 +1,12 @@
+---
+deprecations:
+  - |
+    Volume v1 API is deprecated and the v3 are CURRENT.
+    Tempest doesn't need to test the v1 API as the default.
+    The volume config option 'api_v1' has been marked as
+    deprecated.
+upgrade:
+  - |
+    The volume config option 'api_v1' default is changed to
+    ``False`` because the volume v1 API has been deprecated
+    since Juno release.
diff --git a/releasenotes/notes/fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml b/releasenotes/notes/fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml
new file mode 100644
index 0000000..6d31576
--- /dev/null
+++ b/releasenotes/notes/fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+  - |
+    Fix below volume v2 service clients to make v2 API call: Bug#1667354
+
+    - SchedulerStatsClient
+    - CapabilitiesClient
diff --git a/releasenotes/notes/remove-call_until_true-of-test-de9c13bc8f969921.yaml b/releasenotes/notes/remove-call_until_true-of-test-de9c13bc8f969921.yaml
new file mode 100644
index 0000000..5670821
--- /dev/null
+++ b/releasenotes/notes/remove-call_until_true-of-test-de9c13bc8f969921.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+  - The *call_until_true* of *test* module is removed because it was marked
+    as deprecated and Tempest provides it from *test_utils* as a stable
+    interface instead. Please switch to use *test_utils.call_until_true* if
+    necessary.
diff --git a/releasenotes/notes/remove-cinder-v1-api-tests-71e266b8d55d475f.yaml b/releasenotes/notes/remove-cinder-v1-api-tests-71e266b8d55d475f.yaml
new file mode 100644
index 0000000..710ad9e
--- /dev/null
+++ b/releasenotes/notes/remove-cinder-v1-api-tests-71e266b8d55d475f.yaml
@@ -0,0 +1,5 @@
+upgrade:
+  - Remove Cinder v1 API tests.
+    Cinder v1 API has been deprecated since Juno release, and Juno is
+    not supported by current Tempest. Then Cinder v1 API tests are
+    removed from Tempest.
diff --git a/releasenotes/notes/remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml b/releasenotes/notes/remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml
new file mode 100644
index 0000000..9d7102f
--- /dev/null
+++ b/releasenotes/notes/remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml
@@ -0,0 +1,5 @@
+---
+upgrade:
+  - |
+    The deprecated config option 'allow_port_security_disabled' from compute_feature_enabled
+    group has been removed.
diff --git a/releasenotes/notes/remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml b/releasenotes/notes/remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml
new file mode 100644
index 0000000..b4e4dd1
--- /dev/null
+++ b/releasenotes/notes/remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml
@@ -0,0 +1,11 @@
+---
+upgrade:
+  - |
+    Below deprecated config options from compute group have been removed.
+    Corresponding config options already been available in validation group.
+
+    - ``compute.image_ssh_user`` (available as ``validation.image_ssh_user``)
+    - ``compute.ssh_user`` (available as ``validation.image_ssh_user``)
+    - ``scenario.ssh_user`` (available as ``validation.image_ssh_user``)
+    - ``compute.network_for_ssh`` (available as ``validation.network_for_ssh``)
+    - ``compute.ping_timeout `` (available as ``validation.ping_timeout``)
diff --git a/releasenotes/notes/remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml b/releasenotes/notes/remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml
new file mode 100644
index 0000000..889e862
--- /dev/null
+++ b/releasenotes/notes/remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+  - |
+    The deprecated config option 'dvr_extra_resources' from network group has been removed.
+    This option was for extra resources which were provisioned to bind a router to Neutron
+    L3 agent. The extra resources need to be provisioned in Liberty release or older,
+    and are not required since Mitaka release. Current Tempest doesn't support Liberty, so
+    this option has been removed from Tempest.
diff --git a/releasenotes/notes/remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml b/releasenotes/notes/remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml
new file mode 100644
index 0000000..8085694
--- /dev/null
+++ b/releasenotes/notes/remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml
@@ -0,0 +1,4 @@
+---
+upgrade:
+  - |
+    The deprecated config option 'reseller' from identity_feature_enabled group has been removed.
diff --git a/releasenotes/notes/remove-sahara-service-available-44a642aa9c634ab4.yaml b/releasenotes/notes/remove-sahara-service-available-44a642aa9c634ab4.yaml
new file mode 100644
index 0000000..c0dc7d7
--- /dev/null
+++ b/releasenotes/notes/remove-sahara-service-available-44a642aa9c634ab4.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+  - |
+    The 'sahara' config option in the 'service-available' group has been moved to the sahara plugin
+    (openstack/sahara-tests) along with tests and service client during the Ocata timeframe.
+    A 'sahara' config option was left over on Tempest side, and it's removed now.
+    As long as the sahara plugin is installed, this change as no impact on users of sahara tests.
diff --git a/releasenotes/notes/remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml b/releasenotes/notes/remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml
new file mode 100644
index 0000000..fc15995
--- /dev/null
+++ b/releasenotes/notes/remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml
@@ -0,0 +1,5 @@
+---
+upgrade:
+  - |
+    The deprecated ``volume_services`` option in the ``volume_feature_enabled``
+    section has now been removed.
diff --git a/releasenotes/notes/use-keystone-v3-api-935860d30ddbb8e9.yaml b/releasenotes/notes/use-keystone-v3-api-935860d30ddbb8e9.yaml
new file mode 100644
index 0000000..dd6e924
--- /dev/null
+++ b/releasenotes/notes/use-keystone-v3-api-935860d30ddbb8e9.yaml
@@ -0,0 +1,5 @@
+---
+upgrade:
+  - Tempest now defaults to using Keystone v3 API for the
+    authentication, because Keystone v3 API is CURRENT and
+    the v2 API is deprecated.
diff --git a/releasenotes/notes/volume-transfers-client-e5ed3f5464c0cdc0.yaml b/releasenotes/notes/volume-transfers-client-e5ed3f5464c0cdc0.yaml
new file mode 100644
index 0000000..e5e479b
--- /dev/null
+++ b/releasenotes/notes/volume-transfers-client-e5ed3f5464c0cdc0.yaml
@@ -0,0 +1,18 @@
+---
+features:
+  - |
+    Define volume transfers service clients as libraries.
+    The following volume transfers service clients are defined as library interface.
+
+    * transfers_client(v2)
+deprecations:
+  - |
+    Deprecate volume v2 transfers resource methods from volumes_client(v2) libraries.
+    Same methods are available in new transfers service client: transfers_client(v2)
+    The following methods of volume v2 volumes_clients have been deprecated:
+
+    * create_volume_transfer (v2.volumes_client)
+    * show_volume_transfer (v2.volumes_client)
+    * list_volume_transfers (v2.volumes_client)
+    * delete_volume_transfer (v2.volumes_client)
+    * accept_volume_transfer (v2.volumes_client)
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index 140263c..eec42cd 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # 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
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index 8eac1d0..cea76b4 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -6,6 +6,8 @@
     :maxdepth: 1
 
     unreleased
+    v15.0.0
+    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/releasenotes/source/v15.0.0.rst b/releasenotes/source/v15.0.0.rst
new file mode 100644
index 0000000..2ee1894
--- /dev/null
+++ b/releasenotes/source/v15.0.0.rst
@@ -0,0 +1,6 @@
+=====================
+v15.0.0 Release Notes
+=====================
+
+.. release-notes:: 15.0.0 Release Notes
+   :version: 15.0.0
diff --git a/requirements.txt b/requirements.txt
index d9a9ebb..7c934c2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
 # The order of packages is significant, because pip processes them in the order
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
-pbr>=1.8 # Apache-2.0
+pbr>=2.0.0 # Apache-2.0
 cliff>=2.3.0 # Apache-2.0
 jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
 testtools>=1.4.0 # MIT
@@ -9,15 +9,15 @@
 netaddr!=0.7.16,>=0.7.13 # BSD
 testrepository>=0.0.18 # Apache-2.0/BSD
 oslo.concurrency>=3.8.0 # Apache-2.0
-oslo.config!=3.18.0,>=3.14.0 # Apache-2.0
-oslo.log>=3.11.0 # Apache-2.0
+oslo.config>=3.22.0 # Apache-2.0
+oslo.log>=3.22.0 # Apache-2.0
 oslo.serialization>=1.10.0 # Apache-2.0
-oslo.utils>=3.18.0 # Apache-2.0
+oslo.utils>=3.20.0 # Apache-2.0
 six>=1.9.0 # MIT
 fixtures>=3.0.0 # Apache-2.0/BSD
 PyYAML>=3.10.0 # MIT
 python-subunit>=0.0.18 # Apache-2.0/BSD
-stevedore>=1.17.1 # Apache-2.0
+stevedore>=1.20.0 # Apache-2.0
 PrettyTable<0.8,>=0.7.1 # BSD
 os-testr>=0.8.0 # Apache-2.0
 urllib3>=1.15.1 # MIT
diff --git a/run_tempest.sh b/run_tempest.sh
deleted file mode 100755
index 414146b..0000000
--- a/run_tempest.sh
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/usr/bin/env bash
-
-echo "WARNING: This script is deprecated and will be removed in the near future. Please migrate to tempest run or another method of launching a test runner"
-
-function usage {
-  echo "Usage: $0 [OPTION]..."
-  echo "Run Tempest test suite"
-  echo ""
-  echo "  -V, --virtual-env        Always use virtualenv.  Install automatically if not present"
-  echo "  -N, --no-virtual-env     Don't use virtualenv.  Run tests in local environment"
-  echo "  -n, --no-site-packages   Isolate the virtualenv from the global Python environment"
-  echo "  -f, --force              Force a clean re-build of the virtual environment. Useful when dependencies have been added."
-  echo "  -u, --update             Update the virtual environment with any newer package versions"
-  echo "  -s, --smoke              Only run smoke tests"
-  echo "  -t, --serial             Run testr serially"
-  echo "  -C, --config             Config file location"
-  echo "  -h, --help               Print this usage message"
-  echo "  -d, --debug              Run tests with testtools instead of testr. This allows you to use PDB"
-  echo "  -- [TESTROPTIONS]        After the first '--' you can pass arbitrary arguments to testr "
-}
-
-testrargs=""
-venv=${VENV:-.venv}
-with_venv=tools/with_venv.sh
-serial=0
-always_venv=0
-never_venv=0
-no_site_packages=0
-debug=0
-force=0
-wrapper=""
-config_file=""
-update=0
-
-if ! options=$(getopt -o VNnfusthdC:lL: -l virtual-env,no-virtual-env,no-site-packages,force,update,smoke,serial,help,debug,config: -- "$@")
-then
-    # parse error
-    usage
-    exit 1
-fi
-
-eval set -- $options
-first_uu=yes
-while [ $# -gt 0 ]; do
-  case "$1" in
-    -h|--help) usage; exit;;
-    -V|--virtual-env) always_venv=1; never_venv=0;;
-    -N|--no-virtual-env) always_venv=0; never_venv=1;;
-    -n|--no-site-packages) no_site_packages=1;;
-    -f|--force) force=1;;
-    -u|--update) update=1;;
-    -d|--debug) debug=1;;
-    -C|--config) config_file=$2; shift;;
-    -s|--smoke) testrargs+="smoke";;
-    -t|--serial) serial=1;;
-    --) [ "yes" == "$first_uu" ] || testrargs="$testrargs $1"; first_uu=no  ;;
-    *) testrargs="$testrargs $1";;
-  esac
-  shift
-done
-
-if [ -n "$config_file" ]; then
-    config_file=`readlink -f "$config_file"`
-    export TEMPEST_CONFIG_DIR=`dirname "$config_file"`
-    export TEMPEST_CONFIG=`basename "$config_file"`
-fi
-
-cd `dirname "$0"`
-
-if [ $no_site_packages -eq 1 ]; then
-  installvenvopts="--no-site-packages"
-fi
-
-function testr_init {
-  if [ ! -d .testrepository ]; then
-      ${wrapper} testr init
-  fi
-}
-
-function run_tests {
-  testr_init
-  ${wrapper} find . -type f -name "*.pyc" -delete
-  export OS_TEST_PATH=./tempest/test_discover
-  if [ $debug -eq 1 ]; then
-      if [ "$testrargs" = "" ]; then
-           testrargs="discover ./tempest/test_discover"
-      fi
-      ${wrapper} python -m testtools.run $testrargs
-      return $?
-  fi
-
-  if [ $serial -eq 1 ]; then
-      ${wrapper} testr run --subunit $testrargs | ${wrapper} subunit-trace -n -f
-  else
-      ${wrapper} testr run --parallel --subunit $testrargs | ${wrapper} subunit-trace -n -f
-  fi
-}
-
-if [ $never_venv -eq 0 ]
-then
-  # Remove the virtual environment if --force used
-  if [ $force -eq 1 ]; then
-    echo "Cleaning virtualenv..."
-    rm -rf ${venv}
-  fi
-  if [ $update -eq 1 ]; then
-      echo "Updating virtualenv..."
-      virtualenv $installvenvopts $venv
-      $venv/bin/pip install -U -r requirements.txt
-  fi
-  if [ -e ${venv} ]; then
-    wrapper="${with_venv}"
-  else
-    if [ $always_venv -eq 1 ]; then
-      # Automatically install the virtualenv
-      virtualenv $installvenvopts $venv
-      wrapper="${with_venv}"
-      ${wrapper} pip install -U -r requirements.txt
-    else
-      echo -e "No virtual environment found...create one? (Y/n) \c"
-      read use_ve
-      if [ "x$use_ve" = "xY" -o "x$use_ve" = "x" -o "x$use_ve" = "xy" ]; then
-        # Install the virtualenv and run the test suite in it
-        virtualenv $installvenvopts $venv
-        wrapper=${with_venv}
-        ${wrapper} pip install -U -r requirements.txt
-      fi
-    fi
-  fi
-fi
-
-run_tests
-retval=$?
-
-exit $retval
diff --git a/run_tests.sh b/run_tests.sh
deleted file mode 100755
index a856bb4..0000000
--- a/run_tests.sh
+++ /dev/null
@@ -1,193 +0,0 @@
-#!/usr/bin/env bash
-
-function usage {
-  echo "Usage: $0 [OPTION]..."
-  echo "Run Tempest unit tests"
-  echo ""
-  echo "  -V, --virtual-env        Always use virtualenv.  Install automatically if not present"
-  echo "  -N, --no-virtual-env     Don't use virtualenv.  Run tests in local environment"
-  echo "  -n, --no-site-packages   Isolate the virtualenv from the global Python environment"
-  echo "  -f, --force              Force a clean re-build of the virtual environment. Useful when dependencies have been added."
-  echo "  -u, --update             Update the virtual environment with any newer package versions"
-  echo "  -t, --serial             Run testr serially"
-  echo "  -p, --pep8               Just run pep8"
-  echo "  -c, --coverage           Generate coverage report"
-  echo "  -h, --help               Print this usage message"
-  echo "  -d, --debug              Run tests with testtools instead of testr. This allows you to use PDB"
-  echo "  -- [TESTROPTIONS]        After the first '--' you can pass arbitrary arguments to testr "
-}
-
-function deprecation_warning {
-  cat <<EOF
--------------------------------------------------------------------------
-WARNING: run_tests.sh is deprecated and this script will be removed after
-the Newton release. All tests should be run through testr/ostestr or tox.
-
-To run style checks:
-
- tox -e pep8
-
-To run python 2.7 unit tests
-
- tox -e py27
-
-To run unit tests and generate coverage report
-
- tox -e cover
-
-To run a subset of any of these tests:
-
- tox -e py27 someregex
-
- i.e.: tox -e py27 test_servers
-
-Additional tox targets are available in tox.ini. For more information
-see:
-http://docs.openstack.org/project-team-guide/project-setup/python.html
-
-NOTE: if you want to use testr to run tests, you can instead use:
-
- OS_TEST_PATH=./tempest/tests testr run
-
-Documentation on using testr directly can be found at
-http://testrepository.readthedocs.org/en/latest/MANUAL.html
--------------------------------------------------------------------------
-EOF
-}
-
-testrargs=""
-just_pep8=0
-venv=${VENV:-.venv}
-with_venv=tools/with_venv.sh
-serial=0
-always_venv=0
-never_venv=0
-no_site_packages=0
-debug=0
-force=0
-coverage=0
-wrapper=""
-config_file=""
-update=0
-
-deprecation_warning
-
-if ! options=$(getopt -o VNnfuctphd -l virtual-env,no-virtual-env,no-site-packages,force,update,serial,coverage,pep8,help,debug -- "$@")
-then
-    # parse error
-    usage
-    exit 1
-fi
-
-eval set -- $options
-first_uu=yes
-while [ $# -gt 0 ]; do
-  case "$1" in
-    -h|--help) usage; exit;;
-    -V|--virtual-env) always_venv=1; never_venv=0;;
-    -N|--no-virtual-env) always_venv=0; never_venv=1;;
-    -n|--no-site-packages) no_site_packages=1;;
-    -f|--force) force=1;;
-    -u|--update) update=1;;
-    -d|--debug) debug=1;;
-    -p|--pep8) let just_pep8=1;;
-    -c|--coverage) coverage=1;;
-    -t|--serial) serial=1;;
-    --) [ "yes" == "$first_uu" ] || testrargs="$testrargs $1"; first_uu=no  ;;
-    *) testrargs="$testrargs $1";;
-  esac
-  shift
-done
-
-
-cd `dirname "$0"`
-
-if [ $no_site_packages -eq 1 ]; then
-  installvenvopts="--no-site-packages"
-fi
-
-function testr_init {
-  if [ ! -d .testrepository ]; then
-      ${wrapper} testr init
-  fi
-}
-
-function run_tests {
-  testr_init
-  ${wrapper} find . -type f -name "*.pyc" -delete
-  export OS_TEST_PATH=./tempest/tests
-  if [ $debug -eq 1 ]; then
-      if [ "$testrargs" = "" ]; then
-          testrargs="discover ./tempest/tests"
-      fi
-      ${wrapper} python -m testtools.run $testrargs
-      return $?
-  fi
-
-  if [ $coverage -eq 1 ]; then
-      ${wrapper} python setup.py test --coverage
-      return $?
-  fi
-
-  if [ $serial -eq 1 ]; then
-      ${wrapper} testr run --subunit $testrargs | ${wrapper} subunit-trace -n -f
-  else
-      ${wrapper} testr run --parallel --subunit $testrargs | ${wrapper} subunit-trace -n -f
-  fi
-}
-
-function run_pep8 {
-  echo "Running flake8 ..."
-  if [ $never_venv -eq 1 ]; then
-      echo "**WARNING**:" >&2
-      echo "Running flake8 without virtual env may miss OpenStack HACKING detection" >&2
-  fi
-  ${wrapper} flake8
-}
-
-if [ $never_venv -eq 0 ]
-then
-  # Remove the virtual environment if --force used
-  if [ $force -eq 1 ]; then
-    echo "Cleaning virtualenv..."
-    rm -rf ${venv}
-  fi
-  if [ $update -eq 1 ]; then
-      echo "Updating virtualenv..."
-      virtualenv $installvenvopts $venv
-      $venv/bin/pip install -U -r requirements.txt -r test-requirements.txt
-  fi
-  if [ -e ${venv} ]; then
-    wrapper="${with_venv}"
-  else
-    if [ $always_venv -eq 1 ]; then
-      # Automatically install the virtualenv
-      virtualenv $installvenvopts $venv
-      wrapper="${with_venv}"
-      ${wrapper} pip install -U -r requirements.txt -r test-requirements.txt
-    else
-      echo -e "No virtual environment found...create one? (Y/n) \c"
-      read use_ve
-      if [ "x$use_ve" = "xY" -o "x$use_ve" = "x" -o "x$use_ve" = "xy" ]; then
-        # Install the virtualenv and run the test suite in it
-        virtualenv $installvenvopts $venv
-        wrapper=${with_venv}
-        ${wrapper} pip install -U -r requirements.txt -r test-requirements.txt
-      fi
-    fi
-  fi
-fi
-
-if [ $just_pep8 -eq 1 ]; then
-    run_pep8
-    exit
-fi
-
-run_tests
-retval=$?
-
-if [ -z "$testrargs" ]; then
-    run_pep8
-fi
-
-exit $retval
diff --git a/setup.cfg b/setup.cfg
index 96313fd..b2035bc 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -45,12 +45,10 @@
     tempest.config = tempest.config:list_opts
 
 [build_sphinx]
-all_files = 1
+all-files = 1
+warning-is-error = 1
 build-dir = doc/build
 source-dir = doc/source
 
-[pbr]
-warnerrors = True
-
 [wheel]
 universal = 1
diff --git a/setup.py b/setup.py
index 782bb21..566d844 100644
--- a/setup.py
+++ b/setup.py
@@ -25,5 +25,5 @@
     pass
 
 setuptools.setup(
-    setup_requires=['pbr>=1.8'],
+    setup_requires=['pbr>=2.0.0'],
     pbr=True)
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
index 1c37cad..4ae4372 100644
--- a/tempest/api/compute/admin/test_agents.py
+++ b/tempest/api/compute/admin/test_agents.py
@@ -13,8 +13,8 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 
 class AgentsAdminTestJSON(base.BaseV2ComputeAdminTest):
@@ -44,7 +44,7 @@
             kwargs[rand_key] = data_utils.rand_name(kwargs[rand_key])
         return kwargs
 
-    @test.idempotent_id('1fc6bdc8-0b6d-4cc7-9f30-9b04fabe5b90')
+    @decorators.idempotent_id('1fc6bdc8-0b6d-4cc7-9f30-9b04fabe5b90')
     def test_create_agent(self):
         # Create an agent.
         params = self._param_helper(
@@ -56,7 +56,7 @@
         for expected_item, value in params.items():
             self.assertEqual(value, body[expected_item])
 
-    @test.idempotent_id('dc9ffd51-1c50-4f0e-a820-ae6d2a568a9e')
+    @decorators.idempotent_id('dc9ffd51-1c50-4f0e-a820-ae6d2a568a9e')
     def test_update_agent(self):
         # Create and update an agent.
         body = self.client.create_agent(**self.params_agent)['agent']
@@ -69,7 +69,7 @@
         for expected_item, value in params.items():
             self.assertEqual(value, body[expected_item])
 
-    @test.idempotent_id('470e0b89-386f-407b-91fd-819737d0b335')
+    @decorators.idempotent_id('470e0b89-386f-407b-91fd-819737d0b335')
     def test_delete_agent(self):
         # Create an agent and delete it.
         body = self.client.create_agent(**self.params_agent)['agent']
@@ -80,7 +80,7 @@
         self.assertNotIn(body['agent_id'], map(lambda x: x['agent_id'],
                                                agents))
 
-    @test.idempotent_id('6a326c69-654b-438a-80a3-34bcc454e138')
+    @decorators.idempotent_id('6a326c69-654b-438a-80a3-34bcc454e138')
     def test_list_agents(self):
         # Create an agent and  list all agents.
         body = self.client.create_agent(**self.params_agent)['agent']
@@ -90,7 +90,7 @@
                            'Cannot get any agents.(%s)' % agents)
         self.assertIn(body['agent_id'], map(lambda x: x['agent_id'], agents))
 
-    @test.idempotent_id('eabadde4-3cd7-4ec4-a4b5-5a936d2d4408')
+    @decorators.idempotent_id('eabadde4-3cd7-4ec4-a4b5-5a936d2d4408')
     def test_list_agents_with_filter(self):
         # Create agents and list the agent builds by the filter.
         body = self.client.create_agent(**self.params_agent)['agent']
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 1233a2b..2f5382e 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -17,10 +17,10 @@
 
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
-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 import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -59,7 +59,7 @@
                 msg += " for hypervisor_type %s" % CONF.compute.hypervisor_type
             raise testtools.TestCase.failureException(msg)
 
-    @test.idempotent_id('0d148aa3-d54c-4317-aa8d-42040a475e20')
+    @decorators.idempotent_id('0d148aa3-d54c-4317-aa8d-42040a475e20')
     def test_aggregate_create_delete(self):
         # Create and delete an aggregate.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
@@ -73,7 +73,7 @@
         self.client.delete_aggregate(aggregate['id'])
         self.client.wait_for_resource_deletion(aggregate['id'])
 
-    @test.idempotent_id('5873a6f8-671a-43ff-8838-7ce430bb6d0b')
+    @decorators.idempotent_id('5873a6f8-671a-43ff-8838-7ce430bb6d0b')
     def test_aggregate_create_delete_with_az(self):
         # Create and delete an aggregate.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
@@ -88,7 +88,7 @@
         self.client.delete_aggregate(aggregate['id'])
         self.client.wait_for_resource_deletion(aggregate['id'])
 
-    @test.idempotent_id('68089c38-04b1-4758-bdf0-cf0daec4defd')
+    @decorators.idempotent_id('68089c38-04b1-4758-bdf0-cf0daec4defd')
     def test_aggregate_create_verify_entry_in_list(self):
         # Create an aggregate and ensure it is listed.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
@@ -101,7 +101,7 @@
                       map(lambda x: (x['id'], x['availability_zone']),
                           aggregates))
 
-    @test.idempotent_id('36ec92ca-7a73-43bc-b920-7531809e8540')
+    @decorators.idempotent_id('36ec92ca-7a73-43bc-b920-7531809e8540')
     def test_aggregate_create_update_metadata_get_details(self):
         # Create an aggregate and ensure its details are returned.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
@@ -124,7 +124,7 @@
         body = self.client.show_aggregate(aggregate['id'])['aggregate']
         self.assertEqual(meta, body["metadata"])
 
-    @test.idempotent_id('4d2b2004-40fa-40a1-aab2-66f4dab81beb')
+    @decorators.idempotent_id('4d2b2004-40fa-40a1-aab2-66f4dab81beb')
     def test_aggregate_create_update_with_az(self):
         # Update an aggregate and ensure properties are updated correctly
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
@@ -154,7 +154,7 @@
                           (x['id'], x['name'], x['availability_zone']),
                           aggregates))
 
-    @test.idempotent_id('c8e85064-e79b-4906-9931-c11c24294d02')
+    @decorators.idempotent_id('c8e85064-e79b-4906-9931-c11c24294d02')
     def test_aggregate_add_remove_host(self):
         # Add a host to the given aggregate and remove.
         self.useFixture(fixtures.LockFixture('availability_zone'))
@@ -177,7 +177,7 @@
                          body['availability_zone'])
         self.assertNotIn(self.host, body['hosts'])
 
-    @test.idempotent_id('7f6a1cc5-2446-4cdb-9baa-b6ae0a919b72')
+    @decorators.idempotent_id('7f6a1cc5-2446-4cdb-9baa-b6ae0a919b72')
     def test_aggregate_add_host_list(self):
         # Add a host to the given aggregate and list.
         self.useFixture(fixtures.LockFixture('availability_zone'))
@@ -197,7 +197,7 @@
         self.assertIsNone(agg['availability_zone'])
         self.assertIn(self.host, agg['hosts'])
 
-    @test.idempotent_id('eeef473c-7c52-494d-9f09-2ed7fc8fc036')
+    @decorators.idempotent_id('eeef473c-7c52-494d-9f09-2ed7fc8fc036')
     def test_aggregate_add_host_get_details(self):
         # Add a host to the given aggregate and get details.
         self.useFixture(fixtures.LockFixture('availability_zone'))
@@ -214,7 +214,7 @@
         self.assertIsNone(body['availability_zone'])
         self.assertIn(self.host, body['hosts'])
 
-    @test.idempotent_id('96be03c7-570d-409c-90f8-e4db3c646996')
+    @decorators.idempotent_id('96be03c7-570d-409c-90f8-e4db3c646996')
     def test_aggregate_add_host_create_server_with_az(self):
         # Add a host to the given aggregate and create a server.
         self.useFixture(fixtures.LockFixture('availability_zone'))
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
index 85aa301..e682570 100644
--- a/tempest/api/compute/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -15,7 +15,8 @@
 
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
-from tempest.common.utils import data_utils
+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,6 @@
     def resource_setup(cls):
         super(AggregatesAdminNegativeTestJSON, cls).resource_setup()
         cls.aggregate_name_prefix = 'test_aggregate'
-        cls.az_name_prefix = 'test_az'
 
         hosts_all = cls.os_adm.hosts_client.list_hosts()['hosts']
         hosts = ([host['host_name']
@@ -48,7 +48,7 @@
         return aggregate
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('86a1cb14-da37-4a70-b056-903fd56dfe29')
+    @decorators.idempotent_id('86a1cb14-da37-4a70-b056-903fd56dfe29')
     def test_aggregate_create_as_user(self):
         # Regular user is not allowed to create an aggregate.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
@@ -57,7 +57,7 @@
                           name=aggregate_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('3b8a1929-3793-4e92-bcb4-dfa572ee6c1d')
+    @decorators.idempotent_id('3b8a1929-3793-4e92-bcb4-dfa572ee6c1d')
     def test_aggregate_create_aggregate_name_length_less_than_1(self):
         # the length of aggregate name should >= 1 and <=255
         self.assertRaises(lib_exc.BadRequest,
@@ -65,7 +65,7 @@
                           name='')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('4c194563-543b-4e70-a719-557bbe947fac')
+    @decorators.idempotent_id('4c194563-543b-4e70-a719-557bbe947fac')
     def test_aggregate_create_aggregate_name_length_exceeds_255(self):
         # the length of aggregate name should >= 1 and <=255
         aggregate_name = 'a' * 256
@@ -74,7 +74,7 @@
                           name=aggregate_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9c23a291-b0b1-487b-b464-132e061151b3')
+    @decorators.idempotent_id('9c23a291-b0b1-487b-b464-132e061151b3')
     def test_aggregate_create_with_existent_aggregate_name(self):
         # creating an aggregate with existent aggregate name is forbidden
         aggregate = self._create_test_aggregate()
@@ -83,7 +83,7 @@
                           name=aggregate['name'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('cd6de795-c15d-45f1-8d9e-813c6bb72a3d')
+    @decorators.idempotent_id('cd6de795-c15d-45f1-8d9e-813c6bb72a3d')
     def test_aggregate_delete_as_user(self):
         # Regular user is not allowed to delete an aggregate.
         aggregate = self._create_test_aggregate()
@@ -92,14 +92,14 @@
                           aggregate['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('b7d475a6-5dcd-4ff4-b70a-cd9de66a6672')
+    @decorators.idempotent_id('b7d475a6-5dcd-4ff4-b70a-cd9de66a6672')
     def test_aggregate_list_as_user(self):
         # Regular user is not allowed to list aggregates.
         self.assertRaises(lib_exc.Forbidden,
                           self.user_client.list_aggregates)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('557cad12-34c9-4ff4-95f0-22f0dfbaf7dc')
+    @decorators.idempotent_id('557cad12-34c9-4ff4-95f0-22f0dfbaf7dc')
     def test_aggregate_get_details_as_user(self):
         # Regular user is not allowed to get aggregate details.
         aggregate = self._create_test_aggregate()
@@ -108,21 +108,21 @@
                           aggregate['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('c74f4bf1-4708-4ff2-95a0-f49eaca951bd')
+    @decorators.idempotent_id('c74f4bf1-4708-4ff2-95a0-f49eaca951bd')
     def test_aggregate_delete_with_invalid_id(self):
         # Delete an aggregate with invalid id should raise exceptions.
         self.assertRaises(lib_exc.NotFound,
                           self.client.delete_aggregate, -1)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('3c916244-2c46-49a4-9b55-b20bb0ae512c')
+    @decorators.idempotent_id('3c916244-2c46-49a4-9b55-b20bb0ae512c')
     def test_aggregate_get_details_with_invalid_id(self):
         # Get aggregate details with invalid id should raise exceptions.
         self.assertRaises(lib_exc.NotFound,
                           self.client.show_aggregate, -1)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0ef07828-12b4-45ba-87cc-41425faf5711')
+    @decorators.idempotent_id('0ef07828-12b4-45ba-87cc-41425faf5711')
     def test_aggregate_add_non_exist_host(self):
         # Adding a non-exist host to an aggregate should raise exceptions.
         hosts_all = self.os_adm.hosts_client.list_hosts()['hosts']
@@ -136,7 +136,7 @@
                           aggregate['id'], host=non_exist_host)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7324c334-bd13-4c93-8521-5877322c3d51')
+    @decorators.idempotent_id('7324c334-bd13-4c93-8521-5877322c3d51')
     def test_aggregate_add_host_as_user(self):
         # Regular user is not allowed to add a host to an aggregate.
         aggregate = self._create_test_aggregate()
@@ -145,7 +145,7 @@
                           aggregate['id'], host=self.host)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('19dd44e1-c435-4ee1-a402-88c4f90b5950')
+    @decorators.idempotent_id('19dd44e1-c435-4ee1-a402-88c4f90b5950')
     def test_aggregate_add_existent_host(self):
         self.useFixture(fixtures.LockFixture('availability_zone'))
         aggregate = self._create_test_aggregate()
@@ -158,7 +158,7 @@
                           aggregate['id'], host=self.host)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7a53af20-137a-4e44-a4ae-e19260e626d9')
+    @decorators.idempotent_id('7a53af20-137a-4e44-a4ae-e19260e626d9')
     def test_aggregate_remove_host_as_user(self):
         # Regular user is not allowed to remove a host from an aggregate.
         self.useFixture(fixtures.LockFixture('availability_zone'))
@@ -173,7 +173,7 @@
                           aggregate['id'], host=self.host)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('95d6a6fa-8da9-4426-84d0-eec0329f2e4d')
+    @decorators.idempotent_id('95d6a6fa-8da9-4426-84d0-eec0329f2e4d')
     def test_aggregate_remove_nonexistent_host(self):
         aggregate = self._create_test_aggregate()
 
diff --git a/tempest/api/compute/admin/test_auto_allocate_network.py b/tempest/api/compute/admin/test_auto_allocate_network.py
index 8e481fd..7fda732 100644
--- a/tempest/api/compute/admin/test_auto_allocate_network.py
+++ b/tempest/api/compute/admin/test_auto_allocate_network.py
@@ -17,9 +17,9 @@
 from tempest.api.compute import base
 from tempest.common import compute
 from tempest.common import credentials_factory as credentials
-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 as lib_excs
 from tempest import test
 
@@ -146,22 +146,20 @@
             test_utils.call_and_ignore_notfound_exc(
                 cls.networks_client.delete_network, network['id'])
 
-    @test.idempotent_id('5eb7b8fa-9c23-47a2-9d7d-02ed5809dd34')
+    @decorators.idempotent_id('5eb7b8fa-9c23-47a2-9d7d-02ed5809dd34')
     def test_server_create_no_allocate(self):
         """Tests that no networking is allocated for the server."""
         # create the server with no networking
         server, _ = compute.create_test_server(
             self.os, networks='none', wait_until='ACTIVE')
-        self.addCleanup(waiters.wait_for_server_termination,
-                        self.servers_client, server['id'])
-        self.addCleanup(self.servers_client.delete_server, server['id'])
+        self.addCleanup(self.delete_server, server['id'])
         # get the server ips
         addresses = self.servers_client.list_addresses(
             server['id'])['addresses']
         # assert that there is no networking
         self.assertEqual({}, addresses)
 
-    @test.idempotent_id('2e6cf129-9e28-4e8a-aaaa-045ea826b2a6')
+    @decorators.idempotent_id('2e6cf129-9e28-4e8a-aaaa-045ea826b2a6')
     def test_server_multi_create_auto_allocate(self):
         """Tests that networking is auto-allocated for multiple servers."""
 
@@ -182,9 +180,7 @@
             min_count=3)
         server_nets = set()
         for server in servers:
-            self.addCleanup(waiters.wait_for_server_termination,
-                            self.servers_client, server['id'])
-            self.addCleanup(self.servers_client.delete_server, server['id'])
+            self.addCleanup(self.delete_server, server['id'])
             # get the server ips
             addresses = self.servers_client.list_addresses(
                 server['id'])['addresses']
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index 3470602..50dec28 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class AZAdminV2TestJSON(base.BaseV2ComputeAdminTest):
@@ -25,13 +25,13 @@
         super(AZAdminV2TestJSON, cls).setup_clients()
         cls.client = cls.availability_zone_admin_client
 
-    @test.idempotent_id('d3431479-8a09-4f76-aa2d-26dc580cb27c')
+    @decorators.idempotent_id('d3431479-8a09-4f76-aa2d-26dc580cb27c')
     def test_get_availability_zone_list(self):
         # List of availability zone
         availability_zone = self.client.list_availability_zones()
         self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
 
-    @test.idempotent_id('ef726c58-530f-44c2-968c-c7bed22d5b8c')
+    @decorators.idempotent_id('ef726c58-530f-44c2-968c-c7bed22d5b8c')
     def test_get_availability_zone_list_detail(self):
         # List of availability zones and available services
         availability_zone = self.client.list_availability_zones(detail=True)
diff --git a/tempest/api/compute/admin/test_availability_zone_negative.py b/tempest/api/compute/admin/test_availability_zone_negative.py
index c60de1e..faeb811 100644
--- a/tempest/api/compute/admin/test_availability_zone_negative.py
+++ b/tempest/api/compute/admin/test_availability_zone_negative.py
@@ -13,6 +13,7 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -26,7 +27,7 @@
         cls.non_adm_client = cls.availability_zone_client
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('bf34dca2-fdc3-4073-9c02-7648d9eae0d7')
+    @decorators.idempotent_id('bf34dca2-fdc3-4073-9c02-7648d9eae0d7')
     def test_get_availability_zone_list_detail_with_non_admin_user(self):
         # List of availability zones and available services with
         # non-administrator user
diff --git a/tempest/api/compute/admin/test_baremetal_nodes.py b/tempest/api/compute/admin/test_baremetal_nodes.py
index 722d9a6..7726ed4 100644
--- a/tempest/api/compute/admin/test_baremetal_nodes.py
+++ b/tempest/api/compute/admin/test_baremetal_nodes.py
@@ -14,6 +14,7 @@
 
 from tempest.api.compute import base
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -32,11 +33,11 @@
         cls.ironic_client = cls.os_adm.baremetal_client
 
     @test.attr(type=['baremetal'])
-    @test.idempotent_id('e475aa6e-416d-4fa4-b3af-28d5e84250fb')
+    @decorators.idempotent_id('e475aa6e-416d-4fa4-b3af-28d5e84250fb')
     def test_list_get_baremetal_nodes(self):
         # Create some test nodes in Ironic directly
         test_nodes = []
-        for i in range(0, 3):
+        for _ in range(0, 3):
             _, node = self.ironic_client.create_node()
             test_nodes.append(node)
             self.addCleanup(self.ironic_client.delete_node, node['uuid'])
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index 9cda0cd..10ed519 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -15,6 +15,7 @@
 
 from tempest.api.compute import base
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -47,18 +48,18 @@
             if cls.ip:
                 break
 
-    @test.idempotent_id('16b7d848-2f7c-4709-85a3-2dfb4576cc52')
+    @decorators.idempotent_id('16b7d848-2f7c-4709-85a3-2dfb4576cc52')
     @test.services('network')
     def test_list_fixed_ip_details(self):
         fixed_ip = self.client.show_fixed_ip(self.ip)
         self.assertEqual(fixed_ip['fixed_ip']['address'], self.ip)
 
-    @test.idempotent_id('5485077b-7e46-4cec-b402-91dc3173433b')
+    @decorators.idempotent_id('5485077b-7e46-4cec-b402-91dc3173433b')
     @test.services('network')
     def test_set_reserve(self):
         self.client.reserve_fixed_ip(self.ip, reserve="None")
 
-    @test.idempotent_id('7476e322-b9ff-4710-bf82-49d51bac6e2e')
+    @decorators.idempotent_id('7476e322-b9ff-4710-bf82-49d51bac6e2e')
     @test.services('network')
     def test_set_unreserve(self):
         self.client.reserve_fixed_ip(self.ip, unreserve="None")
diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py
index 05bba21..073f152 100644
--- a/tempest/api/compute/admin/test_fixed_ips_negative.py
+++ b/tempest/api/compute/admin/test_fixed_ips_negative.py
@@ -14,6 +14,7 @@
 
 from tempest.api.compute import base
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -49,14 +50,14 @@
                 break
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9f17f47d-daad-4adc-986e-12370c93e407')
+    @decorators.idempotent_id('9f17f47d-daad-4adc-986e-12370c93e407')
     @test.services('network')
     def test_list_fixed_ip_details_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_client.show_fixed_ip, self.ip)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ce60042c-fa60-4836-8d43-1c8e3359dc47')
+    @decorators.idempotent_id('ce60042c-fa60-4836-8d43-1c8e3359dc47')
     @test.services('network')
     def test_set_reserve_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
@@ -64,7 +65,7 @@
                           self.ip, reserve="None")
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f1f7a35b-0390-48c5-9803-5f27461439db')
+    @decorators.idempotent_id('f1f7a35b-0390-48c5-9803-5f27461439db')
     @test.services('network')
     def test_set_unreserve_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
@@ -72,7 +73,7 @@
                           self.ip, unreserve="None")
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f51cf464-7fc5-4352-bc3e-e75cfa2cb717')
+    @decorators.idempotent_id('f51cf464-7fc5-4352-bc3e-e75cfa2cb717')
     @test.services('network')
     def test_set_reserve_with_invalid_ip(self):
         # NOTE(maurosr): since this exercises the same code snippet, we do it
@@ -85,7 +86,7 @@
                           "my.invalid.ip", reserve="None")
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('fd26ef50-f135-4232-9d32-281aab3f9176')
+    @decorators.idempotent_id('fd26ef50-f135-4232-9d32-281aab3f9176')
     @test.services('network')
     def test_fixed_ip_with_invalid_action(self):
         self.assertRaises(lib_exc.BadRequest,
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index fde5622..3821895 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -16,7 +16,8 @@
 import uuid
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
+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
 
@@ -32,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()
 
@@ -49,85 +44,55 @@
         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']
-
-    @test.idempotent_id('8b4330e1-12c4-4554-9390-e6639971f086')
+    @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))
 
-    @test.idempotent_id('94c9bb4e-2c2a-4f3c-bb1f-5f0daf918e6d')
+    @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)
 
-    @test.idempotent_id('f83fe669-6758-448a-a85e-32d351f36fe0')
+    @decorators.idempotent_id('f83fe669-6758-448a-a85e-32d351f36fe0')
     def test_create_flavor_with_none_id(self):
         # 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)))
 
-    @test.idempotent_id('8261d7b0-be58-43ec-a2e5-300573c3f6c5')
+    @decorators.idempotent_id('8261d7b0-be58-43ec-a2e5-300573c3f6c5')
     def test_create_flavor_verify_entry_in_list_details(self):
         # 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'])
-        flag = False
-        # Verify flavor is retrieved
-        flavors = self.client.list_flavors(detail=True)['flavors']
-        for flavor in flavors:
-            if flavor['name'] == flavor_name:
-                flag = True
-        self.assertTrue(flag)
+        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)
 
-    @test.idempotent_id('63dc64e6-2e79-4fdf-868f-85500d308d66')
+        # Check if flavor is present in list
+        flavors_list = self.admin_flavors_client.list_flavors(
+            detail=True)['flavors']
+        self.assertIn(flavor_name, [f['name'] for f in flavors_list])
+
+    @decorators.idempotent_id('63dc64e6-2e79-4fdf-868f-85500d308d66')
     def test_create_list_flavor_without_extra_data(self):
         # Create a flavor and ensure it is listed
         # This operation requires the user to have 'admin' role
@@ -136,18 +101,17 @@
             # check some extensions for the flavor create/show/detail response
             self.assertEqual(flavor['swap'], '')
             self.assertEqual(int(flavor['rxtx_factor']), 1)
-            self.assertEqual(int(flavor['OS-FLV-EXT-DATA:ephemeral']), 0)
+            self.assertEqual(flavor['OS-FLV-EXT-DATA:ephemeral'], 0)
             self.assertEqual(flavor['os-flavor-access:is_public'], True)
 
         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)['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)
@@ -156,64 +120,46 @@
         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']
-        for flavor in flavors:
-            if flavor['name'] == flavor_name:
-                verify_flavor_response_extension(flavor)
-                flag = True
-        self.assertTrue(flag)
+        flavors_list = [
+            f for f in self.flavors_client.list_flavors(detail=True)['flavors']
+            if f['name'] == flavor_name
+        ]
+        self.assertNotEmpty(flavors_list)
+        verify_flavor_response_extension(flavors_list[0])
 
-    @test.idempotent_id('be6cc18c-7c5d-48c0-ac16-17eaf03c54eb')
+    @decorators.idempotent_id('be6cc18c-7c5d-48c0-ac16-17eaf03c54eb')
     def test_list_non_public_flavor(self):
         # Create a flavor with os-flavor-access:is_public false.
         # The flavor should not be present in list_details as the
         # 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'])
-        # Verify flavor is retrieved
-        flag = False
-        flavors = self.client.list_flavors(detail=True)['flavors']
-        for flavor in flavors:
-            if flavor['name'] == flavor_name:
-                flag = True
-        self.assertFalse(flag)
+        self.create_flavor(name=flavor_name,
+                           ram=self.ram, vcpus=self.vcpus,
+                           disk=self.disk,
+                           is_public="False")
+        # Verify flavor is not retrieved
+        flavors_list = self.admin_flavors_client.list_flavors(
+            detail=True)['flavors']
+        self.assertNotIn(flavor_name, [f['name'] for f in flavors_list])
 
         # Verify flavor is not retrieved with other user
-        flag = False
-        flavors = self.user_client.list_flavors(detail=True)['flavors']
-        for flavor in flavors:
-            if flavor['name'] == flavor_name:
-                flag = True
-        self.assertFalse(flag)
+        flavors_list = self.flavors_client.list_flavors(detail=True)['flavors']
+        self.assertNotIn(flavor_name, [f['name'] for f in flavors_list])
 
-    @test.idempotent_id('bcc418ef-799b-47cc-baa1-ce01368b8987')
+    @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,
@@ -221,65 +167,45 @@
                           name='test', imageRef=self.image_ref,
                           flavorRef=flavor['id'])
 
-    @test.idempotent_id('b345b196-bfbd-4231-8ac1-6d7fe15ff3a3')
+    @decorators.idempotent_id('b345b196-bfbd-4231-8ac1-6d7fe15ff3a3')
     def test_list_public_flavor_with_other_user(self):
         # 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'])
-        flag = False
-        self.new_client = self.flavors_client
+        self.create_flavor(name=flavor_name,
+                           ram=self.ram, vcpus=self.vcpus,
+                           disk=self.disk,
+                           is_public="True")
         # Verify flavor is retrieved with new user
-        flavors = self.new_client.list_flavors(detail=True)['flavors']
-        for flavor in flavors:
-            if flavor['name'] == flavor_name:
-                flag = True
-        self.assertTrue(flag)
+        flavors_list = self.flavors_client.list_flavors(detail=True)['flavors']
+        self.assertIn(flavor_name, [f['name'] for f in flavors_list])
 
-    @test.idempotent_id('fb9cbde6-3a0e-41f2-a983-bdb0a823c44e')
+    @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'])
-
-        def _flavor_lookup(flavors, flavor_name):
-            for flavor in flavors:
-                if flavor['name'] == flavor_name:
-                    return flavor
-            return None
+        self.create_flavor(name=flavor_name_public,
+                           ram=self.ram, vcpus=self.vcpus,
+                           disk=self.disk,
+                           is_public="True")
 
         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)
+                self.assertIn(flavor_name, [f['name'] for f in flavors])
 
         _test_string_variations(['f', 'false', 'no', '0'],
                                 flavor_name_not_public)
@@ -287,19 +213,13 @@
         _test_string_variations(['t', 'true', 'yes', '1'],
                                 flavor_name_public)
 
-    @test.idempotent_id('3b541a2e-2ac2-4b42-8b8d-ba6e22fcd4da')
+    @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 2063267..5a38acc 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -32,68 +32,50 @@
             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()
 
         # Non admin tenant ID
         cls.tenant_id = cls.flavors_client.tenant_id
-        cls.flavor_name_prefix = 'test_flavor_access_'
         cls.ram = 512
         cls.vcpus = 1
         cls.disk = 10
 
-    @test.idempotent_id('ea2c2211-29fa-4db9-97c3-906d36fad3e0')
+    @decorators.idempotent_id('ea2c2211-29fa-4db9-97c3-906d36fad3e0')
     def test_flavor_access_list_with_private_flavor(self):
         # Test to make sure that list flavor access on a newly created
         # 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'])
+        flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk, is_public='False')
+
+        flavor_access = (self.admin_flavors_client.list_flavor_access(
+                         flavor['id'])['flavor_access'])
         self.assertEqual(len(flavor_access), 0, str(flavor_access))
 
-    @test.idempotent_id('59e622f6-bdf6-45e3-8ba8-fedad905a6b4')
+    @decorators.idempotent_id('59e622f6-bdf6-45e3-8ba8-fedad905a6b4')
     def test_flavor_access_add_remove(self):
         # 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'])
+        flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk, is_public='False')
+
         # Add flavor access to a tenant.
         resp_body = {
             "tenant_id": str(self.tenant_id),
-            "flavor_id": str(new_flavor['id']),
+            "flavor_id": str(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(
+            flavor['id'], self.tenant_id)['flavor_access'])
         self.assertIn(resp_body, add_body)
 
         # The flavor is present in list.
         flavors = self.flavors_client.list_flavors(detail=True)['flavors']
-        self.assertIn(new_flavor['id'], map(lambda x: x['id'], flavors))
+        self.assertIn(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(
+            flavor['id'], self.tenant_id)['flavor_access'])
         self.assertNotIn(resp_body, remove_body)
 
         # The flavor is not present in list.
         flavors = self.flavors_client.list_flavors(detail=True)['flavors']
-        self.assertNotIn(new_flavor['id'], map(lambda x: x['id'], flavors))
+        self.assertNotIn(flavor['id'], map(lambda x: x['id'], flavors))
diff --git a/tempest/api/compute/admin/test_flavors_access_negative.py b/tempest/api/compute/admin/test_flavors_access_negative.py
index 1b7eb12..12e4587 100644
--- a/tempest/api/compute/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/admin/test_flavors_access_negative.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.api.compute 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
 
@@ -25,6 +25,8 @@
     Add and remove Flavor Access require admin privileges.
     """
 
+    credentials = ['primary', 'admin', 'alt']
+
     @classmethod
     def skip_checks(cls):
         super(FlavorsAccessNegativeTestJSON, cls).skip_checks()
@@ -33,114 +35,81 @@
             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()
 
         cls.tenant_id = cls.flavors_client.tenant_id
-        cls.flavor_name_prefix = 'test_flavor_access_'
         cls.ram = 512
         cls.vcpus = 1
         cls.disk = 10
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0621c53e-d45d-40e7-951d-43e5e257b272')
+    @decorators.idempotent_id('0621c53e-d45d-40e7-951d-43e5e257b272')
     def test_flavor_access_list_with_public_flavor(self):
         # 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'])
+        flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk, is_public='True')
         self.assertRaises(lib_exc.NotFound,
-                          self.client.list_flavor_access,
-                          new_flavor_id)
+                          self.admin_flavors_client.list_flavor_access,
+                          flavor['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('41eaaade-6d37-4f28-9c74-f21b46ca67bd')
+    @decorators.idempotent_id('41eaaade-6d37-4f28-9c74-f21b46ca67bd')
     def test_flavor_non_admin_add(self):
         # 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'])
+        flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk, is_public='False')
         self.assertRaises(lib_exc.Forbidden,
                           self.flavors_client.add_flavor_access,
-                          new_flavor['id'],
+                          flavor['id'],
                           self.tenant_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('073e79a6-c311-4525-82dc-6083d919cb3a')
+    @decorators.idempotent_id('073e79a6-c311-4525-82dc-6083d919cb3a')
     def test_flavor_non_admin_remove(self):
         # 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'])
+        flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk, is_public='False')
+
         # Add flavor access to a tenant.
-        self.client.add_flavor_access(new_flavor['id'], self.tenant_id)
-        self.addCleanup(self.client.remove_flavor_access,
-                        new_flavor['id'], self.tenant_id)
+        self.admin_flavors_client.add_flavor_access(flavor['id'],
+                                                    self.tenant_id)
+        self.addCleanup(self.admin_flavors_client.remove_flavor_access,
+                        flavor['id'], self.tenant_id)
         self.assertRaises(lib_exc.Forbidden,
                           self.flavors_client.remove_flavor_access,
-                          new_flavor['id'],
+                          flavor['id'],
                           self.tenant_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f3592cc0-0306-483c-b210-9a7b5346eddc')
+    @decorators.idempotent_id('f3592cc0-0306-483c-b210-9a7b5346eddc')
     def test_add_flavor_access_duplicate(self):
         # 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'])
+        flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk, is_public='False')
 
         # Add flavor access to a tenant.
-        self.client.add_flavor_access(new_flavor['id'], self.tenant_id)
-        self.addCleanup(self.client.remove_flavor_access,
-                        new_flavor['id'], self.tenant_id)
+        self.admin_flavors_client.add_flavor_access(flavor['id'],
+                                                    self.tenant_id)
+        self.addCleanup(self.admin_flavors_client.remove_flavor_access,
+                        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,
-                          new_flavor['id'],
+                          self.admin_flavors_client.add_flavor_access,
+                          flavor['id'],
                           self.tenant_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('1f710927-3bc7-4381-9f82-0ca6e42644b7')
+    @decorators.idempotent_id('1f710927-3bc7-4381-9f82-0ca6e42644b7')
     def test_remove_flavor_access_not_found(self):
         # 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'])
+        flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus,
+                                    disk=self.disk, is_public='False')
 
         # An exception should be raised when flavor access is not found
         self.assertRaises(lib_exc.NotFound,
-                          self.client.remove_flavor_access,
-                          new_flavor['id'],
-                          data_utils.rand_uuid())
+                          self.admin_flavors_client.remove_flavor_access,
+                          flavor['id'],
+                          self.os_alt.servers_client.tenant_id)
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index 661cd18..4d7abb6 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -33,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')
@@ -45,71 +41,73 @@
         vcpus = 1
         disk = 10
         ephemeral = 10
-        cls.new_flavor_id = data_utils.rand_int_id(start=1000)
+        new_flavor_id = data_utils.rand_int_id(start=1000)
         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=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()
 
-    @test.idempotent_id('0b2f9d4b-1ca2-4b99-bb40-165d4bb94208')
+    @decorators.idempotent_id('0b2f9d4b-1ca2-4b99-bb40-165d4bb94208')
     def test_flavor_set_get_update_show_unset_keys(self):
         # Test to SET, GET, UPDATE, SHOW, UNSET flavor extra
         # spec as a user with admin privileges.
         # 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")
 
-    @test.idempotent_id('a99dad88-ae1c-4fba-aeb4-32f898218bd0')
+    @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])
 
-    @test.idempotent_id('12805a7f-39a3-4042-b989-701d5cad9c90')
+    @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 7eb4bbf..a728711 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
@@ -15,7 +15,8 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
+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,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()
 
@@ -47,26 +43,27 @@
         vcpus = 1
         disk = 10
         ephemeral = 10
-        cls.new_flavor_id = data_utils.rand_int_id(start=1000)
+        new_flavor_id = data_utils.rand_int_id(start=1000)
         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=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'])
-    @test.idempotent_id('a00a3b81-5641-45a8-ab2b-4a8ec41e1d7d')
+    @decorators.idempotent_id('a00a3b81-5641-45a8-ab2b-4a8ec41e1d7d')
     def test_flavor_non_admin_set_keys(self):
         # Test to SET flavor extra spec as a user without admin privileges.
         self.assertRaises(lib_exc.Forbidden,
@@ -75,10 +72,10 @@
                           key1="value1", key2="value2")
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('1ebf4ef8-759e-48fe-a801-d451d80476fb')
+    @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,
@@ -89,10 +86,10 @@
                           key1='value1_new')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('28f12249-27c7-44c1-8810-1f382f316b11')
+    @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,
@@ -100,15 +97,15 @@
                           'key1')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('440b9f3f-3c7f-4293-a106-0ceda350f8de')
+    @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')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('329a7be3-54b2-48be-8052-bf2ce4afd898')
+    @decorators.idempotent_id('329a7be3-54b2-48be-8052-bf2ce4afd898')
     def test_flavor_get_nonexistent_key(self):
         self.assertRaises(lib_exc.NotFound,
                           self.flavors_client.show_flavor_extra_spec,
@@ -116,21 +113,21 @@
                           "nonexistent_key")
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('25b822b8-9f49-44f6-80de-d99f0482e5cb')
+    @decorators.idempotent_id('25b822b8-9f49-44f6-80de-d99f0482e5cb')
     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")
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f5889590-bf66-41cc-b4b1-6e6370cfd93f')
+    @decorators.idempotent_id('f5889590-bf66-41cc-b4b1-6e6370cfd93f')
     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_floating_ips_bulk.py b/tempest/api/compute/admin/test_floating_ips_bulk.py
index a4695b0..f38af56 100644
--- a/tempest/api/compute/admin/test_floating_ips_bulk.py
+++ b/tempest/api/compute/admin/test_floating_ips_bulk.py
@@ -18,6 +18,7 @@
 from tempest.api.compute import base
 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
 
@@ -55,7 +56,7 @@
                 raise exceptions.InvalidConfiguration(msg)
         return
 
-    @test.idempotent_id('2c8f145f-8012-4cb8-ac7e-95a587f0e4ab')
+    @decorators.idempotent_id('2c8f145f-8012-4cb8-ac7e-95a587f0e4ab')
     @test.services('network')
     def test_create_list_delete_floating_ips_bulk(self):
         # Create, List  and delete the Floating IPs Bulk
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index 3797b29..b664955 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -14,7 +14,7 @@
 
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
-from tempest import test
+from tempest.lib import decorators
 
 
 class HostsAdminTestJSON(base.BaseV2ComputeAdminTest):
@@ -25,12 +25,12 @@
         super(HostsAdminTestJSON, cls).setup_clients()
         cls.client = cls.os_adm.hosts_client
 
-    @test.idempotent_id('9bfaf98d-e2cb-44b0-a07e-2558b2821e4f')
+    @decorators.idempotent_id('9bfaf98d-e2cb-44b0-a07e-2558b2821e4f')
     def test_list_hosts(self):
         hosts = self.client.list_hosts()['hosts']
         self.assertGreaterEqual(len(hosts), 2, str(hosts))
 
-    @test.idempotent_id('5dc06f5b-d887-47a2-bb2a-67762ef3c6de')
+    @decorators.idempotent_id('5dc06f5b-d887-47a2-bb2a-67762ef3c6de')
     def test_list_hosts_with_zone(self):
         self.useFixture(fixtures.LockFixture('availability_zone'))
         hosts = self.client.list_hosts()['hosts']
@@ -39,21 +39,21 @@
         self.assertGreaterEqual(len(hosts), 1)
         self.assertIn(host, hosts)
 
-    @test.idempotent_id('9af3c171-fbf4-4150-a624-22109733c2a6')
+    @decorators.idempotent_id('9af3c171-fbf4-4150-a624-22109733c2a6')
     def test_list_hosts_with_a_blank_zone(self):
         # If send the request with a blank zone, the request will be successful
         # and it will return all the hosts list
         hosts = self.client.list_hosts(zone='')['hosts']
         self.assertNotEqual(0, len(hosts))
 
-    @test.idempotent_id('c6ddbadb-c94e-4500-b12f-8ffc43843ff8')
+    @decorators.idempotent_id('c6ddbadb-c94e-4500-b12f-8ffc43843ff8')
     def test_list_hosts_with_nonexistent_zone(self):
         # If send the request with a nonexistent zone, the request will be
         # successful and no hosts will be returned
         hosts = self.client.list_hosts(zone='xxx')['hosts']
         self.assertEqual(0, len(hosts))
 
-    @test.idempotent_id('38adbb12-aee2-4498-8aec-329c72423aa4')
+    @decorators.idempotent_id('38adbb12-aee2-4498-8aec-329c72423aa4')
     def test_show_host_detail(self):
         hosts = self.client.list_hosts()['hosts']
 
diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py
index 3821b22..07ab8c5 100644
--- a/tempest/api/compute/admin/test_hosts_negative.py
+++ b/tempest/api/compute/admin/test_hosts_negative.py
@@ -13,6 +13,7 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -35,26 +36,26 @@
         cls.hostname = hosts[0]['host_name']
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('dd032027-0210-4d9c-860e-69b1b8deed5f')
+    @decorators.idempotent_id('dd032027-0210-4d9c-860e-69b1b8deed5f')
     def test_list_hosts_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_client.list_hosts)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e75b0a1a-041f-47a1-8b4a-b72a6ff36d3f')
+    @decorators.idempotent_id('e75b0a1a-041f-47a1-8b4a-b72a6ff36d3f')
     def test_show_host_detail_with_nonexistent_hostname(self):
         self.assertRaises(lib_exc.NotFound,
                           self.client.show_host, 'nonexistent_hostname')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('19ebe09c-bfd4-4b7c-81a2-e2e0710f59cc')
+    @decorators.idempotent_id('19ebe09c-bfd4-4b7c-81a2-e2e0710f59cc')
     def test_show_host_detail_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_client.show_host,
                           self.hostname)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e40c72b1-0239-4ed6-ba21-81a184df1f7c')
+    @decorators.idempotent_id('e40c72b1-0239-4ed6-ba21-81a184df1f7c')
     def test_update_host_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_client.update_host,
@@ -63,7 +64,7 @@
                           maintenance_mode='enable')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('fbe2bf3e-3246-4a95-a59f-94e4e298ec77')
+    @decorators.idempotent_id('fbe2bf3e-3246-4a95-a59f-94e4e298ec77')
     def test_update_host_with_invalid_status(self):
         # 'status' can only be 'enable' or 'disable'
         self.assertRaises(lib_exc.BadRequest,
@@ -73,7 +74,7 @@
                           maintenance_mode='enable')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ab1e230e-5e22-41a9-8699-82b9947915d4')
+    @decorators.idempotent_id('ab1e230e-5e22-41a9-8699-82b9947915d4')
     def test_update_host_with_invalid_maintenance_mode(self):
         # 'maintenance_mode' can only be 'enable' or 'disable'
         self.assertRaises(lib_exc.BadRequest,
@@ -83,7 +84,7 @@
                           maintenance_mode='invalid')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0cd85f75-6992-4a4a-b1bd-d11e37fd0eee')
+    @decorators.idempotent_id('0cd85f75-6992-4a4a-b1bd-d11e37fd0eee')
     def test_update_host_without_param(self):
         # 'status' or 'maintenance_mode' needed for host update
         self.assertRaises(lib_exc.BadRequest,
@@ -91,7 +92,7 @@
                           self.hostname)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('23c92146-2100-4d68-b2d6-c7ade970c9c1')
+    @decorators.idempotent_id('23c92146-2100-4d68-b2d6-c7ade970c9c1')
     def test_update_nonexistent_host(self):
         self.assertRaises(lib_exc.NotFound,
                           self.client.update_host,
@@ -100,42 +101,42 @@
                           maintenance_mode='enable')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0d981ac3-4320-4898-b674-82b61fbb60e4')
+    @decorators.idempotent_id('0d981ac3-4320-4898-b674-82b61fbb60e4')
     def test_startup_nonexistent_host(self):
         self.assertRaises(lib_exc.NotFound,
                           self.client.startup_host,
                           'nonexistent_hostname')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9f4ebb7e-b2ae-4e5b-a38f-0fd1bb0ddfca')
+    @decorators.idempotent_id('9f4ebb7e-b2ae-4e5b-a38f-0fd1bb0ddfca')
     def test_startup_host_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_client.startup_host,
                           self.hostname)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9e637444-29cf-4244-88c8-831ae82c31b6')
+    @decorators.idempotent_id('9e637444-29cf-4244-88c8-831ae82c31b6')
     def test_shutdown_nonexistent_host(self):
         self.assertRaises(lib_exc.NotFound,
                           self.client.shutdown_host,
                           'nonexistent_hostname')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a803529c-7e3f-4d3c-a7d6-8e1c203d27f6')
+    @decorators.idempotent_id('a803529c-7e3f-4d3c-a7d6-8e1c203d27f6')
     def test_shutdown_host_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_client.shutdown_host,
                           self.hostname)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f86bfd7b-0b13-4849-ae29-0322e83ee58b')
+    @decorators.idempotent_id('f86bfd7b-0b13-4849-ae29-0322e83ee58b')
     def test_reboot_nonexistent_host(self):
         self.assertRaises(lib_exc.NotFound,
                           self.client.reboot_host,
                           'nonexistent_hostname')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('02d79bb9-eb57-4612-abf6-2cb38897d2f8')
+    @decorators.idempotent_id('02d79bb9-eb57-4612-abf6-2cb38897d2f8')
     def test_reboot_host_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_client.reboot_host,
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index 1f043dc..4637024 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class HypervisorAdminTestJSON(base.BaseV2ComputeAdminTest):
@@ -33,19 +33,19 @@
     def assertHypervisors(self, hypers):
         self.assertGreater(len(hypers), 0, "No hypervisors found: %s" % hypers)
 
-    @test.idempotent_id('7f0ceacd-c64d-4e96-b8ee-d02943142cc5')
+    @decorators.idempotent_id('7f0ceacd-c64d-4e96-b8ee-d02943142cc5')
     def test_get_hypervisor_list(self):
         # List of hypervisor and available hypervisors hostname
         hypers = self._list_hypervisors()
         self.assertHypervisors(hypers)
 
-    @test.idempotent_id('1e7fdac2-b672-4ad1-97a4-bad0e3030118')
+    @decorators.idempotent_id('1e7fdac2-b672-4ad1-97a4-bad0e3030118')
     def test_get_hypervisor_list_details(self):
         # Display the details of the all hypervisor
         hypers = self.client.list_hypervisors(detail=True)['hypervisors']
         self.assertHypervisors(hypers)
 
-    @test.idempotent_id('94ff9eae-a183-428e-9cdb-79fde71211cc')
+    @decorators.idempotent_id('94ff9eae-a183-428e-9cdb-79fde71211cc')
     def test_get_hypervisor_show_details(self):
         # Display the details of the specified hypervisor
         hypers = self._list_hypervisors()
@@ -56,7 +56,7 @@
         self.assertEqual(details['hypervisor_hostname'],
                          hypers[0]['hypervisor_hostname'])
 
-    @test.idempotent_id('e81bba3f-6215-4e39-a286-d52d2f906862')
+    @decorators.idempotent_id('e81bba3f-6215-4e39-a286-d52d2f906862')
     def test_get_hypervisor_show_servers(self):
         # Show instances about the specific hypervisors
         hypers = self._list_hypervisors()
@@ -67,14 +67,14 @@
                        ['hypervisors'])
         self.assertGreater(len(hypervisors), 0)
 
-    @test.idempotent_id('797e4f28-b6e0-454d-a548-80cc77c00816')
+    @decorators.idempotent_id('797e4f28-b6e0-454d-a548-80cc77c00816')
     def test_get_hypervisor_stats(self):
         # Verify the stats of the all hypervisor
         stats = (self.client.show_hypervisor_statistics()
                  ['hypervisor_statistics'])
         self.assertGreater(len(stats), 0)
 
-    @test.idempotent_id('91a50d7d-1c2b-4f24-b55a-a1fe20efca70')
+    @decorators.idempotent_id('91a50d7d-1c2b-4f24-b55a-a1fe20efca70')
     def test_get_hypervisor_uptime(self):
         # Verify that GET shows the specified hypervisor uptime
         hypers = self._list_hypervisors()
@@ -113,7 +113,7 @@
             has_valid_uptime,
             "None of the hypervisors had a valid uptime: %s" % hypers)
 
-    @test.idempotent_id('d7e1805b-3b14-4a3b-b6fd-50ec6d9f361f')
+    @decorators.idempotent_id('d7e1805b-3b14-4a3b-b6fd-50ec6d9f361f')
     def test_search_hypervisor(self):
         hypers = self._list_hypervisors()
         self.assertHypervisors(hypers)
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index 0f35e14..b8a67b9 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
+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 @@
         return hypers
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('c136086a-0f67-4b2b-bc61-8482bd68989f')
+    @decorators.idempotent_id('c136086a-0f67-4b2b-bc61-8482bd68989f')
     def test_show_nonexistent_hypervisor(self):
         nonexistent_hypervisor_id = data_utils.rand_uuid()
 
@@ -44,7 +45,7 @@
             nonexistent_hypervisor_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('51e663d0-6b89-4817-a465-20aca0667d03')
+    @decorators.idempotent_id('51e663d0-6b89-4817-a465-20aca0667d03')
     def test_show_hypervisor_with_non_admin_user(self):
         hypers = self._list_hypervisors()
         self.assertGreater(len(hypers), 0)
@@ -55,7 +56,7 @@
             hypers[0]['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('2a0a3938-832e-4859-95bf-1c57c236b924')
+    @decorators.idempotent_id('2a0a3938-832e-4859-95bf-1c57c236b924')
     def test_show_servers_with_non_admin_user(self):
         hypers = self._list_hypervisors()
         self.assertGreater(len(hypers), 0)
@@ -66,7 +67,7 @@
             hypers[0]['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('02463d69-0ace-4d33-a4a8-93d7883a2bba')
+    @decorators.idempotent_id('02463d69-0ace-4d33-a4a8-93d7883a2bba')
     def test_show_servers_with_nonexistent_hypervisor(self):
         nonexistent_hypervisor_id = data_utils.rand_uuid()
 
@@ -76,14 +77,14 @@
             nonexistent_hypervisor_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e2b061bb-13f9-40d8-9d6e-d5bf17595849')
+    @decorators.idempotent_id('e2b061bb-13f9-40d8-9d6e-d5bf17595849')
     def test_get_hypervisor_stats_with_non_admin_user(self):
         self.assertRaises(
             lib_exc.Forbidden,
             self.non_adm_client.show_hypervisor_statistics)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f60aa680-9a3a-4c7d-90e1-fae3a4891303')
+    @decorators.idempotent_id('f60aa680-9a3a-4c7d-90e1-fae3a4891303')
     def test_get_nonexistent_hypervisor_uptime(self):
         nonexistent_hypervisor_id = data_utils.rand_uuid()
 
@@ -93,7 +94,7 @@
             nonexistent_hypervisor_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('6c3461f9-c04c-4e2a-bebb-71dc9cb47df2')
+    @decorators.idempotent_id('6c3461f9-c04c-4e2a-bebb-71dc9cb47df2')
     def test_get_hypervisor_uptime_with_non_admin_user(self):
         hypers = self._list_hypervisors()
         self.assertGreater(len(hypers), 0)
@@ -104,7 +105,7 @@
             hypers[0]['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('51b3d536-9b14-409c-9bce-c6f7c794994e')
+    @decorators.idempotent_id('51b3d536-9b14-409c-9bce-c6f7c794994e')
     def test_get_hypervisor_list_with_non_admin_user(self):
         # List of hypervisor and available services with non admin user
         self.assertRaises(
@@ -112,7 +113,7 @@
             self.non_adm_client.list_hypervisors)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('dc02db05-e801-4c5f-bc8e-d915290ab345')
+    @decorators.idempotent_id('dc02db05-e801-4c5f-bc8e-d915290ab345')
     def test_get_hypervisor_list_details_with_non_admin_user(self):
         # List of hypervisor details and available services with non admin user
         self.assertRaises(
@@ -120,7 +121,7 @@
             self.non_adm_client.list_hypervisors, detail=True)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('19a45cc1-1000-4055-b6d2-28e8b2ec4faa')
+    @decorators.idempotent_id('19a45cc1-1000-4055-b6d2-28e8b2ec4faa')
     def test_search_nonexistent_hypervisor(self):
         self.assertRaises(
             lib_exc.NotFound,
@@ -128,7 +129,7 @@
             'nonexistent_hypervisor_name')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5b6a6c79-5dc1-4fa5-9c58-9c8085948e74')
+    @decorators.idempotent_id('5b6a6c79-5dc1-4fa5-9c58-9c8085948e74')
     def test_search_hypervisor_with_non_admin_user(self):
         hypers = self._list_hypervisors()
         self.assertGreater(len(hypers), 0)
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log.py b/tempest/api/compute/admin/test_instance_usage_audit_log.py
index 6976783..b613a26 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log.py
@@ -18,7 +18,7 @@
 from six.moves.urllib import parse as urllib
 
 from tempest.api.compute import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class InstanceUsageAuditLogTestJSON(base.BaseV2ComputeAdminTest):
@@ -28,7 +28,7 @@
         super(InstanceUsageAuditLogTestJSON, cls).setup_clients()
         cls.adm_client = cls.os_adm.instance_usages_audit_log_client
 
-    @test.idempotent_id('25319919-33d9-424f-9f99-2c203ee48b9d')
+    @decorators.idempotent_id('25319919-33d9-424f-9f99-2c203ee48b9d')
     def test_list_instance_usage_audit_logs(self):
         # list instance usage audit logs
         body = (self.adm_client.list_instance_usage_audit_logs()
@@ -41,7 +41,7 @@
         for item in expected_items:
             self.assertIn(item, body)
 
-    @test.idempotent_id('6e40459d-7c5f-400b-9e83-449fbc8e7feb')
+    @decorators.idempotent_id('6e40459d-7c5f-400b-9e83-449fbc8e7feb')
     def test_get_instance_usage_audit_log(self):
         # Get instance usage audit log before specified time
         now = datetime.datetime.now()
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
index b908502..16c39c4 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
@@ -18,6 +18,7 @@
 from six.moves.urllib import parse as urllib
 
 from tempest.api.compute import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -30,7 +31,7 @@
         cls.adm_client = cls.os_adm.instance_usages_audit_log_client
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a9d33178-d2c9-4131-ad3b-f4ca8d0308a2')
+    @decorators.idempotent_id('a9d33178-d2c9-4131-ad3b-f4ca8d0308a2')
     def test_instance_usage_audit_logs_with_nonadmin_user(self):
         # the instance_usage_audit_logs API just can be accessed by admin user
         self.assertRaises(lib_exc.Forbidden,
@@ -43,7 +44,7 @@
                           urllib.quote(now.strftime("%Y-%m-%d %H:%M:%S")))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9b952047-3641-41c7-ba91-a809fc5974c8')
+    @decorators.idempotent_id('9b952047-3641-41c7-ba91-a809fc5974c8')
     def test_get_instance_usage_audit_logs_with_invalid_time(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.adm_client.show_instance_usage_audit_log,
diff --git a/tempest/api/compute/admin/test_keypairs_v210.py b/tempest/api/compute/admin/test_keypairs_v210.py
index dfa7c39..b6c2c3d 100644
--- a/tempest/api/compute/admin/test_keypairs_v210.py
+++ b/tempest/api/compute/admin/test_keypairs_v210.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest.api.compute.keypairs import base
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 
 class KeyPairsV210TestJSON(base.BaseKeypairTest):
@@ -30,11 +30,11 @@
 
     def _create_and_check_keypairs(self, user_id):
         key_list = list()
-        for i in range(2):
+        for _ in range(2):
             k_name = data_utils.rand_name('keypair')
-            keypair = self._create_keypair(k_name,
-                                           keypair_type='ssh',
-                                           user_id=user_id)
+            keypair = self.create_keypair(k_name,
+                                          keypair_type='ssh',
+                                          user_id=user_id)
             self.assertEqual(k_name, keypair['name'],
                              "The created keypair name is not equal "
                              "to the requested name!")
@@ -45,7 +45,7 @@
             key_list.append(keypair)
         return key_list
 
-    @test.idempotent_id('3c8484af-cfb3-48f6-b8ba-d5d58bbf3eac')
+    @decorators.idempotent_id('3c8484af-cfb3-48f6-b8ba-d5d58bbf3eac')
     def test_admin_manage_keypairs_for_other_users(self):
         user_id = self.non_admin_client.user_id
         key_list = self._create_and_check_keypairs(user_id)
@@ -56,8 +56,7 @@
         self.assertEqual(user_id, keypair_detail['user_id'],
                          "The fetched keypair is not for requested user!")
         # Create a admin keypair
-        admin_k_name = data_utils.rand_name('keypair')
-        admin_keypair = self._create_keypair(admin_k_name, keypair_type='ssh')
+        admin_keypair = self.create_keypair(keypair_type='ssh')
         admin_keypair.pop('private_key', None)
         admin_keypair.pop('user_id')
 
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index d29a2a0..0ceb13c 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -46,7 +46,6 @@
     def setup_clients(cls):
         super(LiveBlockMigrationTestJSON, cls).setup_clients()
         cls.admin_hosts_client = cls.os_adm.hosts_client
-        cls.admin_servers_client = cls.os_adm.servers_client
         cls.admin_migration_client = cls.os_adm.migrations_client
 
     @classmethod
@@ -73,10 +72,9 @@
             block_migration = (CONF.compute_feature_enabled.
                                block_migration_for_live_migration and
                                not volume_backed)
-        body = self.admin_servers_client.live_migrate_server(
+        self.admin_servers_client.live_migrate_server(
             server_id, host=dest_host, block_migration=block_migration,
             **kwargs)
-        return body
 
     def _get_host_other_than(self, host):
         for target_host in self._get_compute_hostnames():
@@ -131,23 +129,23 @@
             LOG.info("Live migrate back to source %s", source_host)
             self._live_migrate(server_id, source_host, state, volume_backed)
 
-    @test.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
+    @decorators.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
     def test_live_block_migration(self):
         self._test_live_migration()
 
-    @test.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88')
+    @decorators.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88')
     @testtools.skipUnless(CONF.compute_feature_enabled.pause,
                           'Pause is not available.')
     def test_live_block_migration_paused(self):
         self._test_live_migration(state='PAUSED')
 
     @decorators.skip_because(bug="1524898")
-    @test.idempotent_id('5071cf17-3004-4257-ae61-73a84e28badd')
+    @decorators.idempotent_id('5071cf17-3004-4257-ae61-73a84e28badd')
     @test.services('volume')
     def test_volume_backed_live_migration(self):
         self._test_live_migration(volume_backed=True)
 
-    @test.idempotent_id('e19c0cc6-6720-4ed8-be83-b6603ed5c812')
+    @decorators.idempotent_id('e19c0cc6-6720-4ed8-be83-b6603ed5c812')
     @testtools.skipIf(not CONF.compute_feature_enabled.
                       block_migration_for_live_migration,
                       'Block Live migration not available')
diff --git a/tempest/api/compute/admin/test_migrations.py b/tempest/api/compute/admin/test_migrations.py
index 2dd2e89..df8b175 100644
--- a/tempest/api/compute/admin/test_migrations.py
+++ b/tempest/api/compute/admin/test_migrations.py
@@ -15,11 +15,11 @@
 import testtools
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 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
 
@@ -30,15 +30,13 @@
     def setup_clients(cls):
         super(MigrationsAdminTest, cls).setup_clients()
         cls.client = cls.os_adm.migrations_client
-        cls.flavors_admin_client = cls.os_adm.flavors_client
-        cls.admin_servers_client = cls.os_adm.servers_client
 
-    @test.idempotent_id('75c0b83d-72a0-4cf8-a153-631e83e7d53f')
+    @decorators.idempotent_id('75c0b83d-72a0-4cf8-a153-631e83e7d53f')
     def test_list_migrations(self):
         # Admin can get the migrations list
         self.client.list_migrations()
 
-    @test.idempotent_id('1b512062-8093-438e-b47a-37d2f597cd64')
+    @decorators.idempotent_id('1b512062-8093-438e-b47a-37d2f597cd64')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     def test_list_migrations_in_flavor_resize_situation(self):
@@ -55,12 +53,12 @@
 
     def _flavor_clean_up(self, flavor_id):
         try:
-            self.flavors_admin_client.delete_flavor(flavor_id)
-            self.flavors_admin_client.wait_for_resource_deletion(flavor_id)
+            self.admin_flavors_client.delete_flavor(flavor_id)
+            self.admin_flavors_client.wait_for_resource_deletion(flavor_id)
         except exceptions.NotFound:
             pass
 
-    @test.idempotent_id('33f1fec3-ba18-4470-8e4e-1d888e7c3593')
+    @decorators.idempotent_id('33f1fec3-ba18-4470-8e4e-1d888e7c3593')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     def test_resize_server_revert_deleted_flavor(self):
@@ -69,9 +67,9 @@
 
         # First we have to create a flavor that we can delete so make a copy
         # of the normal flavor from which we'd create a server.
-        flavor = self.flavors_admin_client.show_flavor(
+        flavor = self.admin_flavors_client.show_flavor(
             self.flavor_ref)['flavor']
-        flavor = self.flavors_admin_client.create_flavor(
+        flavor = self.admin_flavors_client.create_flavor(
             name=data_utils.rand_name('test_resize_flavor_'),
             ram=flavor['ram'],
             disk=flavor['disk'],
@@ -127,13 +125,13 @@
             server['id'])['server']['OS-EXT-SRV-ATTR:host']
         assert_func(src_host, dst_host)
 
-    @test.idempotent_id('4bf0be52-3b6f-4746-9a27-3143636fe30d')
+    @decorators.idempotent_id('4bf0be52-3b6f-4746-9a27-3143636fe30d')
     @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
                           'Cold migration not available.')
     def test_cold_migration(self):
         self._test_cold_migrate_server(revert=False)
 
-    @test.idempotent_id('caa1aa8b-f4ef-4374-be0d-95f001c2ac2d')
+    @decorators.idempotent_id('caa1aa8b-f4ef-4374-be0d-95f001c2ac2d')
     @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
                           'Cold migration not available.')
     def test_revert_cold_migration(self):
diff --git a/tempest/api/compute/admin/test_networks.py b/tempest/api/compute/admin/test_networks.py
index 8504840..12ae864 100644
--- a/tempest/api/compute/admin/test_networks.py
+++ b/tempest/api/compute/admin/test_networks.py
@@ -15,7 +15,7 @@
 
 from tempest.api.compute import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -32,7 +32,7 @@
         super(NetworksTest, cls).setup_clients()
         cls.client = cls.os_adm.compute_networks_client
 
-    @test.idempotent_id('d206d211-8912-486f-86e2-a9d090d1f416')
+    @decorators.idempotent_id('d206d211-8912-486f-86e2-a9d090d1f416')
     def test_get_network(self):
         networks = self.client.list_networks()['networks']
         if CONF.compute.fixed_network_name:
@@ -53,7 +53,7 @@
                    ['network'])
         self.assertEqual(configured_network['label'], network['label'])
 
-    @test.idempotent_id('df3d1046-6fa5-4b2c-ad0c-cfa46a351cb9')
+    @decorators.idempotent_id('df3d1046-6fa5-4b2c-ad0c-cfa46a351cb9')
     def test_list_all_networks(self):
         networks = self.client.list_networks()['networks']
         # Check the configured network is in the list
@@ -61,5 +61,5 @@
             configured_network = CONF.compute.fixed_network_name
             self.assertIn(configured_network, [x['label'] for x in networks])
         else:
-            network_name = map(lambda x: x['label'], networks)
-            self.assertGreaterEqual(len(network_name), 1)
+            network_labels = [x['label'] for x in networks]
+            self.assertGreaterEqual(len(network_labels), 1)
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index ce0adb4..c9d7722 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -14,13 +14,12 @@
 #    under the License.
 
 from oslo_log import log as logging
-import six
 from testtools import matchers
 
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 LOG = logging.getLogger(__name__)
 
@@ -54,7 +53,7 @@
                                      'instances', 'security_group_rules',
                                      'cores', 'security_groups'))
 
-    @test.idempotent_id('3b0a7c8f-cf58-46b8-a60c-715a32a8ba7d')
+    @decorators.idempotent_id('3b0a7c8f-cf58-46b8-a60c-715a32a8ba7d')
     def test_get_default_quotas(self):
         # Admin can get the default resource quota set for a tenant
         expected_quota_set = self.default_quota_set | set(['id'])
@@ -64,7 +63,7 @@
         for quota in expected_quota_set:
             self.assertIn(quota, quota_set.keys())
 
-    @test.idempotent_id('55fbe2bf-21a9-435b-bbd2-4162b0ed799a')
+    @decorators.idempotent_id('55fbe2bf-21a9-435b-bbd2-4162b0ed799a')
     def test_update_all_quota_resources_for_tenant(self):
         # Admin can update all the resource quota limits for a tenant
         default_quota_set = self.adm_client.show_default_quota_set(
@@ -89,7 +88,7 @@
             self.assertIn(quota, quota_set.keys())
 
     # TODO(afazekas): merge these test cases
-    @test.idempotent_id('ce9e0815-8091-4abd-8345-7fe5b85faa1d')
+    @decorators.idempotent_id('ce9e0815-8091-4abd-8345-7fe5b85faa1d')
     def test_get_updated_quotas(self):
         # Verify that GET shows the updated quota set of project
         project_name = data_utils.rand_name('cpu_quota_project')
@@ -121,7 +120,7 @@
             project_id, user_id=user_id)['quota_set']
         self.assertEqual(2048, quota_set['ram'])
 
-    @test.idempotent_id('389d04f0-3a41-405f-9317-e5f86e3c44f0')
+    @decorators.idempotent_id('389d04f0-3a41-405f-9317-e5f86e3c44f0')
     def test_delete_quota(self):
         # Admin can delete the resource quota set for a project
         project_name = data_utils.rand_name('ram_quota_project')
@@ -165,7 +164,7 @@
     # global state, and possibly needs to be part of a set of
     # tests that get run all by themselves at the end under a
     # 'danger' flag.
-    @test.idempotent_id('7932ab0f-5136-4075-b201-c0e2338df51a')
+    @decorators.idempotent_id('7932ab0f-5136-4075-b201-c0e2338df51a')
     def test_update_default_quotas(self):
         LOG.debug("get the current 'default' quota class values")
         body = (self.adm_client.show_quota_class_set('default')
@@ -175,7 +174,7 @@
         # restore the defaults when the test is done
         self.addCleanup(self._restore_default_quotas, body.copy())
         # increment all of the values for updating the default quota class
-        for quota, default in six.iteritems(body):
+        for quota, default in body.items():
             # NOTE(sdague): we need to increment a lot, otherwise
             # there is a real chance that we go from -1 (unlimited)
             # to a very small number which causes issues.
diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py
index 015e14d..a1dd2e7 100644
--- a/tempest/api/compute/admin/test_quotas_negative.py
+++ b/tempest/api/compute/admin/test_quotas_negative.py
@@ -13,8 +13,8 @@
 #    under the License.
 
 from tempest.api.compute 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
@@ -52,7 +52,7 @@
                         **{quota_item: default_quota_value})
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('733abfe8-166e-47bb-8363-23dbd7ff3476')
+    @decorators.idempotent_id('733abfe8-166e-47bb-8363-23dbd7ff3476')
     def test_update_quota_normal_user(self):
         self.assertRaises(lib_exc.Forbidden,
                           self.client.update_quota_set,
@@ -62,7 +62,7 @@
     # TODO(afazekas): Add dedicated tenant to the skipped quota tests.
     # It can be moved into the setUpClass as well.
     @test.attr(type=['negative'])
-    @test.idempotent_id('91058876-9947-4807-9f22-f6eb17140d9b')
+    @decorators.idempotent_id('91058876-9947-4807-9f22-f6eb17140d9b')
     def test_create_server_when_cpu_quota_is_full(self):
         # Disallow server creation when tenant's vcpu quota is full
         self._update_quota('cores', 0)
@@ -70,7 +70,7 @@
                           self.create_test_server)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('6fdd7012-584d-4327-a61c-49122e0d5864')
+    @decorators.idempotent_id('6fdd7012-584d-4327-a61c-49122e0d5864')
     def test_create_server_when_memory_quota_is_full(self):
         # Disallow server creation when tenant's memory quota is full
         self._update_quota('ram', 0)
@@ -78,7 +78,7 @@
                           self.create_test_server)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7c6be468-0274-449a-81c3-ac1c32ee0161')
+    @decorators.idempotent_id('7c6be468-0274-449a-81c3-ac1c32ee0161')
     def test_create_server_when_instances_quota_is_full(self):
         # Once instances quota limit is reached, disallow server creation
         self._update_quota('instances', 0)
@@ -87,7 +87,8 @@
 
     @decorators.skip_because(bug="1186354",
                              condition=CONF.service_available.neutron)
-    @test.idempotent_id('7c6c8f3b-2bf6-4918-b240-57b136a66aa0')
+    @test.attr(type=['negative'])
+    @decorators.idempotent_id('7c6c8f3b-2bf6-4918-b240-57b136a66aa0')
     @test.services('network')
     def test_security_groups_exceed_limit(self):
         # Negative test: Creation Security Groups over limit should FAIL
@@ -106,7 +107,7 @@
     @decorators.skip_because(bug="1186354",
                              condition=CONF.service_available.neutron)
     @test.attr(type=['negative'])
-    @test.idempotent_id('6e9f436d-f1ed-4f8e-a493-7275dfaa4b4d')
+    @decorators.idempotent_id('6e9f436d-f1ed-4f8e-a493-7275dfaa4b4d')
     @test.services('network')
     def test_security_groups_rules_exceed_limit(self):
         # Negative test: Creation of Security Group Rules should FAIL
diff --git a/tempest/api/compute/admin/test_security_group_default_rules.py b/tempest/api/compute/admin/test_security_group_default_rules.py
index ce350b6..ab97bd4 100644
--- a/tempest/api/compute/admin/test_security_group_default_rules.py
+++ b/tempest/api/compute/admin/test_security_group_default_rules.py
@@ -16,8 +16,8 @@
 
 from tempest.api.compute 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
 
@@ -55,7 +55,7 @@
         self.assertEqual(cidr, rule['ip_range']['cidr'])
         return rule
 
-    @test.idempotent_id('6d880615-eec3-4d29-97c5-7a074dde239d')
+    @decorators.idempotent_id('6d880615-eec3-4d29-97c5-7a074dde239d')
     def test_create_delete_security_group_default_rules(self):
         # Create and delete Security Group default rule
         ip_protocols = ['tcp', 'udp', 'icmp']
@@ -67,7 +67,7 @@
                               self.adm_client.show_security_group_default_rule,
                               rule['id'])
 
-    @test.idempotent_id('4d752e0a-33a1-4c3a-b498-ff8667ca22e5')
+    @decorators.idempotent_id('4d752e0a-33a1-4c3a-b498-ff8667ca22e5')
     def test_create_security_group_default_rule_without_cidr(self):
         ip_protocol = 'udp'
         from_port = 80
@@ -81,7 +81,7 @@
         self.assertNotEqual(0, rule['id'])
         self.assertEqual('0.0.0.0/0', rule['ip_range']['cidr'])
 
-    @test.idempotent_id('29f2d218-69b0-4a95-8f3d-6bd0ef732b3a')
+    @decorators.idempotent_id('29f2d218-69b0-4a95-8f3d-6bd0ef732b3a')
     def test_create_security_group_default_rule_with_blank_cidr(self):
         ip_protocol = 'icmp'
         from_port = 10
@@ -97,7 +97,7 @@
         self.assertNotEqual(0, rule['id'])
         self.assertEqual('0.0.0.0/0', rule['ip_range']['cidr'])
 
-    @test.idempotent_id('6e6de55e-9146-4ae0-89f2-3569586e0b9b')
+    @decorators.idempotent_id('6e6de55e-9146-4ae0-89f2-3569586e0b9b')
     def test_security_group_default_rules_list(self):
         ip_protocol = 'tcp'
         from_port = 22
@@ -114,7 +114,7 @@
         self.assertNotEqual(0, len(rules))
         self.assertIn(rule, rules)
 
-    @test.idempotent_id('15cbb349-86b4-4f71-a048-04b7ef3f150b')
+    @decorators.idempotent_id('15cbb349-86b4-4f71-a048-04b7ef3f150b')
     def test_default_security_group_default_rule_show(self):
         ip_protocol = 'tcp'
         from_port = 22
diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py
index e329869..b4d0f2a 100644
--- a/tempest/api/compute/admin/test_security_groups.py
+++ b/tempest/api/compute/admin/test_security_groups.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -32,14 +33,14 @@
         else:
             self.client.delete_security_group(securitygroup_id)
 
-    @test.idempotent_id('49667619-5af9-4c63-ab5d-2cfdd1c8f7f1')
+    @decorators.idempotent_id('49667619-5af9-4c63-ab5d-2cfdd1c8f7f1')
     @test.services('network')
     def test_list_security_groups_list_all_tenants_filter(self):
         # Admin can list security groups of all tenants
         # List of all security groups created
         security_group_list = []
         # Create two security groups for a non-admin tenant
-        for i in range(2):
+        for _ in range(2):
             name = data_utils.rand_name('securitygroup')
             description = data_utils.rand_name('description')
             securitygroup = self.client.create_security_group(
@@ -50,7 +51,7 @@
 
         client_tenant_id = securitygroup['tenant_id']
         # Create two security groups for admin tenant
-        for i in range(2):
+        for _ in range(2):
             name = data_utils.rand_name('securitygroup')
             description = data_utils.rand_name('description')
             adm_securitygroup = self.adm_client.create_security_group(
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index a8a8b83..4360586 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -15,8 +15,8 @@
 from tempest.api.compute import base
 from tempest.common import compute
 from tempest.common import fixed_network
-from tempest.common.utils import data_utils
 from tempest.common import waiters
+from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 from tempest import test
 
@@ -35,16 +35,17 @@
         super(ServersAdminTestJSON, cls).resource_setup()
 
         cls.s1_name = data_utils.rand_name(cls.__name__ + '-server')
-        server = cls.create_test_server(name=cls.s1_name,
-                                        wait_until='ACTIVE')
+        server = cls.create_test_server(name=cls.s1_name)
         cls.s1_id = server['id']
 
         cls.s2_name = data_utils.rand_name(cls.__name__ + '-server')
         server = cls.create_test_server(name=cls.s2_name,
                                         wait_until='ACTIVE')
         cls.s2_id = server['id']
+        waiters.wait_for_server_status(cls.non_admin_client,
+                                       cls.s1_id, 'ACTIVE')
 
-    @test.idempotent_id('06f960bb-15bb-48dc-873d-f96e89be7870')
+    @decorators.idempotent_id('06f960bb-15bb-48dc-873d-f96e89be7870')
     def test_list_servers_filter_by_error_status(self):
         # Filter the list of servers by server error status
         params = {'status': 'error'}
@@ -60,14 +61,14 @@
         self.assertIn(self.s1_id, map(lambda x: x['id'], servers))
         self.assertNotIn(self.s2_id, map(lambda x: x['id'], servers))
 
-    @test.idempotent_id('d56e9540-73ed-45e0-9b88-98fc419087eb')
+    @decorators.idempotent_id('d56e9540-73ed-45e0-9b88-98fc419087eb')
     def test_list_servers_detailed_filter_by_invalid_status(self):
         params = {'status': 'invalid_status'}
         body = self.client.list_servers(detail=True, **params)
         servers = body['servers']
         self.assertEqual([], servers)
 
-    @test.idempotent_id('51717b38-bdc1-458b-b636-1cf82d99f62f')
+    @decorators.idempotent_id('51717b38-bdc1-458b-b636-1cf82d99f62f')
     def test_list_servers_by_admin(self):
         # Listing servers by admin user returns a list which doesn't
         # contain the other tenants' server by default
@@ -80,7 +81,7 @@
         self.assertNotIn(self.s1_name, servers_name)
         self.assertNotIn(self.s2_name, servers_name)
 
-    @test.idempotent_id('9f5579ae-19b4-4985-a091-2a5d56106580')
+    @decorators.idempotent_id('9f5579ae-19b4-4985-a091-2a5d56106580')
     def test_list_servers_by_admin_with_all_tenants(self):
         # Listing servers by admin user with all tenants parameter
         # Here should be listed all servers
@@ -92,7 +93,8 @@
         self.assertIn(self.s1_name, servers_name)
         self.assertIn(self.s2_name, servers_name)
 
-    @test.idempotent_id('7e5d6b8f-454a-4ba1-8ae2-da857af8338b')
+    @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
 
@@ -101,7 +103,7 @@
         params = {'tenant_id': tenant_id}
         body = self.client.list_servers(detail=True, **params)
         servers = body['servers']
-        servers_name = map(lambda x: x['name'], servers)
+        servers_name = [x['name'] for x in servers]
         self.assertNotIn(self.s1_name, servers_name)
         self.assertNotIn(self.s2_name, servers_name)
 
@@ -109,7 +111,7 @@
         params = {'all_tenants': '', 'tenant_id': tenant_id}
         body = self.client.list_servers(detail=True, **params)
         servers = body['servers']
-        servers_name = map(lambda x: x['name'], servers)
+        servers_name = [x['name'] for x in servers]
         self.assertIn(self.s1_name, servers_name)
         self.assertIn(self.s2_name, servers_name)
 
@@ -118,11 +120,11 @@
         params = {'all_tenants': '', 'tenant_id': admin_tenant_id}
         body = self.client.list_servers(detail=True, **params)
         servers = body['servers']
-        servers_name = map(lambda x: x['name'], servers)
+        servers_name = [x['name'] for x in servers]
         self.assertNotIn(self.s1_name, servers_name)
         self.assertNotIn(self.s2_name, servers_name)
 
-    @test.idempotent_id('86c7a8f7-50cf-43a9-9bac-5b985317134f')
+    @decorators.idempotent_id('86c7a8f7-50cf-43a9-9bac-5b985317134f')
     def test_list_servers_filter_by_exist_host(self):
         # Filter the list of servers by existent host
         name = data_utils.rand_name(self.__class__.__name__ + '-server')
@@ -147,7 +149,7 @@
         self.assertNotIn(test_server['id'],
                          map(lambda x: x['id'], nonexistent_servers))
 
-    @test.idempotent_id('ee8ae470-db70-474d-b752-690b7892cab1')
+    @decorators.idempotent_id('ee8ae470-db70-474d-b752-690b7892cab1')
     def test_reset_state_server(self):
         # Reset server's state to 'error'
         self.client.reset_state(self.s1_id, state='error')
@@ -164,7 +166,7 @@
         self.assertEqual(server['status'], 'ACTIVE')
 
     @decorators.skip_because(bug="1240043")
-    @test.idempotent_id('31ff3486-b8a0-4f56-a6c0-aab460531db3')
+    @decorators.idempotent_id('31ff3486-b8a0-4f56-a6c0-aab460531db3')
     def test_get_server_diagnostics_by_admin(self):
         # Retrieve server diagnostics by admin user
         diagnostic = self.client.show_server_diagnostics(self.s1_id)
@@ -174,7 +176,7 @@
         for key in basic_attrs:
             self.assertIn(key, str(diagnostic.keys()))
 
-    @test.idempotent_id('682cb127-e5bb-4f53-87ce-cb9003604442')
+    @decorators.idempotent_id('682cb127-e5bb-4f53-87ce-cb9003604442')
     def test_rebuild_server_in_error_state(self):
         # The server in error state should be rebuilt using the provided
         # image and changed to ACTIVE state
@@ -202,7 +204,7 @@
         rebuilt_image_id = server['image']['id']
         self.assertEqual(self.image_ref_alt, rebuilt_image_id)
 
-    @test.idempotent_id('7a1323b4-a6a2-497a-96cb-76c07b945c71')
+    @decorators.idempotent_id('7a1323b4-a6a2-497a-96cb-76c07b945c71')
     def test_reset_network_inject_network_info(self):
         # Reset Network of a Server
         server = self.create_test_server(wait_until='ACTIVE')
@@ -210,7 +212,7 @@
         # Inject the Network Info into Server
         self.client.inject_network_info(server['id'])
 
-    @test.idempotent_id('fdcd9b33-0903-4e00-a1f7-b5f6543068d6')
+    @decorators.idempotent_id('fdcd9b33-0903-4e00-a1f7-b5f6543068d6')
     def test_create_server_with_scheduling_hint(self):
         # Create a server with scheduler hints.
         hints = {
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index 206260f..ebdceef 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -16,9 +16,10 @@
 
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 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,6 @@
         super(ServersAdminNegativeTestJSON, cls).setup_clients()
         cls.client = cls.os_adm.servers_client
         cls.non_adm_client = cls.servers_client
-        cls.flavors_client = cls.os_adm.flavors_client
         cls.quotas_client = cls.os_adm.quotas_client
 
     @classmethod
@@ -41,99 +41,75 @@
         super(ServersAdminNegativeTestJSON, cls).resource_setup()
         cls.tenant_id = cls.client.tenant_id
 
-        cls.s1_name = data_utils.rand_name(cls.__name__ + '-server')
-        server = cls.create_test_server(name=cls.s1_name,
-                                        wait_until='ACTIVE')
+        server = cls.create_test_server(wait_until='ACTIVE')
         cls.s1_id = server['id']
 
-    def _get_unused_flavor_id(self):
-        flavor_id = data_utils.rand_int_id(start=1000)
-        while True:
-            try:
-                self.flavors_client.show_flavor(flavor_id)
-            except lib_exc.NotFound:
-                break
-            flavor_id = data_utils.rand_int_id(start=1000)
-        return flavor_id
-
-    @test.idempotent_id('28dcec23-f807-49da-822c-56a92ea3c687')
+    @decorators.idempotent_id('28dcec23-f807-49da-822c-56a92ea3c687')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     @test.attr(type=['negative'])
     def test_resize_server_using_overlimit_ram(self):
         # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
         self.useFixture(fixtures.LockFixture('compute_quotas'))
-        flavor_name = data_utils.rand_name("flavor")
-        flavor_id = self._get_unused_flavor_id()
         quota_set = self.quotas_client.show_quota_set(
             self.tenant_id)['quota_set']
-        ram = int(quota_set['ram'])
+        ram = quota_set['ram']
         if ram == -1:
             raise self.skipException("ram quota set is -1,"
                                      " cannot test overlimit")
         ram += 1
         vcpus = 1
         disk = 5
-        flavor_ref = self.flavors_client.create_flavor(name=flavor_name,
-                                                       ram=ram, vcpus=vcpus,
-                                                       disk=disk,
-                                                       id=flavor_id)['flavor']
-        self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
+        flavor_ref = self.create_flavor(ram=ram, vcpus=vcpus, disk=disk)
         self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit),
                           self.client.resize_server,
                           self.servers[0]['id'],
                           flavor_ref['id'])
 
-    @test.idempotent_id('7368a427-2f26-4ad9-9ba9-911a0ec2b0db')
+    @decorators.idempotent_id('7368a427-2f26-4ad9-9ba9-911a0ec2b0db')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     @test.attr(type=['negative'])
     def test_resize_server_using_overlimit_vcpus(self):
         # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
         self.useFixture(fixtures.LockFixture('compute_quotas'))
-        flavor_name = data_utils.rand_name("flavor")
-        flavor_id = self._get_unused_flavor_id()
         quota_set = self.quotas_client.show_quota_set(
             self.tenant_id)['quota_set']
-        vcpus = int(quota_set['cores'])
+        vcpus = quota_set['cores']
         if vcpus == -1:
             raise self.skipException("cores quota set is -1,"
                                      " cannot test overlimit")
         vcpus += 1
         ram = 512
         disk = 5
-        flavor_ref = self.flavors_client.create_flavor(name=flavor_name,
-                                                       ram=ram, vcpus=vcpus,
-                                                       disk=disk,
-                                                       id=flavor_id)['flavor']
-        self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
+        flavor_ref = self.create_flavor(ram=ram, vcpus=vcpus, disk=disk)
         self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit),
                           self.client.resize_server,
                           self.servers[0]['id'],
                           flavor_ref['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('b0b4d8af-1256-41ef-9ee7-25f1c19dde80')
+    @decorators.idempotent_id('b0b4d8af-1256-41ef-9ee7-25f1c19dde80')
     def test_reset_state_server_invalid_state(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.client.reset_state, self.s1_id,
                           state='invalid')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('4cdcc984-fab0-4577-9a9d-6d558527ee9d')
+    @decorators.idempotent_id('4cdcc984-fab0-4577-9a9d-6d558527ee9d')
     def test_reset_state_server_invalid_type(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.client.reset_state, self.s1_id,
                           state=1)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e741298b-8df2-46f0-81cb-8f814ff2504c')
+    @decorators.idempotent_id('e741298b-8df2-46f0-81cb-8f814ff2504c')
     def test_reset_state_server_nonexistent_server(self):
         self.assertRaises(lib_exc.NotFound,
                           self.client.reset_state, '999', state='error')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e84e2234-60d2-42fa-8b30-e2d3049724ac')
+    @decorators.idempotent_id('e84e2234-60d2-42fa-8b30-e2d3049724ac')
     def test_get_server_diagnostics_by_non_admin(self):
         # Non-admin user can not view server diagnostics according to policy
         self.assertRaises(lib_exc.Forbidden,
@@ -141,14 +117,14 @@
                           self.s1_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('46a4e1ca-87ae-4d28-987a-1b6b136a0221')
+    @decorators.idempotent_id('46a4e1ca-87ae-4d28-987a-1b6b136a0221')
     def test_migrate_non_existent_server(self):
         # migrate a non existent server
         self.assertRaises(lib_exc.NotFound,
                           self.client.migrate_server,
                           data_utils.rand_uuid())
 
-    @test.idempotent_id('b0b17f83-d14e-4fc4-8f31-bcc9f3cfa629')
+    @decorators.idempotent_id('b0b17f83-d14e-4fc4-8f31-bcc9f3cfa629')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
diff --git a/tempest/api/compute/admin/test_servers_on_multinodes.py b/tempest/api/compute/admin/test_servers_on_multinodes.py
index 1bbde98..6b92273 100644
--- a/tempest/api/compute/admin/test_servers_on_multinodes.py
+++ b/tempest/api/compute/admin/test_servers_on_multinodes.py
@@ -16,6 +16,7 @@
 
 from tempest.api.compute import base
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -35,7 +36,7 @@
         return self.os_adm.servers_client.show_server(
             server_id)['server']['OS-EXT-SRV-ATTR:host']
 
-    @test.idempotent_id('26a9d5df-6890-45f2-abc4-a659290cb130')
+    @decorators.idempotent_id('26a9d5df-6890-45f2-abc4-a659290cb130')
     @testtools.skipUnless(
         test.is_scheduler_filter_enabled("SameHostFilter"),
         'SameHostFilter is not available.')
@@ -49,7 +50,7 @@
         host02 = self._get_host(server02)
         self.assertEqual(host01, host02)
 
-    @test.idempotent_id('cc7ca884-6e3e-42a3-a92f-c522fcf25e8e')
+    @decorators.idempotent_id('cc7ca884-6e3e-42a3-a92f-c522fcf25e8e')
     @testtools.skipUnless(
         test.is_scheduler_filter_enabled("DifferentHostFilter"),
         'DifferentHostFilter is not available.')
@@ -63,7 +64,7 @@
         host02 = self._get_host(server02)
         self.assertNotEqual(host01, host02)
 
-    @test.idempotent_id('7869cc84-d661-4e14-9f00-c18cdc89cf57')
+    @decorators.idempotent_id('7869cc84-d661-4e14-9f00-c18cdc89cf57')
     @testtools.skipUnless(
         test.is_scheduler_filter_enabled("DifferentHostFilter"),
         'DifferentHostFilter is not available.')
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index 8648b9f..c1c1c82 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -15,7 +15,7 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class ServicesAdminTestJSON(base.BaseV2ComputeAdminTest):
@@ -26,12 +26,12 @@
         super(ServicesAdminTestJSON, cls).setup_clients()
         cls.client = cls.os_adm.services_client
 
-    @test.idempotent_id('5be41ef4-53d1-41cc-8839-5c2a48a1b283')
+    @decorators.idempotent_id('5be41ef4-53d1-41cc-8839-5c2a48a1b283')
     def test_list_services(self):
         services = self.client.list_services()['services']
         self.assertNotEqual(0, len(services))
 
-    @test.idempotent_id('f345b1ec-bc6e-4c38-a527-3ca2bc00bef5')
+    @decorators.idempotent_id('f345b1ec-bc6e-4c38-a527-3ca2bc00bef5')
     def test_get_service_by_service_binary_name(self):
         binary_name = 'nova-compute'
         services = self.client.list_services(binary=binary_name)['services']
@@ -39,7 +39,7 @@
         for service in services:
             self.assertEqual(binary_name, service['binary'])
 
-    @test.idempotent_id('affb42d5-5b4b-43c8-8b0b-6dca054abcca')
+    @decorators.idempotent_id('affb42d5-5b4b-43c8-8b0b-6dca054abcca')
     def test_get_service_by_host_name(self):
         services = self.client.list_services()['services']
         host_name = services[0]['host']
@@ -57,7 +57,7 @@
         # on order.
         self.assertEqual(sorted(s1), sorted(s2))
 
-    @test.idempotent_id('39397f6f-37b8-4234-8671-281e44c74025')
+    @decorators.idempotent_id('39397f6f-37b8-4234-8671-281e44c74025')
     def test_get_service_by_service_and_host_name(self):
         services = self.client.list_services()['services']
         host_name = services[0]['host']
diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py
index 710cac4..9447a09 100644
--- a/tempest/api/compute/admin/test_services_negative.py
+++ b/tempest/api/compute/admin/test_services_negative.py
@@ -13,6 +13,7 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -27,13 +28,13 @@
         cls.non_admin_client = cls.services_client
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('1126d1f8-266e-485f-a687-adc547492646')
+    @decorators.idempotent_id('1126d1f8-266e-485f-a687-adc547492646')
     def test_list_services_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_client.list_services)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d0884a69-f693-4e79-a9af-232d15643bf7')
+    @decorators.idempotent_id('d0884a69-f693-4e79-a9af-232d15643bf7')
     def test_get_service_by_invalid_params(self):
         # return all services if send the request with invalid parameter
         services = self.client.list_services()['services']
@@ -42,7 +43,7 @@
         self.assertEqual(len(services), len(services_xxx))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('1e966d4a-226e-47c7-b601-0b18a27add54')
+    @decorators.idempotent_id('1e966d4a-226e-47c7-b601-0b18a27add54')
     def test_get_service_by_invalid_service_and_valid_host(self):
         services = self.client.list_services()['services']
         host_name = services[0]['host']
@@ -51,7 +52,7 @@
         self.assertEqual(0, len(services))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('64e7e7fb-69e8-4cb6-a71d-8d5eb0c98655')
+    @decorators.idempotent_id('64e7e7fb-69e8-4cb6-a71d-8d5eb0c98655')
     def test_get_service_with_valid_service_and_invalid_host(self):
         services = self.client.list_services()['services']
         binary_name = services[0]['binary']
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py
index dbc22e0..ef55584 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage.py
@@ -17,8 +17,8 @@
 
 from tempest.api.compute import base
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions as e
-from tempest import test
 
 # Time that waits for until returning valid response
 # TODO(takmatsu): Ideally this value would come from configuration.
@@ -65,7 +65,7 @@
                              func.__name__, duration))
         return self.resp
 
-    @test.idempotent_id('062c8ae9-9912-4249-8b51-e38d664e926e')
+    @decorators.idempotent_id('062c8ae9-9912-4249-8b51-e38d664e926e')
     def test_list_usage_all_tenants(self):
         # Get usage for all tenants
         tenant_usage = self.call_until_valid(
@@ -73,7 +73,7 @@
             start=self.start, end=self.end, detailed="1")['tenant_usages'][0]
         self.assertEqual(len(tenant_usage), 8)
 
-    @test.idempotent_id('94135049-a4c5-4934-ad39-08fa7da4f22e')
+    @decorators.idempotent_id('94135049-a4c5-4934-ad39-08fa7da4f22e')
     def test_get_usage_tenant(self):
         # Get usage for a specific tenant
         tenant_usage = self.call_until_valid(
@@ -82,7 +82,7 @@
 
         self.assertEqual(len(tenant_usage), 8)
 
-    @test.idempotent_id('9d00a412-b40e-4fd9-8eba-97b496316116')
+    @decorators.idempotent_id('9d00a412-b40e-4fd9-8eba-97b496316116')
     def test_get_usage_tenant_with_non_admin_user(self):
         # Get usage for a specific tenant with non admin user
         tenant_usage = self.call_until_valid(
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
index 315116e..35762d6 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
@@ -16,6 +16,7 @@
 import datetime
 
 from tempest.api.compute import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -41,7 +42,7 @@
         return at.strftime('%Y-%m-%dT%H:%M:%S.%f')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('8b21e135-d94b-4991-b6e9-87059609c8ed')
+    @decorators.idempotent_id('8b21e135-d94b-4991-b6e9-87059609c8ed')
     def test_get_usage_tenant_with_empty_tenant_id(self):
         # Get usage for a specific tenant empty
         params = {'start': self.start,
@@ -51,7 +52,7 @@
                           '', **params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('4079dd2a-9e8d-479f-869d-6fa985ce45b6')
+    @decorators.idempotent_id('4079dd2a-9e8d-479f-869d-6fa985ce45b6')
     def test_get_usage_tenant_with_invalid_date(self):
         # Get usage for tenant with invalid date
         params = {'start': self.end,
@@ -61,7 +62,7 @@
                           self.client.tenant_id, **params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('bbe6fe2c-15d8-404c-a0a2-44fad0ad5cc7')
+    @decorators.idempotent_id('bbe6fe2c-15d8-404c-a0a2-44fad0ad5cc7')
     def test_list_usage_all_tenants_with_non_admin_user(self):
         # Get usage for all tenants with non admin user
         params = {'start': self.start,
diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py
index f603abd..22a5bc4 100644
--- a/tempest/api/compute/admin/test_volume_swap.py
+++ b/tempest/api/compute/admin/test_volume_swap.py
@@ -10,9 +10,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import time
+
 from tempest.api.compute import base
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
@@ -29,6 +33,9 @@
     5. Swap volume from "volume1" to "volume2" as admin.
     6. Check the swap volume is successful and "volume2"
        is attached to "instance1" and "volume1" is in available state.
+    7. Swap volume from "volume2" to "volume1" as admin.
+    8. Check the swap volume is successful and "volume1"
+       is attached to "instance1" and "volume2" is in available state.
     """
 
     @classmethod
@@ -37,13 +44,42 @@
         if not CONF.compute_feature_enabled.swap_volume:
             raise cls.skipException("Swapping volumes is not supported.")
 
-    @classmethod
-    def setup_clients(cls):
-        super(TestVolumeSwap, cls).setup_clients()
-        # We need the admin client for performing the update (swap) volume call
-        cls.servers_admin_client = cls.os_adm.servers_client
+    def _wait_for_server_volume_swap(self, server_id, old_volume_id,
+                                     new_volume_id):
+        """Waits for a server to swap the old volume to a new one."""
+        volume_attachments = self.servers_client.list_volume_attachments(
+            server_id)['volumeAttachments']
+        attached_volume_ids = [attachment['volumeId']
+                               for attachment in volume_attachments]
+        start = int(time.time())
 
-    @test.idempotent_id('1769f00d-a693-4d67-a631-6a3496773813')
+        while (old_volume_id in attached_volume_ids) \
+                or (new_volume_id not in attached_volume_ids):
+            time.sleep(self.servers_client.build_interval)
+            volume_attachments = self.servers_client.list_volume_attachments(
+                server_id)['volumeAttachments']
+            attached_volume_ids = [attachment['volumeId']
+                                   for attachment in volume_attachments]
+
+            if int(time.time()) - start >= self.servers_client.build_timeout:
+                old_vol_bdm_status = 'in BDM' \
+                    if old_volume_id in attached_volume_ids else 'not in BDM'
+                new_vol_bdm_status = 'in BDM' \
+                    if new_volume_id in attached_volume_ids else 'not in BDM'
+                message = ('Failed to swap old volume %(old_volume_id)s '
+                           '(current %(old_vol_bdm_status)s) to new volume '
+                           '%(new_volume_id)s (current %(new_vol_bdm_status)s)'
+                           ' on server %(server_id)s within the required time '
+                           '(%(timeout)s s)' %
+                           {'old_volume_id': old_volume_id,
+                            'old_vol_bdm_status': old_vol_bdm_status,
+                            'new_volume_id': new_volume_id,
+                            'new_vol_bdm_status': new_vol_bdm_status,
+                            'server_id': server_id,
+                            'timeout': self.servers_client.build_timeout})
+                raise lib_exc.TimeoutException(message)
+
+    @decorators.idempotent_id('1769f00d-a693-4d67-a631-6a3496773813')
     @test.services('volume')
     def test_volume_swap(self):
         # Create two volumes.
@@ -57,19 +93,31 @@
         # Attach "volume1" to server
         self.attach_volume(server, volume1)
         # Swap volume from "volume1" to "volume2"
-        self.servers_admin_client.update_attached_volume(
+        self.admin_servers_client.update_attached_volume(
             server['id'], volume1['id'], volumeId=volume2['id'])
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume1['id'], 'available')
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume2['id'], 'in-use')
-        self.addCleanup(self.servers_client.detach_volume,
-                        server['id'], volume2['id'])
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume1['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume2['id'], 'in-use')
+        self._wait_for_server_volume_swap(server['id'], volume1['id'],
+                                          volume2['id'])
         # Verify "volume2" is attached to the server
         vol_attachments = self.servers_client.list_volume_attachments(
             server['id'])['volumeAttachments']
         self.assertEqual(1, len(vol_attachments))
         self.assertIn(volume2['id'], vol_attachments[0]['volumeId'])
 
-        # TODO(mriedem): Test swapping back from volume2 to volume1 after
-        # nova bug 1490236 is fixed.
+        # Swap volume from "volume2" to "volume1"
+        self.admin_servers_client.update_attached_volume(
+            server['id'], volume2['id'], volumeId=volume1['id'])
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume2['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume1['id'], 'in-use')
+        self._wait_for_server_volume_swap(server['id'], volume2['id'],
+                                          volume1['id'])
+        # Verify "volume1" is attached to the server
+        vol_attachments = self.servers_client.list_volume_attachments(
+            server['id'])['volumeAttachments']
+        self.assertEqual(1, len(vol_attachments))
+        self.assertIn(volume1['id'], vol_attachments[0]['volumeId'])
diff --git a/tempest/api/compute/admin/test_volumes_negative.py b/tempest/api/compute/admin/test_volumes_negative.py
index b9dac6f..06b0893 100644
--- a/tempest/api/compute/admin/test_volumes_negative.py
+++ b/tempest/api/compute/admin/test_volumes_negative.py
@@ -13,8 +13,9 @@
 #    under the License.
 
 from tempest.api.compute 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
 
@@ -31,31 +32,29 @@
             raise cls.skipException(skip_msg)
 
     @classmethod
-    def setup_clients(cls):
-        super(VolumesAdminNegativeTest, cls).setup_clients()
-        cls.servers_admin_client = cls.os_adm.servers_client
-
-    @classmethod
     def resource_setup(cls):
         super(VolumesAdminNegativeTest, cls).resource_setup()
         cls.server = cls.create_test_server(wait_until='ACTIVE')
 
-    @test.idempotent_id('309b5ecd-0585-4a7e-a36f-d2b2bf55259d')
+    @test.attr(type=['negative'])
+    @decorators.idempotent_id('309b5ecd-0585-4a7e-a36f-d2b2bf55259d')
     def test_update_attached_volume_with_nonexistent_volume_in_uri(self):
         volume = self.create_volume()
         nonexistent_volume = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound,
-                          self.servers_admin_client.update_attached_volume,
+                          self.admin_servers_client.update_attached_volume,
                           self.server['id'], nonexistent_volume,
                           volumeId=volume['id'])
 
-    @test.idempotent_id('7dcac15a-b107-46d3-a5f6-cb863f4e454a')
+    @test.related_bug('1629110', status_code=400)
+    @test.attr(type=['negative'])
+    @decorators.idempotent_id('7dcac15a-b107-46d3-a5f6-cb863f4e454a')
     def test_update_attached_volume_with_nonexistent_volume_in_body(self):
         volume = self.create_volume()
         self.attach_volume(self.server, volume)
 
         nonexistent_volume = data_utils.rand_uuid()
         self.assertRaises(lib_exc.BadRequest,
-                          self.servers_admin_client.update_attached_volume,
+                          self.admin_servers_client.update_attached_volume,
                           self.server['id'], volume['id'],
                           volumeId=nonexistent_volume)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index d77ea90..1736463 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -19,11 +19,11 @@
 
 from tempest.api.compute import api_microversion_fixture
 from tempest.common import compute
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
 from tempest.lib.common import api_version_utils
+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
@@ -94,10 +94,7 @@
             cls.os.security_group_default_rules_client)
         cls.versions_client = cls.os.compute_versions_client
 
-        if CONF.volume_feature_enabled.api_v1:
-            cls.volumes_client = cls.os.volumes_client
-        else:
-            cls.volumes_client = cls.os.volumes_v2_client
+        cls.volumes_client = cls.os.volumes_v2_client
 
     @classmethod
     def resource_setup(cls):
@@ -295,21 +292,41 @@
     @classmethod
     def create_image_from_server(cls, server_id, **kwargs):
         """Wrapper utility that returns an image created from the server."""
-        name = data_utils.rand_name(cls.__name__ + "-image")
-        if 'name' in kwargs:
-            name = kwargs.pop('name')
+        name = kwargs.pop('name',
+                          data_utils.rand_name(cls.__name__ + "-image"))
+        wait_until = kwargs.pop('wait_until', None)
+        wait_for_server = kwargs.pop('wait_for_server', True)
 
-        image = cls.compute_images_client.create_image(server_id, name=name)
+        image = cls.compute_images_client.create_image(server_id, name=name,
+                                                       **kwargs)
         image_id = data_utils.parse_image_id(image.response['location'])
         cls.images.append(image_id)
 
-        if 'wait_until' in kwargs:
-            waiters.wait_for_image_status(cls.compute_images_client,
-                                          image_id, kwargs['wait_until'])
+        if wait_until is not None:
+            try:
+                waiters.wait_for_image_status(cls.compute_images_client,
+                                              image_id, wait_until)
+            except lib_exc.NotFound:
+                if 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):
+            if wait_until.upper() == 'ACTIVE':
+                if wait_for_server:
                     waiters.wait_for_server_status(cls.servers_client,
                                                    server_id, 'ACTIVE')
         return image
@@ -392,8 +409,8 @@
             kwargs['imageRef'] = image_ref
         volume = cls.volumes_client.create_volume(**kwargs)['volume']
         cls.volumes.append(volume)
-        waiters.wait_for_volume_status(cls.volumes_client,
-                                       volume['id'], 'available')
+        waiters.wait_for_volume_resource_status(cls.volumes_client,
+                                                volume['id'], 'available')
         return volume
 
     @classmethod
@@ -427,20 +444,21 @@
         attach_kwargs = dict(volumeId=volume['id'])
         if device:
             attach_kwargs['device'] = device
-        self.servers_client.attach_volume(
-            server['id'], **attach_kwargs)
+        attachment = self.servers_client.attach_volume(
+            server['id'], **attach_kwargs)['volumeAttachment']
         # On teardown detach the volume and wait for it to be available. This
         # is so we don't error out when trying to delete the volume during
         # teardown.
-        self.addCleanup(waiters.wait_for_volume_status,
+        self.addCleanup(waiters.wait_for_volume_resource_status,
                         self.volumes_client, volume['id'], 'available')
         # Ignore 404s on detach in case the server is deleted or the volume
         # is already detached.
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.servers_client.detach_volume,
                         server['id'], volume['id'])
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume['id'], 'in-use')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'in-use')
+        return attachment
 
 
 class BaseV2ComputeAdminTest(BaseV2ComputeTest):
@@ -453,3 +471,18 @@
         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
+        cls.admin_servers_client = cls.os_adm.servers_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/certificates/test_certificates.py b/tempest/api/compute/certificates/test_certificates.py
index d5c7302..a39fec9 100644
--- a/tempest/api/compute/certificates/test_certificates.py
+++ b/tempest/api/compute/certificates/test_certificates.py
@@ -15,7 +15,7 @@
 
 from tempest.api.compute import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -28,14 +28,14 @@
         if not CONF.compute_feature_enabled.nova_cert:
             raise cls.skipException("Nova cert is not available")
 
-    @test.idempotent_id('c070a441-b08e-447e-a733-905909535b1b')
+    @decorators.idempotent_id('c070a441-b08e-447e-a733-905909535b1b')
     def test_create_root_certificate(self):
         # create certificates
         body = self.certificates_client.create_certificate()['certificate']
         self.assertIn('data', body)
         self.assertIn('private_key', body)
 
-    @test.idempotent_id('3ac273d0-92d2-4632-bdfc-afbc21d4606c')
+    @decorators.idempotent_id('3ac273d0-92d2-4632-bdfc-afbc21d4606c')
     def test_get_root_certificate(self):
         # get the root certificate
         body = (self.certificates_client.show_certificate('root')
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index 7e01296..89051c1 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -21,107 +22,106 @@
     _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')
-    @test.idempotent_id('e36c0eaa-dff5-4082-ad1f-3f9a80aa3f59')
+    @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)
 
-    @test.idempotent_id('6e85fde4-b3cd-4137-ab72-ed5f418e8c24')
+    @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')
-    @test.idempotent_id('1f12046b-753d-40d2-abb6-d8eb8b30cb2f')
+    @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'])
 
-    @test.idempotent_id('8d7691b3-6ed4-411a-abc9-2839a765adab')
+    @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))
 
-    @test.idempotent_id('b26f6327-2886-467a-82be-cef7a27709cb')
+    @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))
 
-    @test.idempotent_id('e800f879-9828-4bd0-8eae-4f17189951fb')
+    @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.')
 
-    @test.idempotent_id('6db2f0c0-ddee-4162-9c84-0703d3dd1107')
+    @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.')
 
-    @test.idempotent_id('3df2743e-3034-4e57-a4cb-b6527f6eac79')
+    @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]))
 
-    @test.idempotent_id('09fe7509-b4ee-4b34-bf8b-39532dc47292')
+    @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]))
 
-    @test.idempotent_id('10645a4d-96f5-443f-831b-730711e11dd4')
+    @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]))
 
-    @test.idempotent_id('935cf550-e7c8-4da6-8002-00f92d5edfaa')
+    @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/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
new file mode 100644
index 0000000..eee6bd2
--- /dev/null
+++ b/tempest/api/compute/flavors/test_flavors_negative.py
@@ -0,0 +1,90 @@
+# Copyright 2017 Red Hat, Inc.
+# 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 random
+
+import six
+
+from tempest.api.compute import base
+from tempest.common import image as common_image
+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
+
+
+class FlavorsV2NegativeTest(base.BaseV2ComputeTest):
+
+    @classmethod
+    def setup_clients(cls):
+        super(FlavorsV2NegativeTest, cls).setup_clients()
+        if CONF.image_feature_enabled.api_v1:
+            cls.images_client = cls.os.image_client
+        elif CONF.image_feature_enabled.api_v2:
+            cls.images_client = cls.os.image_client_v2
+        else:
+            raise lib_exc.InvalidConfiguration(
+                'Either api_v1 or api_v2 must be True in '
+                '[image-feature-enabled].')
+
+    @test.attr(type=['negative'])
+    @test.services('image')
+    @decorators.idempotent_id('90f0d93a-91c1-450c-91e6-07d18172cefe')
+    def test_boot_with_low_ram(self):
+        """Try boot a vm with lower than min ram
+
+        Create an image with min_ram value
+        Try to create server with flavor of insufficient ram size from
+        that image
+        """
+        flavor = self.flavors_client.show_flavor(
+            CONF.compute.flavor_ref)['flavor']
+        min_img_ram = flavor['ram'] + 1
+        size = random.randint(1024, 4096)
+        image_file = six.BytesIO(data_utils.random_bytes(size))
+        params = {
+            'name': data_utils.rand_name('image'),
+            'container_format': CONF.image.container_formats[0],
+            'disk_format': CONF.image.disk_formats[0],
+            'min_ram': min_img_ram
+        }
+
+        if CONF.image_feature_enabled.api_v1:
+            params.update({'is_public': False})
+            params = {'headers': common_image.image_meta_to_headers(**params)}
+        else:
+            params.update({'visibility': 'private'})
+
+        image = self.images_client.create_image(**params)
+        image = image['image'] if 'image' in image else image
+        self.addCleanup(self.images_client.delete_image, image['id'])
+
+        if CONF.image_feature_enabled.api_v1:
+            self.images_client.update_image(image['id'], data=image_file)
+        else:
+            self.images_client.store_image_file(image['id'], data=image_file)
+
+        self.assertEqual(min_img_ram, image['min_ram'])
+
+        # Try to create server with flavor of insufficient ram size
+        self.assertRaisesRegexp(lib_exc.BadRequest,
+                                "Flavor's memory is too small for "
+                                "requested image",
+                                self.create_test_server,
+                                image_id=image['id'],
+                                flavor=flavor['id'])
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index dcb2d2c..2769245 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -13,9 +13,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 from tempest.api.compute.floating_ips 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
 
@@ -52,7 +55,7 @@
             cls.client.delete_floating_ip(cls.floating_ip_id)
         super(FloatingIPsTestJSON, cls).resource_cleanup()
 
-    @test.idempotent_id('f7bfb946-297e-41b8-9e8c-aba8e9bb5194')
+    @decorators.idempotent_id('f7bfb946-297e-41b8-9e8c-aba8e9bb5194')
     @test.services('network')
     def test_allocate_floating_ip(self):
         # Positive test:Allocation of a new floating IP to a project
@@ -68,7 +71,7 @@
         body = self.client.list_floating_ips()['floating_ips']
         self.assertIn(floating_ip_details, body)
 
-    @test.idempotent_id('de45e989-b5ca-4a9b-916b-04a52e7bbb8b')
+    @decorators.idempotent_id('de45e989-b5ca-4a9b-916b-04a52e7bbb8b')
     @test.services('network')
     def test_delete_floating_ip(self):
         # Positive test:Deletion of valid floating IP from project
@@ -83,8 +86,10 @@
         # Check it was really deleted.
         self.client.wait_for_resource_deletion(floating_ip_body['id'])
 
-    @test.idempotent_id('307efa27-dc6f-48a0-8cd2-162ce3ef0b52')
+    @decorators.idempotent_id('307efa27-dc6f-48a0-8cd2-162ce3ef0b52')
     @test.services('network')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     def test_associate_disassociate_floating_ip(self):
         # Positive test:Associate and disassociate the provided floating IP
         # to a specific server should be successful
@@ -104,8 +109,10 @@
             self.floating_ip,
             self.server_id)
 
-    @test.idempotent_id('6edef4b2-aaf1-4abc-bbe3-993e2561e0fe')
+    @decorators.idempotent_id('6edef4b2-aaf1-4abc-bbe3-993e2561e0fe')
     @test.services('network')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     def test_associate_already_associated_floating_ip(self):
         # positive test:Association of an already associated floating IP
         # to specific server should change the association of the Floating IP
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
index 31cf39c..b3c3e17 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
@@ -14,8 +14,9 @@
 #    under the License.
 
 from tempest.api.compute.floating_ips 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
 
@@ -48,7 +49,7 @@
                 break
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('6e0f059b-e4dd-48fb-8207-06e3bba5b074')
+    @decorators.idempotent_id('6e0f059b-e4dd-48fb-8207-06e3bba5b074')
     @test.services('network')
     def test_allocate_floating_ip_from_nonexistent_pool(self):
         # Negative test:Allocation of a new floating IP from a nonexistent_pool
@@ -58,7 +59,7 @@
                           pool="non_exist_pool")
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ae1c55a8-552b-44d4-bfb6-2a115a15d0ba')
+    @decorators.idempotent_id('ae1c55a8-552b-44d4-bfb6-2a115a15d0ba')
     @test.services('network')
     def test_delete_nonexistent_floating_ip(self):
         # Negative test:Deletion of a nonexistent floating IP
@@ -69,7 +70,7 @@
                           self.non_exist_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('595fa616-1a71-4670-9614-46564ac49a4c')
+    @decorators.idempotent_id('595fa616-1a71-4670-9614-46564ac49a4c')
     @test.services('network')
     def test_associate_nonexistent_floating_ip(self):
         # Negative test:Association of a non existent floating IP
@@ -80,7 +81,7 @@
                           "0.0.0.0", self.server_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0a081a66-e568-4e6b-aa62-9587a876dca8')
+    @decorators.idempotent_id('0a081a66-e568-4e6b-aa62-9587a876dca8')
     @test.services('network')
     def test_dissociate_nonexistent_floating_ip(self):
         # Negative test:Dissociation of a non existent floating IP should fail
@@ -90,7 +91,7 @@
                           "0.0.0.0", self.server_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('804b4fcb-bbf5-412f-925d-896672b61eb3')
+    @decorators.idempotent_id('804b4fcb-bbf5-412f-925d-896672b61eb3')
     @test.services('network')
     def test_associate_ip_to_server_without_passing_floating_ip(self):
         # Negative test:Association of empty floating IP to specific server
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index 222bf18..71f5f13 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -15,6 +15,7 @@
 
 from tempest.api.compute import base
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -33,7 +34,7 @@
         super(FloatingIPDetailsTestJSON, cls).resource_setup()
         cls.floating_ip = []
         cls.floating_ip_id = []
-        for i in range(3):
+        for _ in range(3):
             body = cls.client.create_floating_ip(
                 pool=CONF.network.floating_network_name)['floating_ip']
             cls.floating_ip.append(body)
@@ -45,7 +46,7 @@
             cls.client.delete_floating_ip(f_id)
         super(FloatingIPDetailsTestJSON, cls).resource_cleanup()
 
-    @test.idempotent_id('16db31c3-fb85-40c9-bbe2-8cf7b67ff99f')
+    @decorators.idempotent_id('16db31c3-fb85-40c9-bbe2-8cf7b67ff99f')
     @test.services('network')
     def test_list_floating_ips(self):
         # Positive test:Should return the list of floating IPs
@@ -56,7 +57,7 @@
         for i in range(3):
             self.assertIn(self.floating_ip[i], floating_ips)
 
-    @test.idempotent_id('eef497e0-8ff7-43c8-85ef-558440574f84')
+    @decorators.idempotent_id('eef497e0-8ff7-43c8-85ef-558440574f84')
     @test.services('network')
     def test_get_floating_ip_details(self):
         # Positive test:Should be able to GET the details of floatingIP
@@ -78,7 +79,7 @@
                          body['fixed_ip'])
         self.assertEqual(floating_ip_id, body['id'])
 
-    @test.idempotent_id('df389fc8-56f5-43cc-b290-20eda39854d3')
+    @decorators.idempotent_id('df389fc8-56f5-43cc-b290-20eda39854d3')
     @test.services('network')
     def test_list_floating_ip_pools(self):
         # Positive test:Should return the list of floating IP Pools
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
index ea56ae9..388db0b 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
@@ -14,8 +14,9 @@
 #    under the License.
 
 from tempest.api.compute 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
 
@@ -30,7 +31,7 @@
         cls.client = cls.floating_ips_client
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7ab18834-4a4b-4f28-a2c5-440579866695')
+    @decorators.idempotent_id('7ab18834-4a4b-4f28-a2c5-440579866695')
     @test.services('network')
     def test_get_nonexistent_floating_ip_details(self):
         # Negative test:Should not be able to GET the details
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index 26d4efe..dcc44d8 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -17,11 +17,11 @@
 
 from tempest.api.compute import base
 from tempest.common import image as common_image
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 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
 
@@ -83,7 +83,7 @@
         meta = {'os_version': 'value1', 'os_distro': 'value2'}
         self.client.set_image_metadata(self.image_id, meta)
 
-    @test.idempotent_id('37ec6edd-cf30-4c53-bd45-ae74db6b0531')
+    @decorators.idempotent_id('37ec6edd-cf30-4c53-bd45-ae74db6b0531')
     def test_list_image_metadata(self):
         # All metadata key/value pairs for an image should be returned
         resp_metadata = self.client.list_image_metadata(self.image_id)
@@ -91,7 +91,7 @@
             'os_version': 'value1', 'os_distro': 'value2'}}
         self.assertEqual(expected, resp_metadata)
 
-    @test.idempotent_id('ece7befc-d3ce-42a4-b4be-c3067a418c29')
+    @decorators.idempotent_id('ece7befc-d3ce-42a4-b4be-c3067a418c29')
     def test_set_image_metadata(self):
         # The metadata for the image should match the new values
         req_metadata = {'os_version': 'value2', 'architecture': 'value3'}
@@ -102,7 +102,7 @@
                          ['metadata'])
         self.assertEqual(req_metadata, resp_metadata)
 
-    @test.idempotent_id('7b491c11-a9d5-40fe-a696-7f7e03d3fea2')
+    @decorators.idempotent_id('7b491c11-a9d5-40fe-a696-7f7e03d3fea2')
     def test_update_image_metadata(self):
         # The metadata for the image should match the updated values
         req_metadata = {'os_version': 'alt1', 'architecture': 'value3'}
@@ -116,14 +116,14 @@
             'architecture': 'value3'}}
         self.assertEqual(expected, resp_metadata)
 
-    @test.idempotent_id('4f5db52f-6685-4c75-b848-f4bb363f9aa6')
+    @decorators.idempotent_id('4f5db52f-6685-4c75-b848-f4bb363f9aa6')
     def test_get_image_metadata_item(self):
         # The value for a specific metadata key should be returned
         meta = self.client.show_image_metadata_item(self.image_id,
                                                     'os_distro')['meta']
         self.assertEqual('value2', meta['os_distro'])
 
-    @test.idempotent_id('f2de776a-4778-4d90-a5da-aae63aee64ae')
+    @decorators.idempotent_id('f2de776a-4778-4d90-a5da-aae63aee64ae')
     def test_set_image_metadata_item(self):
         # The value provided for the given meta item should be set for
         # the image
@@ -134,7 +134,7 @@
         expected = {'metadata': {'os_version': 'alt', 'os_distro': 'value2'}}
         self.assertEqual(expected, resp_metadata)
 
-    @test.idempotent_id('a013796c-ba37-4bb5-8602-d944511def14')
+    @decorators.idempotent_id('a013796c-ba37-4bb5-8602-d944511def14')
     def test_delete_image_metadata_item(self):
         # The metadata value/key pair should be deleted from the image
         self.client.delete_image_metadata_item(self.image_id,
diff --git a/tempest/api/compute/images/test_image_metadata_negative.py b/tempest/api/compute/images/test_image_metadata_negative.py
index 489bfbc..9cb4b57 100644
--- a/tempest/api/compute/images/test_image_metadata_negative.py
+++ b/tempest/api/compute/images/test_image_metadata_negative.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
+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
 
@@ -27,7 +28,7 @@
         cls.client = cls.compute_images_client
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('94069db2-792f-4fa8-8bd3-2271a6e0c095')
+    @decorators.idempotent_id('94069db2-792f-4fa8-8bd3-2271a6e0c095')
     def test_list_nonexistent_image_metadata(self):
         # Negative test: List on nonexistent image
         # metadata should not happen
@@ -35,7 +36,7 @@
                           data_utils.rand_uuid())
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a403ef9e-9f95-427c-b70a-3ce3388796f1')
+    @decorators.idempotent_id('a403ef9e-9f95-427c-b70a-3ce3388796f1')
     def test_update_nonexistent_image_metadata(self):
         # Negative test:An update should not happen for a non-existent image
         meta = {'os_distro': 'alt1', 'os_version': 'alt2'}
@@ -44,7 +45,7 @@
                           data_utils.rand_uuid(), meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('41ae052c-6ee6-405c-985e-5712393a620d')
+    @decorators.idempotent_id('41ae052c-6ee6-405c-985e-5712393a620d')
     def test_get_nonexistent_image_metadata_item(self):
         # Negative test: Get on non-existent image should not happen
         self.assertRaises(lib_exc.NotFound,
@@ -52,7 +53,7 @@
                           data_utils.rand_uuid(), 'os_version')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('dc64f2ce-77e8-45b0-88c8-e15041d08eaf')
+    @decorators.idempotent_id('dc64f2ce-77e8-45b0-88c8-e15041d08eaf')
     def test_set_nonexistent_image_metadata(self):
         # Negative test: Metadata should not be set to a non-existent image
         meta = {'os_distro': 'alt1', 'os_version': 'alt2'}
@@ -60,7 +61,7 @@
                           data_utils.rand_uuid(), meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('2154fd03-ab54-457c-8874-e6e3eb56e9cf')
+    @decorators.idempotent_id('2154fd03-ab54-457c-8874-e6e3eb56e9cf')
     def test_set_nonexistent_image_metadata_item(self):
         # Negative test: Metadata item should not be set to a
         # nonexistent image
@@ -71,7 +72,7 @@
                           meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('848e157f-6bcf-4b2e-a5dd-5124025a8518')
+    @decorators.idempotent_id('848e157f-6bcf-4b2e-a5dd-5124025a8518')
     def test_delete_nonexistent_image_metadata_item(self):
         # Negative test: Shouldn't be able to delete metadata
         # item from non-existent image
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index a06f4a7..29bd6da 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -13,10 +13,11 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+import testtools
 
 CONF = config.CONF
 
@@ -39,7 +40,7 @@
         super(ImagesTestJSON, cls).setup_clients()
         cls.client = cls.compute_images_client
 
-    @test.idempotent_id('aa06b52b-2db5-4807-b218-9441f75d74e3')
+    @decorators.idempotent_id('aa06b52b-2db5-4807-b218-9441f75d74e3')
     def test_delete_saving_image(self):
         server = self.create_test_server(wait_until='ACTIVE')
         self.addCleanup(self.servers_client.delete_server, server['id'])
@@ -50,7 +51,7 @@
                .format(image_id=image['id']))
         self.assertTrue(self.client.is_resource_deleted(image['id']), msg)
 
-    @test.idempotent_id('aaacd1d0-55a2-4ce8-818a-b5439df8adc9')
+    @decorators.idempotent_id('aaacd1d0-55a2-4ce8-818a-b5439df8adc9')
     def test_create_image_from_stopped_server(self):
         server = self.create_test_server(wait_until='ACTIVE')
         self.servers_client.stop_server(server['id'])
@@ -64,3 +65,39 @@
                                               wait_for_server=False)
         self.addCleanup(self.client.delete_image, image['id'])
         self.assertEqual(snapshot_name, image['name'])
+
+    @decorators.idempotent_id('71bcb732-0261-11e7-9086-fa163e4fa634')
+    @testtools.skipUnless(CONF.compute_feature_enabled.pause,
+                          'Pause is not available.')
+    def test_create_image_from_paused_server(self):
+        server = self.create_test_server(wait_until='ACTIVE')
+        self.servers_client.pause_server(server['id'])
+        waiters.wait_for_server_status(self.servers_client,
+                                       server['id'], 'PAUSED')
+        self.addCleanup(self.servers_client.delete_server, server['id'])
+
+        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)
+        self.addCleanup(self.client.delete_image, image['id'])
+        self.assertEqual(snapshot_name, image['name'])
+
+    @decorators.idempotent_id('8ca07fec-0262-11e7-907e-fa163e4fa634')
+    @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
+                          'Suspend is not available.')
+    def test_create_image_from_suspended_server(self):
+        server = self.create_test_server(wait_until='ACTIVE')
+        self.servers_client.suspend_server(server['id'])
+        waiters.wait_for_server_status(self.servers_client,
+                                       server['id'], 'SUSPENDED')
+        self.addCleanup(self.servers_client.delete_server, server['id'])
+
+        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)
+        self.addCleanup(self.client.delete_image, image['id'])
+        self.assertEqual(snapshot_name, image['name'])
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index 549262e..86013d4 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -13,9 +13,10 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 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
 
@@ -41,7 +42,7 @@
         cls.client = cls.compute_images_client
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('6cd5a89d-5b47-46a7-93bc-3916f0d84973')
+    @decorators.idempotent_id('6cd5a89d-5b47-46a7-93bc-3916f0d84973')
     def test_create_image_from_deleted_server(self):
         # An image should not be created if the server instance is removed
         server = self.create_test_server(wait_until='ACTIVE')
@@ -50,24 +51,22 @@
         self.servers_client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.servers_client, server['id'])
         # Create a new image after server is deleted
-        name = data_utils.rand_name('image')
         meta = {'image_type': 'test'}
         self.assertRaises(lib_exc.NotFound,
                           self.create_image_from_server,
-                          server['id'], name=name, meta=meta)
+                          server['id'], metadata=meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('82c5b0c4-9dbd-463c-872b-20c4755aae7f')
+    @decorators.idempotent_id('82c5b0c4-9dbd-463c-872b-20c4755aae7f')
     def test_create_image_from_invalid_server(self):
         # An image should not be created with invalid server id
         # Create a new image with invalid server id
-        name = data_utils.rand_name('image')
         meta = {'image_type': 'test'}
         self.assertRaises(lib_exc.NotFound, self.create_image_from_server,
-                          '!@$^&*()', name=name, meta=meta)
+                          data_utils.rand_name('invalid'), metadata=meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ec176029-73dc-4037-8d72-2e4ff60cf538')
+    @decorators.idempotent_id('ec176029-73dc-4037-8d72-2e4ff60cf538')
     def test_create_image_specify_uuid_35_characters_or_less(self):
         # Return an error if Image ID passed is 35 characters or less
         snapshot_name = data_utils.rand_name('test-snap')
@@ -76,7 +75,7 @@
                           test_uuid, name=snapshot_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('36741560-510e-4cc2-8641-55fe4dfb2437')
+    @decorators.idempotent_id('36741560-510e-4cc2-8641-55fe4dfb2437')
     def test_create_image_specify_uuid_37_characters_or_more(self):
         # Return an error if Image ID passed is 37 characters or more
         snapshot_name = data_utils.rand_name('test-snap')
@@ -85,14 +84,14 @@
                           test_uuid, name=snapshot_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('381acb65-785a-4942-94ce-d8f8c84f1f0f')
+    @decorators.idempotent_id('381acb65-785a-4942-94ce-d8f8c84f1f0f')
     def test_delete_image_with_invalid_image_id(self):
         # An image should not be deleted with invalid image id
         self.assertRaises(lib_exc.NotFound, self.client.delete_image,
-                          '!@$^&*()')
+                          data_utils.rand_name('invalid'))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('137aef61-39f7-44a1-8ddf-0adf82511701')
+    @decorators.idempotent_id('137aef61-39f7-44a1-8ddf-0adf82511701')
     def test_delete_non_existent_image(self):
         # Return an error while trying to delete a non-existent image
 
@@ -101,13 +100,13 @@
                           non_existent_image_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e6e41425-af5c-4fe6-a4b5-7b7b963ffda5')
+    @decorators.idempotent_id('e6e41425-af5c-4fe6-a4b5-7b7b963ffda5')
     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('924540c3-f1f1-444c-8f58-718958b6724e')
+    @decorators.idempotent_id('924540c3-f1f1-444c-8f58-718958b6724e')
     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"
@@ -115,13 +114,13 @@
                           invalid_image_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('68e2c175-bd26-4407-ac0f-4ea9ce2139ea')
+    @decorators.idempotent_id('68e2c175-bd26-4407-ac0f-4ea9ce2139ea')
     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('b340030d-82cd-4066-a314-c72fb7c59277')
+    @decorators.idempotent_id('b340030d-82cd-4066-a314-c72fb7c59277')
     def test_delete_image_with_id_over_character_limit(self):
         # Return an error while trying to delete image with id over limit
         invalid_image_id = data_utils.rand_uuid() + "1"
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 0b4a2a8..db24174 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -14,11 +14,9 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
-from tempest.common import waiters
 from tempest import config
-from tempest.lib.common.utils import test_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -46,22 +44,18 @@
         flavor = self.flavors_client.show_flavor(flavor_id)['flavor']
         return flavor['disk']
 
-    @test.idempotent_id('3731d080-d4c5-4872-b41a-64d0d0021314')
+    @decorators.idempotent_id('3731d080-d4c5-4872-b41a-64d0d0021314')
     def test_create_delete_image(self):
         server_id = self.create_test_server(wait_until='ACTIVE')['id']
 
         # Create a new image
         name = data_utils.rand_name('image')
         meta = {'image_type': 'test'}
-        body = self.client.create_image(server_id, name=name,
-                                        metadata=meta)
-        image_id = data_utils.parse_image_id(body.response['location'])
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.client.delete_image, image_id)
-        waiters.wait_for_image_status(self.client, image_id, 'ACTIVE')
+        image = self.create_image_from_server(server_id, name=name,
+                                              metadata=meta,
+                                              wait_until='ACTIVE')
 
         # Verify the image was created correctly
-        image = self.client.show_image(image_id)['image']
         self.assertEqual(name, image['name'])
         self.assertEqual('test', image['metadata']['image_type'])
 
@@ -76,10 +70,11 @@
                       (str(original_image['minDisk']), str(flavor_disk_size)))
 
         # Verify the image was deleted correctly
-        self.client.delete_image(image_id)
-        self.client.wait_for_resource_deletion(image_id)
+        self.client.delete_image(image['id'])
+        self.images.remove(image['id'])
+        self.client.wait_for_resource_deletion(image['id'])
 
-    @test.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6')
+    @decorators.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6')
     def test_create_image_specify_multibyte_character_image_name(self):
         server_id = self.create_test_server(wait_until='ACTIVE')['id']
 
@@ -89,7 +84,7 @@
         # We use a string with 3 byte utf-8 character due to bug
         # #1370954 in glance which will 500 if mysql is used as the
         # backend and it attempts to store a 4 byte utf-8 character
-        utf8_name = data_utils.rand_name('\xe2\x82\xa1')
+        utf8_name = data_utils.rand_name(b'\xe2\x82\xa1'.decode('utf-8'))
         body = self.client.create_image(server_id, name=utf8_name)
         image_id = data_utils.parse_image_id(body.response['location'])
         self.addCleanup(self.client.delete_image, image_id)
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index cd71de7..68563bd 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -17,9 +17,10 @@
 from oslo_log import log as logging
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 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
 
@@ -32,9 +33,6 @@
 
     def tearDown(self):
         """Terminate test instances created after a test is executed."""
-        for image_id in self.image_ids:
-            self.client.delete_image(image_id)
-            self.image_ids.remove(image_id)
         self.server_check_teardown()
         super(ImagesOneServerNegativeTestJSON, self).tearDown()
 
@@ -79,45 +77,41 @@
         server = cls.create_test_server(wait_until='ACTIVE')
         cls.server_id = server['id']
 
-        cls.image_ids = []
-
     @test.attr(type=['negative'])
-    @test.idempotent_id('55d1d38c-dd66-4933-9c8e-7d92aeb60ddc')
+    @decorators.idempotent_id('55d1d38c-dd66-4933-9c8e-7d92aeb60ddc')
     def test_create_image_specify_invalid_metadata(self):
         # Return an error when creating image with invalid metadata
-        snapshot_name = data_utils.rand_name('test-snap')
         meta = {'': ''}
-        self.assertRaises(lib_exc.BadRequest, self.client.create_image,
-                          self.server_id, name=snapshot_name, metadata=meta)
+        self.assertRaises(lib_exc.BadRequest, self.create_image_from_server,
+                          self.server_id, metadata=meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('3d24d11f-5366-4536-bd28-cff32b748eca')
+    @decorators.idempotent_id('3d24d11f-5366-4536-bd28-cff32b748eca')
     def test_create_image_specify_metadata_over_limits(self):
         # Return an error when creating image with meta data over 255 chars
-        snapshot_name = data_utils.rand_name('test-snap')
         meta = {'a' * 256: 'b' * 256}
-        self.assertRaises(lib_exc.BadRequest, self.client.create_image,
-                          self.server_id, name=snapshot_name, metadata=meta)
+        self.assertRaises(lib_exc.BadRequest, self.create_image_from_server,
+                          self.server_id, metadata=meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0460efcf-ee88-4f94-acef-1bf658695456')
+    @decorators.idempotent_id('0460efcf-ee88-4f94-acef-1bf658695456')
     def test_create_second_image_when_first_image_is_being_saved(self):
         # Disallow creating another image when first image is being saved
 
         # Create first snapshot
-        snapshot_name = data_utils.rand_name('test-snap')
-        body = self.client.create_image(self.server_id, name=snapshot_name)
-        image_id = data_utils.parse_image_id(body.response['location'])
-        self.image_ids.append(image_id)
+        image = self.create_image_from_server(self.server_id)
         self.addCleanup(self._reset_server)
 
         # Create second snapshot
-        alt_snapshot_name = data_utils.rand_name('test-snap')
-        self.assertRaises(lib_exc.Conflict, self.client.create_image,
-                          self.server_id, name=alt_snapshot_name)
+        self.assertRaises(lib_exc.Conflict, self.create_image_from_server,
+                          self.server_id)
+
+        image_id = data_utils.parse_image_id(image.response['location'])
+        self.client.delete_image(image_id)
+        self.images.remove(image_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('084f0cbc-500a-4963-8a4e-312905862581')
+    @decorators.idempotent_id('084f0cbc-500a-4963-8a4e-312905862581')
     def test_create_image_specify_name_over_character_limit(self):
         # Return an error if snapshot name over 255 characters is passed
 
@@ -126,18 +120,17 @@
                           self.server_id, name=snapshot_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0894954d-2db2-4195-a45b-ffec0bc0187e')
+    @decorators.idempotent_id('0894954d-2db2-4195-a45b-ffec0bc0187e')
     def test_delete_image_that_is_not_yet_active(self):
         # Return an error while trying to delete an image what is creating
 
-        snapshot_name = data_utils.rand_name('test-snap')
-        body = self.client.create_image(self.server_id, name=snapshot_name)
-        image_id = data_utils.parse_image_id(body.response['location'])
-        self.image_ids.append(image_id)
+        image = self.create_image_from_server(self.server_id)
+        image_id = data_utils.parse_image_id(image.response['location'])
+
         self.addCleanup(self._reset_server)
 
         # Do not wait, attempt to delete the image, ensure it's successful
         self.client.delete_image(image_id)
-        self.image_ids.remove(image_id)
-
-        self.assertRaises(lib_exc.NotFound, self.client.show_image, image_id)
+        self.images.remove(image_id)
+        self.assertRaises(lib_exc.NotFound,
+                          self.client.show_image, image_id)
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index a9c2f7a..7168a8c 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -20,11 +20,11 @@
 
 from tempest.api.compute import base
 from tempest.common import image as common_image
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 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
 
@@ -122,7 +122,7 @@
             cls.server1['id'], wait_until='ACTIVE')
         cls.snapshot2_id = cls.snapshot2['id']
 
-    @test.idempotent_id('a3f5b513-aeb3-42a9-b18e-f091ef73254d')
+    @decorators.idempotent_id('a3f5b513-aeb3-42a9-b18e-f091ef73254d')
     def test_list_images_filter_by_status(self):
         # The list of images should contain only images with the
         # provided status
@@ -133,7 +133,7 @@
         self.assertTrue(any([i for i in images if i['id'] == self.image2_id]))
         self.assertTrue(any([i for i in images if i['id'] == self.image3_id]))
 
-    @test.idempotent_id('33163b73-79f5-4d07-a7ea-9213bcc468ff')
+    @decorators.idempotent_id('33163b73-79f5-4d07-a7ea-9213bcc468ff')
     def test_list_images_filter_by_name(self):
         # List of all images should contain the expected images filtered
         # by name
@@ -144,7 +144,7 @@
         self.assertFalse(any([i for i in images if i['id'] == self.image2_id]))
         self.assertFalse(any([i for i in images if i['id'] == self.image3_id]))
 
-    @test.idempotent_id('9f238683-c763-45aa-b848-232ec3ce3105')
+    @decorators.idempotent_id('9f238683-c763-45aa-b848-232ec3ce3105')
     @testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
                           'Snapshotting is not available.')
     def test_list_images_filter_by_server_id(self):
@@ -161,7 +161,7 @@
         self.assertFalse(any([i for i in images
                               if i['id'] == self.snapshot3_id]))
 
-    @test.idempotent_id('05a377b8-28cf-4734-a1e6-2ab5c38bf606')
+    @decorators.idempotent_id('05a377b8-28cf-4734-a1e6-2ab5c38bf606')
     @testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
                           'Snapshotting is not available.')
     def test_list_images_filter_by_server_ref(self):
@@ -180,7 +180,7 @@
             self.assertTrue(any([i for i in images
                                  if i['id'] == self.snapshot3_id]))
 
-    @test.idempotent_id('e3356918-4d3e-4756-81d5-abc4524ba29f')
+    @decorators.idempotent_id('e3356918-4d3e-4756-81d5-abc4524ba29f')
     @testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
                           'Snapshotting is not available.')
     def test_list_images_filter_by_type(self):
@@ -197,14 +197,14 @@
         self.assertFalse(any([i for i in images
                               if i['id'] == self.image_ref]))
 
-    @test.idempotent_id('3a484ca9-67ba-451e-b494-7fcf28d32d62')
+    @decorators.idempotent_id('3a484ca9-67ba-451e-b494-7fcf28d32d62')
     def test_list_images_limit_results(self):
         # Verify only the expected number of results are returned
         params = {'limit': '1'}
         images = self.client.list_images(**params)['images']
         self.assertEqual(1, len([x for x in images if 'id' in x]))
 
-    @test.idempotent_id('18bac3ae-da27-436c-92a9-b22474d13aab')
+    @decorators.idempotent_id('18bac3ae-da27-436c-92a9-b22474d13aab')
     def test_list_images_filter_by_changes_since(self):
         # Verify only updated images are returned in the detailed list
 
@@ -215,7 +215,7 @@
         found = any([i for i in images if i['id'] == self.image3_id])
         self.assertTrue(found)
 
-    @test.idempotent_id('9b0ea018-6185-4f71-948a-a123a107988e')
+    @decorators.idempotent_id('9b0ea018-6185-4f71-948a-a123a107988e')
     def test_list_images_with_detail_filter_by_status(self):
         # Detailed list of all images should only contain images
         # with the provided status
@@ -226,7 +226,7 @@
         self.assertTrue(any([i for i in images if i['id'] == self.image2_id]))
         self.assertTrue(any([i for i in images if i['id'] == self.image3_id]))
 
-    @test.idempotent_id('644ea267-9bd9-4f3b-af9f-dffa02396a17')
+    @decorators.idempotent_id('644ea267-9bd9-4f3b-af9f-dffa02396a17')
     def test_list_images_with_detail_filter_by_name(self):
         # Detailed list of all images should contain the expected
         # images filtered by name
@@ -237,7 +237,7 @@
         self.assertFalse(any([i for i in images if i['id'] == self.image2_id]))
         self.assertFalse(any([i for i in images if i['id'] == self.image3_id]))
 
-    @test.idempotent_id('ba2fa9a9-b672-47cc-b354-3b4c0600e2cb')
+    @decorators.idempotent_id('ba2fa9a9-b672-47cc-b354-3b4c0600e2cb')
     def test_list_images_with_detail_limit_results(self):
         # Verify only the expected number of results (with full details)
         # are returned
@@ -245,7 +245,7 @@
         images = self.client.list_images(detail=True, **params)['images']
         self.assertEqual(1, len(images))
 
-    @test.idempotent_id('8c78f822-203b-4bf6-8bba-56ebd551cf84')
+    @decorators.idempotent_id('8c78f822-203b-4bf6-8bba-56ebd551cf84')
     @testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
                           'Snapshotting is not available.')
     def test_list_images_with_detail_filter_by_server_ref(self):
@@ -264,7 +264,7 @@
             self.assertTrue(any([i for i in images
                                  if i['id'] == self.snapshot3_id]))
 
-    @test.idempotent_id('888c0cc0-7223-43c5-9db0-b125fd0a393b')
+    @decorators.idempotent_id('888c0cc0-7223-43c5-9db0-b125fd0a393b')
     @testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
                           'Snapshotting is not available.')
     def test_list_images_with_detail_filter_by_type(self):
@@ -282,7 +282,7 @@
         self.assertFalse(any([i for i in images
                               if i['id'] == self.image_ref]))
 
-    @test.idempotent_id('7d439e18-ac2e-4827-b049-7e18004712c4')
+    @decorators.idempotent_id('7d439e18-ac2e-4827-b049-7e18004712c4')
     def test_list_images_with_detail_filter_by_changes_since(self):
         # Verify an update image is returned
 
diff --git a/tempest/api/compute/images/test_list_image_filters_negative.py b/tempest/api/compute/images/test_list_image_filters_negative.py
index 2689f88..403961f 100644
--- a/tempest/api/compute/images/test_list_image_filters_negative.py
+++ b/tempest/api/compute/images/test_list_image_filters_negative.py
@@ -13,8 +13,9 @@
 #    under the License.
 
 from tempest.api.compute 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
 
@@ -36,7 +37,7 @@
         cls.client = cls.compute_images_client
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('391b0440-432c-4d4b-b5da-c5096aa247eb')
+    @decorators.idempotent_id('391b0440-432c-4d4b-b5da-c5096aa247eb')
     def test_get_nonexistent_image(self):
         # Check raises a NotFound
         nonexistent_image = data_utils.rand_uuid()
diff --git a/tempest/api/compute/images/test_list_images.py b/tempest/api/compute/images/test_list_images.py
index ae3667d..5d3cbf3 100644
--- a/tempest/api/compute/images/test_list_images.py
+++ b/tempest/api/compute/images/test_list_images.py
@@ -15,7 +15,7 @@
 
 from tempest.api.compute import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -34,20 +34,20 @@
         super(ListImagesTestJSON, cls).setup_clients()
         cls.client = cls.compute_images_client
 
-    @test.idempotent_id('490d0898-e12a-463f-aef0-c50156b9f789')
+    @decorators.idempotent_id('490d0898-e12a-463f-aef0-c50156b9f789')
     def test_get_image(self):
         # Returns the correct details for a single image
         image = self.client.show_image(self.image_ref)['image']
         self.assertEqual(self.image_ref, image['id'])
 
-    @test.idempotent_id('fd51b7f4-d4a3-4331-9885-866658112a6f')
+    @decorators.idempotent_id('fd51b7f4-d4a3-4331-9885-866658112a6f')
     def test_list_images(self):
         # The list of all images should contain the image
         images = self.client.list_images()['images']
         found = any([i for i in images if i['id'] == self.image_ref])
         self.assertTrue(found)
 
-    @test.idempotent_id('9f94cb6b-7f10-48c5-b911-a0b84d7d4cd6')
+    @decorators.idempotent_id('9f94cb6b-7f10-48c5-b911-a0b84d7d4cd6')
     def test_list_images_with_detail(self):
         # Detailed list of all images should contain the expected images
         images = self.client.list_images(detail=True)['images']
diff --git a/tempest/api/compute/keypairs/base.py b/tempest/api/compute/keypairs/base.py
index ad7f958..0051810 100644
--- a/tempest/api/compute/keypairs/base.py
+++ b/tempest/api/compute/keypairs/base.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest.lib.common.utils import data_utils
 
 
 class BaseKeypairTest(base.BaseV2ComputeTest):
@@ -27,9 +28,12 @@
     def _delete_keypair(self, keypair_name, **params):
         self.client.delete_keypair(keypair_name, **params)
 
-    def _create_keypair(self, keypair_name,
-                        pub_key=None, keypair_type=None,
-                        user_id=None):
+    def create_keypair(self, keypair_name=None,
+                       pub_key=None, keypair_type=None,
+                       user_id=None):
+        if keypair_name is None:
+            keypair_name = data_utils.rand_name(
+                self.__class__.__name__ + '-keypair')
         kwargs = {'name': keypair_name}
         delete_params = {}
         if pub_key:
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 562a508..0b7a967 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -14,21 +14,20 @@
 #    under the License.
 
 from tempest.api.compute.keypairs import base
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 
 class KeyPairsV2TestJSON(base.BaseKeypairTest):
     max_microversion = '2.1'
 
-    @test.idempotent_id('1d1dbedb-d7a0-432a-9d09-83f543c3c19b')
+    @decorators.idempotent_id('1d1dbedb-d7a0-432a-9d09-83f543c3c19b')
     def test_keypairs_create_list_delete(self):
         # Keypairs created should be available in the response list
         # Create 3 keypairs
         key_list = list()
-        for i in range(3):
-            k_name = data_utils.rand_name('keypair')
-            keypair = self._create_keypair(k_name)
+        for _ in range(3):
+            keypair = self.create_keypair()
             # Need to pop these keys so that our compare doesn't fail later,
             # as the keypair dicts from list API doesn't have them.
             keypair.pop('private_key')
@@ -47,11 +46,11 @@
                          "Failed to find keypairs %s in fetched list"
                          % ', '.join(m_key['name'] for m_key in missing_kps))
 
-    @test.idempotent_id('6c1d3123-4519-4742-9194-622cb1714b7d')
+    @decorators.idempotent_id('6c1d3123-4519-4742-9194-622cb1714b7d')
     def test_keypair_create_delete(self):
         # Keypair should be created, verified and deleted
         k_name = data_utils.rand_name('keypair')
-        keypair = self._create_keypair(k_name)
+        keypair = self.create_keypair(k_name)
         private_key = keypair['private_key']
         key_name = keypair['name']
         self.assertEqual(key_name, k_name,
@@ -60,11 +59,11 @@
         self.assertIsNotNone(private_key,
                              "Field private_key is empty or not found.")
 
-    @test.idempotent_id('a4233d5d-52d8-47cc-9a25-e1864527e3df')
+    @decorators.idempotent_id('a4233d5d-52d8-47cc-9a25-e1864527e3df')
     def test_get_keypair_detail(self):
         # Keypair should be created, Got details by name and deleted
         k_name = data_utils.rand_name('keypair')
-        self._create_keypair(k_name)
+        self.create_keypair(k_name)
         keypair_detail = self.client.show_keypair(k_name)['keypair']
         self.assertIn('name', keypair_detail)
         self.assertIn('public_key', keypair_detail)
@@ -75,7 +74,7 @@
         self.assertIsNotNone(public_key,
                              "Field public_key is empty or not found.")
 
-    @test.idempotent_id('39c90c6a-304a-49dd-95ec-2366129def05')
+    @decorators.idempotent_id('39c90c6a-304a-49dd-95ec-2366129def05')
     def test_keypair_create_with_pub_key(self):
         # Keypair should be created with a given public key
         k_name = data_utils.rand_name('keypair')
@@ -88,7 +87,7 @@
                    "LOeB1kYMOBaiUPLQTWXR3JpckqFIQwhIH0zoHlJvZE8hh90"
                    "XcPojYN56tI0OlrGqojbediJYD0rUsJu4weZpbn8vilb3JuDY+jws"
                    "snSA8wzBx3A/8y9Pp1B nova@ubuntu")
-        keypair = self._create_keypair(k_name, pub_key)
+        keypair = self.create_keypair(k_name, pub_key)
         self.assertNotIn('private_key', keypair,
                          "Field private_key is not empty!")
         key_name = keypair['name']
diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py
index 2a6139b..8b5a35b 100644
--- a/tempest/api/compute/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/keypairs/test_keypairs_negative.py
@@ -15,23 +15,23 @@
 #    under the License.
 
 from tempest.api.compute.keypairs import base
-from tempest.common.utils import data_utils
+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 KeyPairsNegativeTestJSON(base.BaseKeypairTest):
     @test.attr(type=['negative'])
-    @test.idempotent_id('29cca892-46ae-4d48-bc32-8fe7e731eb81')
+    @decorators.idempotent_id('29cca892-46ae-4d48-bc32-8fe7e731eb81')
     def test_keypair_create_with_invalid_pub_key(self):
         # Keypair should not be created with a non RSA public key
-        k_name = data_utils.rand_name('keypair')
         pub_key = "ssh-rsa JUNK nova@ubuntu"
         self.assertRaises(lib_exc.BadRequest,
-                          self._create_keypair, k_name, pub_key)
+                          self.create_keypair, pub_key=pub_key)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7cc32e47-4c42-489d-9623-c5e2cb5a2fa5')
+    @decorators.idempotent_id('7cc32e47-4c42-489d-9623-c5e2cb5a2fa5')
     def test_keypair_delete_nonexistent_key(self):
         # Non-existent key deletion should throw a proper error
         k_name = data_utils.rand_name("keypair-non-existent")
@@ -39,53 +39,51 @@
                           k_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('dade320e-69ca-42a9-ba4a-345300f127e0')
+    @decorators.idempotent_id('dade320e-69ca-42a9-ba4a-345300f127e0')
     def test_create_keypair_with_empty_public_key(self):
         # Keypair should not be created with an empty public key
-        k_name = data_utils.rand_name("keypair")
         pub_key = ' '
-        self.assertRaises(lib_exc.BadRequest, self._create_keypair,
-                          k_name, pub_key)
+        self.assertRaises(lib_exc.BadRequest, self.create_keypair,
+                          pub_key=pub_key)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('fc100c19-2926-4b9c-8fdc-d0589ee2f9ff')
+    @decorators.idempotent_id('fc100c19-2926-4b9c-8fdc-d0589ee2f9ff')
     def test_create_keypair_when_public_key_bits_exceeds_maximum(self):
         # Keypair should not be created when public key bits are too long
-        k_name = data_utils.rand_name("keypair")
         pub_key = 'ssh-rsa ' + 'A' * 2048 + ' openstack@ubuntu'
-        self.assertRaises(lib_exc.BadRequest, self._create_keypair,
-                          k_name, pub_key)
+        self.assertRaises(lib_exc.BadRequest, self.create_keypair,
+                          pub_key=pub_key)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0359a7f1-f002-4682-8073-0c91e4011b7c')
+    @decorators.idempotent_id('0359a7f1-f002-4682-8073-0c91e4011b7c')
     def test_create_keypair_with_duplicate_name(self):
         # Keypairs with duplicate names should not be created
         k_name = data_utils.rand_name('keypair')
         self.client.create_keypair(name=k_name)
         # Now try the same keyname to create another key
-        self.assertRaises(lib_exc.Conflict, self._create_keypair,
+        self.assertRaises(lib_exc.Conflict, self.create_keypair,
                           k_name)
         self.client.delete_keypair(k_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('1398abe1-4a84-45fb-9294-89f514daff00')
+    @decorators.idempotent_id('1398abe1-4a84-45fb-9294-89f514daff00')
     def test_create_keypair_with_empty_name_string(self):
         # Keypairs with name being an empty string should not be created
-        self.assertRaises(lib_exc.BadRequest, self._create_keypair,
+        self.assertRaises(lib_exc.BadRequest, self.create_keypair,
                           '')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('3faa916f-779f-4103-aca7-dc3538eee1b7')
+    @decorators.idempotent_id('3faa916f-779f-4103-aca7-dc3538eee1b7')
     def test_create_keypair_with_long_keynames(self):
         # Keypairs with name longer than 255 chars should not be created
         k_name = 'keypair-'.ljust(260, '0')
-        self.assertRaises(lib_exc.BadRequest, self._create_keypair,
+        self.assertRaises(lib_exc.BadRequest, self.create_keypair,
                           k_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('45fbe5e0-acb5-49aa-837a-ff8d0719db91')
+    @decorators.idempotent_id('45fbe5e0-acb5-49aa-837a-ff8d0719db91')
     def test_create_keypair_invalid_name(self):
         # Keypairs with name being an invalid name should not be created
         k_name = 'key_/.\@:'
-        self.assertRaises(lib_exc.BadRequest, self._create_keypair,
+        self.assertRaises(lib_exc.BadRequest, self.create_keypair,
                           k_name)
diff --git a/tempest/api/compute/keypairs/test_keypairs_v22.py b/tempest/api/compute/keypairs/test_keypairs_v22.py
index 997ef9b..f39bb12 100644
--- a/tempest/api/compute/keypairs/test_keypairs_v22.py
+++ b/tempest/api/compute/keypairs/test_keypairs_v22.py
@@ -13,8 +13,8 @@
 #    under the License.
 
 from tempest.api.compute.keypairs import test_keypairs
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 
 class KeyPairsV22TestJSON(test_keypairs.KeyPairsV2TestJSON):
@@ -28,7 +28,7 @@
 
     def _test_keypairs_create_list_show(self, keypair_type=None):
         k_name = data_utils.rand_name('keypair')
-        keypair = self._create_keypair(k_name, keypair_type=keypair_type)
+        keypair = self.create_keypair(k_name, keypair_type=keypair_type)
         # Verify whether 'type' is present in keypair create response of
         # version 2.2 and it is with default value 'ssh'.
         self._check_keypair_type(keypair, keypair_type)
@@ -41,11 +41,11 @@
             if keypair['keypair']['name'] == k_name:
                 self._check_keypair_type(keypair['keypair'], keypair_type)
 
-    @test.idempotent_id('8726fa85-7f98-4b20-af9e-f710a4f3391c')
+    @decorators.idempotent_id('8726fa85-7f98-4b20-af9e-f710a4f3391c')
     def test_keypairsv22_create_list_show(self):
         self._test_keypairs_create_list_show()
 
-    @test.idempotent_id('89d59d43-f735-441a-abcf-0601727f47b6')
+    @decorators.idempotent_id('89d59d43-f735-441a-abcf-0601727f47b6')
     def test_keypairsv22_create_list_show_with_type(self):
         keypair_type = 'x509'
         self._test_keypairs_create_list_show(keypair_type=keypair_type)
diff --git a/tempest/api/compute/limits/test_absolute_limits.py b/tempest/api/compute/limits/test_absolute_limits.py
index 6cc722c..58352bd 100644
--- a/tempest/api/compute/limits/test_absolute_limits.py
+++ b/tempest/api/compute/limits/test_absolute_limits.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class AbsoluteLimitsTestJSON(base.BaseV2ComputeTest):
@@ -24,7 +24,7 @@
         super(AbsoluteLimitsTestJSON, cls).setup_clients()
         cls.client = cls.limits_client
 
-    @test.idempotent_id('b54c66af-6ab6-4cf0-a9e5-a0cb58d75e0b')
+    @decorators.idempotent_id('b54c66af-6ab6-4cf0-a9e5-a0cb58d75e0b')
     def test_absLimits_get(self):
         # To check if all limits are present in the response
         limits = self.client.show_limits()['limits']
diff --git a/tempest/api/compute/limits/test_absolute_limits_negative.py b/tempest/api/compute/limits/test_absolute_limits_negative.py
index 66bc241..21b4b1c 100644
--- a/tempest/api/compute/limits/test_absolute_limits_negative.py
+++ b/tempest/api/compute/limits/test_absolute_limits_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -32,7 +33,7 @@
         cls.client = cls.limits_client
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('215cd465-d8ae-49c9-bf33-9c911913a5c8')
+    @decorators.idempotent_id('215cd465-d8ae-49c9-bf33-9c911913a5c8')
     def test_max_image_meta_exceed_limit(self):
         # We should not create vm with image meta over maxImageMeta limit
         # Get max limit value
@@ -40,11 +41,11 @@
         max_meta = limits['absolute']['maxImageMeta']
 
         # No point in running this test if there is no limit.
-        if int(max_meta) == -1:
+        if max_meta == -1:
             raise self.skipException('no limit for maxImageMeta')
 
         # Create server should fail, since we are passing > metadata Limit!
-        max_meta_data = int(max_meta) + 1
+        max_meta_data = max_meta + 1
 
         meta_data = {}
         for xx in range(max_meta_data):
diff --git a/tempest/api/compute/security_groups/base.py b/tempest/api/compute/security_groups/base.py
index f70f6d3..6148e16 100644
--- a/tempest/api/compute/security_groups/base.py
+++ b/tempest/api/compute/security_groups/base.py
@@ -14,6 +14,11 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest import test
+
+CONF = config.CONF
 
 
 class BaseSecurityGroupsTest(base.BaseV2ComputeTest):
@@ -23,3 +28,11 @@
         # A network and a subnet will be created for these tests
         cls.set_network_resources(network=True, subnet=True)
         super(BaseSecurityGroupsTest, cls).setup_credentials()
+
+    @staticmethod
+    def generate_random_security_group_id():
+        if (CONF.service_available.neutron and
+            test.is_extension_enabled('security-group', 'network')):
+            return data_utils.rand_uuid()
+        else:
+            return data_utils.rand_int_id(start=999)
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 38c294b..a50933b 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -14,11 +14,9 @@
 #    under the License.
 
 from tempest.api.compute.security_groups import base
-from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
-CONF = config.CONF
-
 
 class SecurityGroupRulesTestJSON(base.BaseSecurityGroupsTest):
 
@@ -30,7 +28,6 @@
     @classmethod
     def resource_setup(cls):
         super(SecurityGroupRulesTestJSON, cls).resource_setup()
-        cls.neutron_available = CONF.service_available.neutron
         cls.ip_protocol = 'tcp'
         cls.from_port = 22
         cls.to_port = 22
@@ -43,7 +40,6 @@
         group = {}
         ip_range = {}
         cls.expected = {
-            'id': None,
             'parent_group_id': None,
             'ip_protocol': cls.ip_protocol,
             'from_port': from_port,
@@ -54,13 +50,11 @@
 
     def _check_expected_response(self, actual_rule):
         for key in self.expected:
-            if key == 'id':
-                continue
             self.assertEqual(self.expected[key], actual_rule[key],
                              "Miss-matched key is %s" % key)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('850795d7-d4d3-4e55-b527-a774c0123d3a')
+    @decorators.idempotent_id('850795d7-d4d3-4e55-b527-a774c0123d3a')
     @test.services('network')
     def test_security_group_rules_create(self):
         # Positive test: Creation of Security Group rule
@@ -78,7 +72,7 @@
         self.expected['ip_range'] = {'cidr': '0.0.0.0/0'}
         self._check_expected_response(rule)
 
-    @test.idempotent_id('7a01873e-3c38-4f30-80be-31a043cfe2fd')
+    @decorators.idempotent_id('7a01873e-3c38-4f30-80be-31a043cfe2fd')
     @test.services('network')
     def test_security_group_rules_create_with_optional_cidr(self):
         # Positive test: Creation of Security Group rule
@@ -101,7 +95,7 @@
         self.expected['ip_range'] = {'cidr': cidr}
         self._check_expected_response(rule)
 
-    @test.idempotent_id('7f5d2899-7705-4d4b-8458-4505188ffab6')
+    @decorators.idempotent_id('7f5d2899-7705-4d4b-8458-4505188ffab6')
     @test.services('network')
     def test_security_group_rules_create_with_optional_group_id(self):
         # Positive test: Creation of Security Group rule
@@ -130,7 +124,7 @@
         self._check_expected_response(rule)
 
     @test.attr(type='smoke')
-    @test.idempotent_id('a6154130-5a55-4850-8be4-5e9e796dbf17')
+    @decorators.idempotent_id('a6154130-5a55-4850-8be4-5e9e796dbf17')
     @test.services('network')
     def test_security_group_rules_list(self):
         # Positive test: Created Security Group rules should be
@@ -168,7 +162,7 @@
         self.assertTrue(any([i for i in rules if i['id'] == rule1_id]))
         self.assertTrue(any([i for i in rules if i['id'] == rule2_id]))
 
-    @test.idempotent_id('fc5c5acf-2091-43a6-a6ae-e42760e9ffaf')
+    @decorators.idempotent_id('fc5c5acf-2091-43a6-a6ae-e42760e9ffaf')
     @test.services('network')
     def test_security_group_rules_delete_when_peer_group_deleted(self):
         # Positive test:rule will delete when peer group deleting
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index 32b3ea3..6b8dfdf 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -14,21 +14,11 @@
 #    under the License.
 
 from tempest.api.compute.security_groups 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
-
-
-def not_existing_id():
-    if (CONF.service_available.neutron and
-        test.is_extension_enabled('security-group', 'network')):
-        return data_utils.rand_uuid()
-    else:
-        return data_utils.rand_int_id(start=999)
-
 
 class SecurityGroupRulesNegativeTestJSON(base.BaseSecurityGroupsTest):
 
@@ -38,13 +28,13 @@
         cls.rules_client = cls.security_group_rules_client
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('1d507e98-7951-469b-82c3-23f1e6b8c254')
+    @decorators.idempotent_id('1d507e98-7951-469b-82c3-23f1e6b8c254')
     @test.services('network')
     def test_create_security_group_rule_with_non_existent_id(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with non existent Parent group id
         # Adding rules to the non existent Security Group id
-        parent_group_id = not_existing_id()
+        parent_group_id = self.generate_random_security_group_id()
         ip_protocol = 'tcp'
         from_port = 22
         to_port = 22
@@ -55,7 +45,7 @@
                           to_port=to_port)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('2244d7e4-adb7-4ecb-9930-2d77e123ce4f')
+    @decorators.idempotent_id('2244d7e4-adb7-4ecb-9930-2d77e123ce4f')
     @test.services('network')
     def test_create_security_group_rule_with_invalid_id(self):
         # Negative test: Creation of Security Group rule should FAIL
@@ -72,7 +62,7 @@
                           to_port=to_port)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('8bd56d02-3ffa-4d67-9933-b6b9a01d6089')
+    @decorators.idempotent_id('8bd56d02-3ffa-4d67-9933-b6b9a01d6089')
     @test.services('network')
     def test_create_security_group_rule_duplicate(self):
         # Negative test: Create Security Group rule duplicate should fail
@@ -97,7 +87,7 @@
                           to_port=to_port)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('84c81249-9f6e-439c-9bbf-cbb0d2cddbdf')
+    @decorators.idempotent_id('84c81249-9f6e-439c-9bbf-cbb0d2cddbdf')
     @test.services('network')
     def test_create_security_group_rule_with_invalid_ip_protocol(self):
         # Negative test: Creation of Security Group rule should FAIL
@@ -117,7 +107,7 @@
                           to_port=to_port)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('12bbc875-1045-4f7a-be46-751277baedb9')
+    @decorators.idempotent_id('12bbc875-1045-4f7a-be46-751277baedb9')
     @test.services('network')
     def test_create_security_group_rule_with_invalid_from_port(self):
         # Negative test: Creation of Security Group rule should FAIL
@@ -136,7 +126,7 @@
                           to_port=to_port)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ff88804d-144f-45d1-bf59-dd155838a43a')
+    @decorators.idempotent_id('ff88804d-144f-45d1-bf59-dd155838a43a')
     @test.services('network')
     def test_create_security_group_rule_with_invalid_to_port(self):
         # Negative test: Creation of Security Group rule should FAIL
@@ -155,7 +145,7 @@
                           to_port=to_port)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('00296fa9-0576-496a-ae15-fbab843189e0')
+    @decorators.idempotent_id('00296fa9-0576-496a-ae15-fbab843189e0')
     @test.services('network')
     def test_create_security_group_rule_with_invalid_port_range(self):
         # Negative test: Creation of Security Group rule should FAIL
@@ -174,12 +164,12 @@
                           to_port=to_port)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('56fddcca-dbb8-4494-a0db-96e9f869527c')
+    @decorators.idempotent_id('56fddcca-dbb8-4494-a0db-96e9f869527c')
     @test.services('network')
     def test_delete_security_group_rule_with_non_existent_id(self):
         # Negative test: Deletion of Security Group rule should be FAIL
         # with non existent id
-        non_existent_rule_id = not_existing_id()
+        non_existent_rule_id = self.generate_random_security_group_id()
         self.assertRaises(lib_exc.NotFound,
                           self.rules_client.delete_security_group_rule,
                           non_existent_rule_id)
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index 4184afa..ed0e722 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -14,8 +14,9 @@
 #    under the License.
 
 from tempest.api.compute.security_groups import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
+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
 
@@ -28,13 +29,13 @@
         cls.client = cls.security_groups_client
 
     @test.attr(type='smoke')
-    @test.idempotent_id('eb2b087d-633d-4d0d-a7bd-9e6ba35b32de')
+    @decorators.idempotent_id('eb2b087d-633d-4d0d-a7bd-9e6ba35b32de')
     @test.services('network')
     def test_security_groups_create_list_delete(self):
         # Positive test:Should return the list of Security Groups
         # Create 3 Security Groups
         security_group_list = []
-        for i in range(3):
+        for _ in range(3):
             body = self.create_security_group()
             security_group_list.append(body)
         # Fetch all Security Groups and verify the list
@@ -60,7 +61,7 @@
                          "list" % ', '.join(m_group['name']
                                             for m_group in deleted_sgs))
 
-    @test.idempotent_id('ecc0da4a-2117-48af-91af-993cca39a615')
+    @decorators.idempotent_id('ecc0da4a-2117-48af-91af-993cca39a615')
     @test.services('network')
     def test_security_group_create_get_delete(self):
         # Security Group should be created, fetched and deleted
@@ -82,7 +83,7 @@
         self.client.delete_security_group(securitygroup['id'])
         self.client.wait_for_resource_deletion(securitygroup['id'])
 
-    @test.idempotent_id('fe4abc0d-83f5-4c50-ad11-57a1127297a2')
+    @decorators.idempotent_id('fe4abc0d-83f5-4c50-ad11-57a1127297a2')
     @test.services('network')
     def test_server_security_groups(self):
         # Checks that security groups may be added and linked to a server
@@ -124,7 +125,7 @@
         self.client.delete_security_group(sg['id'])
         self.client.delete_security_group(sg2['id'])
 
-    @test.idempotent_id('7d4e1d3c-3209-4d6d-b020-986304ebad1f')
+    @decorators.idempotent_id('7d4e1d3c-3209-4d6d-b020-986304ebad1f')
     @test.services('network')
     def test_update_security_groups(self):
         # Update security group name and description
@@ -143,3 +144,31 @@
                          ['security_group'])
         self.assertEqual(s_new_name, fetched_group['name'])
         self.assertEqual(s_new_des, fetched_group['description'])
+
+    @decorators.idempotent_id('79517d60-535a-438f-af3d-e6feab1cbea7')
+    @test.services('network')
+    def test_list_security_groups_by_server(self):
+        # Create a couple security groups that we will use
+        # for the server resource this test creates
+        sg = self.create_security_group()
+        sg2 = self.create_security_group()
+        assigned_security_groups_ids = [sg['id'], sg2['id']]
+        # Create server and add the security group created
+        # above to the server we just created
+        server_id = self.create_test_server(wait_until='ACTIVE')['id']
+        # add security groups to server
+        self.servers_client.add_security_group(server_id, name=sg['name'])
+        self.servers_client.add_security_group(server_id, name=sg2['name'])
+
+        # list security groups for a server
+        fetched_groups = (
+            self.servers_client.list_security_groups_by_server(
+                server_id)['security_groups'])
+        fetched_security_groups_ids = [i['id'] for i in fetched_groups]
+        # verifying the security groups ids in list
+        missing_security_groups =\
+            [p for p in assigned_security_groups_ids
+             if p not in fetched_security_groups_ids]
+        self.assertEmpty(missing_security_groups,
+                         "Failed to find security_groups %s in fetched list" %
+                         ', '.join(missing_security_groups))
diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py
index e6abf28..3593237 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -16,8 +16,8 @@
 import testtools
 
 from tempest.api.compute.security_groups 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
@@ -32,41 +32,20 @@
         super(SecurityGroupsNegativeTestJSON, cls).setup_clients()
         cls.client = cls.security_groups_client
 
-    @classmethod
-    def resource_setup(cls):
-        super(SecurityGroupsNegativeTestJSON, cls).resource_setup()
-        cls.neutron_available = CONF.service_available.neutron
-
-    def _generate_a_non_existent_security_group_id(self):
-        security_group_id = []
-        body = self.client.list_security_groups()['security_groups']
-        for i in range(len(body)):
-            security_group_id.append(body[i]['id'])
-        # Generate a non-existent security group id
-        while True:
-            if (self.neutron_available and
-                test.is_extension_enabled('security-group', 'network')):
-                non_exist_id = data_utils.rand_uuid()
-            else:
-                non_exist_id = data_utils.rand_int_id(start=999)
-            if non_exist_id not in security_group_id:
-                break
-        return non_exist_id
-
     @test.attr(type=['negative'])
-    @test.idempotent_id('673eaec1-9b3e-48ed-bdf1-2786c1b9661c')
+    @decorators.idempotent_id('673eaec1-9b3e-48ed-bdf1-2786c1b9661c')
     @test.services('network')
     def test_security_group_get_nonexistent_group(self):
         # Negative test:Should not be able to GET the details
         # of non-existent Security Group
-        non_exist_id = self._generate_a_non_existent_security_group_id()
+        non_exist_id = self.generate_random_security_group_id()
         self.assertRaises(lib_exc.NotFound, self.client.show_security_group,
                           non_exist_id)
 
     @decorators.skip_because(bug="1161411",
                              condition=CONF.service_available.neutron)
     @test.attr(type=['negative'])
-    @test.idempotent_id('1759c3cb-b0fc-44b7-86ce-c99236be911d')
+    @decorators.idempotent_id('1759c3cb-b0fc-44b7-86ce-c99236be911d')
     @test.services('network')
     def test_security_group_create_with_invalid_group_name(self):
         # Negative test: Security Group should not be created with group name
@@ -89,7 +68,7 @@
     @decorators.skip_because(bug="1161411",
                              condition=CONF.service_available.neutron)
     @test.attr(type=['negative'])
-    @test.idempotent_id('777b6f14-aca9-4758-9e84-38783cfa58bc')
+    @decorators.idempotent_id('777b6f14-aca9-4758-9e84-38783cfa58bc')
     @test.services('network')
     def test_security_group_create_with_invalid_group_description(self):
         # Negative test: Security Group should not be created with description
@@ -102,7 +81,7 @@
                           self.client.create_security_group,
                           name=s_name, description=s_description)
 
-    @test.idempotent_id('9fdb4abc-6b66-4b27-b89c-eb215a956168')
+    @decorators.idempotent_id('9fdb4abc-6b66-4b27-b89c-eb215a956168')
     @testtools.skipIf(CONF.service_available.neutron,
                       "Neutron allows duplicate names for security groups")
     @test.attr(type=['negative'])
@@ -119,7 +98,7 @@
                           name=s_name, description=s_description)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('36a1629f-c6da-4a26-b8b8-55e7e5d5cd58')
+    @decorators.idempotent_id('36a1629f-c6da-4a26-b8b8-55e7e5d5cd58')
     @test.services('network')
     def test_delete_the_default_security_group(self):
         # Negative test:Deletion of the "default" Security Group should Fail
@@ -135,16 +114,16 @@
                           default_security_group_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('6727c00b-214c-4f9e-9a52-017ac3e98411')
+    @decorators.idempotent_id('6727c00b-214c-4f9e-9a52-017ac3e98411')
     @test.services('network')
     def test_delete_nonexistent_security_group(self):
         # Negative test:Deletion of a non-existent Security Group should fail
-        non_exist_id = self._generate_a_non_existent_security_group_id()
+        non_exist_id = self.generate_random_security_group_id()
         self.assertRaises(lib_exc.NotFound,
                           self.client.delete_security_group, non_exist_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('1438f330-8fa4-4aeb-8a94-37c250106d7f')
+    @decorators.idempotent_id('1438f330-8fa4-4aeb-8a94-37c250106d7f')
     @test.services('network')
     def test_delete_security_group_without_passing_id(self):
         # Negative test:Deletion of a Security Group with out passing ID
@@ -152,7 +131,7 @@
         self.assertRaises(lib_exc.NotFound,
                           self.client.delete_security_group, '')
 
-    @test.idempotent_id('00579617-fe04-4e1c-9d08-ca7467d2e34b')
+    @decorators.idempotent_id('00579617-fe04-4e1c-9d08-ca7467d2e34b')
     @testtools.skipIf(CONF.service_available.neutron,
                       "Neutron does not check the security group ID")
     @test.attr(type=['negative'])
@@ -167,7 +146,7 @@
                           self.client.update_security_group, sg_id_invalid,
                           name=s_name, description=s_description)
 
-    @test.idempotent_id('cda8d8b4-59f8-4087-821d-20cf5a03b3b1')
+    @decorators.idempotent_id('cda8d8b4-59f8-4087-821d-20cf5a03b3b1')
     @testtools.skipIf(CONF.service_available.neutron,
                       "Neutron does not check the security group name")
     @test.attr(type=['negative'])
@@ -183,7 +162,7 @@
                           self.client.update_security_group,
                           securitygroup_id, name=s_new_name)
 
-    @test.idempotent_id('97d12b1c-a610-4194-93f1-ba859e718b45')
+    @decorators.idempotent_id('97d12b1c-a610-4194-93f1-ba859e718b45')
     @testtools.skipIf(CONF.service_available.neutron,
                       "Neutron does not check the security group description")
     @test.attr(type=['negative'])
@@ -200,11 +179,11 @@
                           securitygroup_id, description=s_new_des)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('27edee9c-873d-4da6-a68a-3c256efebe8f')
+    @decorators.idempotent_id('27edee9c-873d-4da6-a68a-3c256efebe8f')
     @test.services('network')
     def test_update_non_existent_security_group(self):
         # Update a non-existent Security Group should Fail
-        non_exist_id = self._generate_a_non_existent_security_group_id()
+        non_exist_id = self.generate_random_security_group_id()
         s_name = data_utils.rand_name('sg')
         s_description = data_utils.rand_name('description')
         self.assertRaises(lib_exc.NotFound,
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index a21ce94..e0c8887 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -79,7 +79,6 @@
 
     def _check_interface(self, iface, port_id=None, network_id=None,
                          fixed_ip=None, mac_addr=None):
-        self.assertIn('port_state', iface)
         if port_id:
             self.assertEqual(iface['port_id'], port_id)
         if network_id:
@@ -184,7 +183,7 @@
 
         self.assertEqual(sorted(list1), sorted(list2))
 
-    @test.idempotent_id('73fe8f02-590d-4bf1-b184-e9ca81065051')
+    @decorators.idempotent_id('73fe8f02-590d-4bf1-b184-e9ca81065051')
     @test.services('network')
     def test_create_list_show_delete_interfaces(self):
         server, ifs = self._create_server_get_interfaces()
@@ -221,7 +220,7 @@
         self.assertEqual(len(ifs) - 1, len(_ifs))
 
     @test.attr(type='smoke')
-    @test.idempotent_id('c7e0e60b-ee45-43d0-abeb-8596fd42a2f9')
+    @decorators.idempotent_id('c7e0e60b-ee45-43d0-abeb-8596fd42a2f9')
     @test.services('network')
     def test_add_remove_fixed_ip(self):
         # Add and Remove the fixed IP to server.
@@ -246,7 +245,7 @@
         self.servers_client.remove_fixed_ip(server['id'], address=fixed_ip)
 
     @decorators.skip_because(bug='1607714')
-    @test.idempotent_id('2f3a0127-95c7-4977-92d2-bc5aec602fb4')
+    @decorators.idempotent_id('2f3a0127-95c7-4977-92d2-bc5aec602fb4')
     def test_reassign_port_between_servers(self):
         """Tests the following:
 
@@ -268,9 +267,7 @@
             self.os, tenant_network=network, wait_until='ACTIVE', min_count=2)
         # add our cleanups for the servers since we bypassed the base class
         for server in servers:
-            self.addCleanup(waiters.wait_for_server_termination,
-                            self.servers_client, server['id'])
-            self.addCleanup(self.servers_client.delete_server, server['id'])
+            self.addCleanup(self.delete_server, server['id'])
 
         for server in servers:
             # attach the port to the server
diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py
index 00df86b..82e74ed 100644
--- a/tempest/api/compute/servers/test_availability_zone.py
+++ b/tempest/api/compute/servers/test_availability_zone.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class AZV2TestJSON(base.BaseV2ComputeTest):
@@ -25,7 +25,7 @@
         super(AZV2TestJSON, cls).setup_clients()
         cls.client = cls.availability_zone_client
 
-    @test.idempotent_id('a8333aa2-205c-449f-a828-d38c2489bf25')
+    @decorators.idempotent_id('a8333aa2-205c-449f-a828-d38c2489bf25')
     def test_get_availability_zone_list_with_non_admin_user(self):
         # List of availability zone with non-administrator user
         availability_zone = self.client.list_availability_zones()
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 2dcacb7..eb23e4b 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -17,9 +17,10 @@
 import testtools
 
 from tempest.api.compute import base
-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 data_utils
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -50,7 +51,7 @@
         cls.name = data_utils.rand_name(cls.__name__ + '-server')
         cls.password = data_utils.rand_password()
         disk_config = cls.disk_config
-        cls.server_initial = cls.create_test_server(
+        server_initial = cls.create_test_server(
             validatable=True,
             wait_until='ACTIVE',
             name=cls.name,
@@ -59,7 +60,7 @@
             accessIPv6=cls.accessIPv6,
             disk_config=disk_config,
             adminPass=cls.password)
-        cls.server = (cls.client.show_server(cls.server_initial['id'])
+        cls.server = (cls.client.show_server(server_initial['id'])
                       ['server'])
 
     def _create_net_subnet_ret_net_from_cidr(self, cidr):
@@ -77,7 +78,7 @@
         return net
 
     @test.attr(type='smoke')
-    @test.idempotent_id('5de47127-9977-400a-936f-abcfbec1218f')
+    @decorators.idempotent_id('5de47127-9977-400a-936f-abcfbec1218f')
     def test_verify_server_details(self):
         # Verify the specified server attributes are set correctly
         self.assertEqual(self.accessIPv4, self.server['accessIPv4'])
@@ -91,7 +92,7 @@
         self.assertEqual(self.meta, self.server['metadata'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('9a438d88-10c6-4bcd-8b5b-5b6e25e1346f')
+    @decorators.idempotent_id('9a438d88-10c6-4bcd-8b5b-5b6e25e1346f')
     def test_list_servers(self):
         # The created server should be in the list of all servers
         body = self.client.list_servers()
@@ -99,7 +100,7 @@
         found = any([i for i in servers if i['id'] == self.server['id']])
         self.assertTrue(found)
 
-    @test.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997')
+    @decorators.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997')
     def test_list_servers_with_detail(self):
         # The created server should be in the detailed list of all servers
         body = self.client.list_servers(detail=True)
@@ -107,7 +108,7 @@
         found = any([i for i in servers if i['id'] == self.server['id']])
         self.assertTrue(found)
 
-    @test.idempotent_id('cbc0f52f-05aa-492b-bdc1-84b575ca294b')
+    @decorators.idempotent_id('cbc0f52f-05aa-492b-bdc1-84b575ca294b')
     @testtools.skipUnless(CONF.validation.run_validation,
                           'Instance validation tests are disabled.')
     def test_verify_created_server_vcpus(self):
@@ -121,9 +122,10 @@
             self.validation_resources['keypair']['private_key'],
             server=self.server,
             servers_client=self.client)
-        self.assertEqual(flavor['vcpus'], linux_client.get_number_of_vcpus())
+        output = linux_client.exec_command('grep -c ^processor /proc/cpuinfo')
+        self.assertEqual(flavor['vcpus'], int(output))
 
-    @test.idempotent_id('ac1ad47f-984b-4441-9274-c9079b7a0666')
+    @decorators.idempotent_id('ac1ad47f-984b-4441-9274-c9079b7a0666')
     @testtools.skipUnless(CONF.validation.run_validation,
                           'Instance validation tests are disabled.')
     def test_host_name_is_same_as_server_name(self):
@@ -135,12 +137,12 @@
             self.validation_resources['keypair']['private_key'],
             server=self.server,
             servers_client=self.client)
-        hostname = linux_client.get_hostname()
+        hostname = linux_client.exec_command("hostname").rstrip()
         msg = ('Failed while verifying servername equals hostname. Expected '
                'hostname "%s" but got "%s".' % (self.name, hostname))
         self.assertEqual(self.name.lower(), hostname, msg)
 
-    @test.idempotent_id('ed20d3fb-9d1f-4329-b160-543fbd5d9811')
+    @decorators.idempotent_id('ed20d3fb-9d1f-4329-b160-543fbd5d9811')
     @testtools.skipUnless(
         test.is_scheduler_filter_enabled("ServerGroupAffinityFilter"),
         'ServerGroupAffinityFilter is not available.')
@@ -156,7 +158,7 @@
                         ['server_group'])
         self.assertIn(server['id'], server_group['members'])
 
-    @test.idempotent_id('0578d144-ed74-43f8-8e57-ab10dbf9b3c2')
+    @decorators.idempotent_id('0578d144-ed74-43f8-8e57-ab10dbf9b3c2')
     @testtools.skipUnless(CONF.service_available.neutron,
                           'Neutron service must be available.')
     def test_verify_multiple_nics_order(self):
@@ -194,7 +196,7 @@
         for address, network in zip(addr, networks):
             self.assertIn(address, network)
 
-    @test.idempotent_id('1678d144-ed74-43f8-8e57-ab10dbf9b3c2')
+    @decorators.idempotent_id('1678d144-ed74-43f8-8e57-ab10dbf9b3c2')
     @testtools.skipUnless(CONF.service_available.neutron,
                           'Neutron service must be available.')
     def test_verify_duplicate_network_nics(self):
@@ -235,7 +237,6 @@
     @classmethod
     def setup_clients(cls):
         super(ServersWithSpecificFlavorTestJSON, cls).setup_clients()
-        cls.flavor_client = cls.os_adm.flavors_client
         cls.client = cls.servers_client
 
     @classmethod
@@ -244,7 +245,7 @@
 
         super(ServersWithSpecificFlavorTestJSON, cls).resource_setup()
 
-    @test.idempotent_id('b3c7bcfc-bb5b-4e22-b517-c7f686b802ca')
+    @decorators.idempotent_id('b3c7bcfc-bb5b-4e22-b517-c7f686b802ca')
     @testtools.skipUnless(CONF.validation.run_validation,
                           'Instance validation tests are disabled.')
     def test_verify_created_server_ephemeral_disk(self):
@@ -253,7 +254,6 @@
             self.flavor_ref)['flavor']
 
         def create_flavor_with_ephemeral(ephem_disk):
-            flavor_id = data_utils.rand_int_id(start=1000)
             name = 'flavor_with_ephemeral_%s' % ephem_disk
             flavor_name = data_utils.rand_name(name)
 
@@ -262,17 +262,10 @@
             disk = flavor_base['disk']
 
             # Create a flavor with ephemeral disk
-            flavor = self.flavor_client.create_flavor(
-                name=flavor_name, ram=ram, vcpus=vcpus, disk=disk,
-                id=flavor_id, ephemeral=ephem_disk)['flavor']
-            self.addCleanup(flavor_clean_up, flavor['id'])
-
+            flavor = self.create_flavor(name=flavor_name, ram=ram, vcpus=vcpus,
+                                        disk=disk, ephemeral=ephem_disk)
             return flavor['id']
 
-        def flavor_clean_up(flavor_id):
-            self.flavor_client.delete_flavor(flavor_id)
-            self.flavor_client.wait_for_resource_deletion(flavor_id)
-
         flavor_with_eph_disk_id = create_flavor_with_ephemeral(ephem_disk=1)
         flavor_no_eph_disk_id = create_flavor_with_ephemeral(ephem_disk=0)
 
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index 07f46c5..8ed55e0 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -19,6 +19,7 @@
 from tempest.common import compute
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -34,21 +35,21 @@
         super(DeleteServersTestJSON, cls).setup_clients()
         cls.client = cls.servers_client
 
-    @test.idempotent_id('9e6e0c87-3352-42f7-9faf-5d6210dbd159')
+    @decorators.idempotent_id('9e6e0c87-3352-42f7-9faf-5d6210dbd159')
     def test_delete_server_while_in_building_state(self):
         # Delete a server while it's VM state is Building
         server = self.create_test_server(wait_until='BUILD')
         self.client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.client, server['id'])
 
-    @test.idempotent_id('925fdfb4-5b13-47ea-ac8a-c36ae6fddb05')
+    @decorators.idempotent_id('925fdfb4-5b13-47ea-ac8a-c36ae6fddb05')
     def test_delete_active_server(self):
         # Delete a server while it's VM state is Active
         server = self.create_test_server(wait_until='ACTIVE')
         self.client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.client, server['id'])
 
-    @test.idempotent_id('546d368c-bb6c-4645-979a-83ed16f3a6be')
+    @decorators.idempotent_id('546d368c-bb6c-4645-979a-83ed16f3a6be')
     def test_delete_server_while_in_shutoff_state(self):
         # Delete a server while it's VM state is Shutoff
         server = self.create_test_server(wait_until='ACTIVE')
@@ -57,7 +58,7 @@
         self.client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.client, server['id'])
 
-    @test.idempotent_id('943bd6e8-4d7a-4904-be83-7a6cc2d4213b')
+    @decorators.idempotent_id('943bd6e8-4d7a-4904-be83-7a6cc2d4213b')
     @testtools.skipUnless(CONF.compute_feature_enabled.pause,
                           'Pause is not available.')
     def test_delete_server_while_in_pause_state(self):
@@ -68,7 +69,7 @@
         self.client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.client, server['id'])
 
-    @test.idempotent_id('1f82ebd3-8253-4f4e-b93f-de9b7df56d8b')
+    @decorators.idempotent_id('1f82ebd3-8253-4f4e-b93f-de9b7df56d8b')
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
                           'Suspend is not available.')
     def test_delete_server_while_in_suspended_state(self):
@@ -79,7 +80,7 @@
         self.client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.client, server['id'])
 
-    @test.idempotent_id('bb0cb402-09dd-4947-b6e5-5e7e1cfa61ad')
+    @decorators.idempotent_id('bb0cb402-09dd-4947-b6e5-5e7e1cfa61ad')
     @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
                           'Shelve is not available.')
     def test_delete_server_while_in_shelved_state(self):
@@ -90,7 +91,7 @@
         self.client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.client, server['id'])
 
-    @test.idempotent_id('ab0c38b4-cdd8-49d3-9b92-0cb898723c01')
+    @decorators.idempotent_id('ab0c38b4-cdd8-49d3-9b92-0cb898723c01')
     @testtools.skipIf(not CONF.compute_feature_enabled.resize,
                       'Resize not available.')
     def test_delete_server_while_in_verify_resize_state(self):
@@ -102,7 +103,7 @@
         self.client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.client, server['id'])
 
-    @test.idempotent_id('d0f3f0d6-d9b6-4a32-8da4-23015dcab23c')
+    @decorators.idempotent_id('d0f3f0d6-d9b6-4a32-8da4-23015dcab23c')
     @test.services('volume')
     def test_delete_server_while_in_attached_volume(self):
         # Delete a server while a volume is attached to it
@@ -114,8 +115,8 @@
 
         self.client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.client, server['id'])
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'available')
 
 
 class DeleteServersAdminTestJSON(base.BaseV2ComputeAdminTest):
@@ -128,7 +129,7 @@
         cls.non_admin_client = cls.servers_client
         cls.admin_client = cls.os_adm.servers_client
 
-    @test.idempotent_id('99774678-e072-49d1-9d2a-49a59bc56063')
+    @decorators.idempotent_id('99774678-e072-49d1-9d2a-49a59bc56063')
     def test_delete_server_while_in_error_state(self):
         # Delete a server while it's VM state is error
         server = self.create_test_server(wait_until='ACTIVE')
@@ -141,7 +142,7 @@
                                             server['id'],
                                             ignore_error=True)
 
-    @test.idempotent_id('73177903-6737-4f27-a60c-379e8ae8cf48')
+    @decorators.idempotent_id('73177903-6737-4f27-a60c-379e8ae8cf48')
     def test_admin_delete_servers_of_others(self):
         # Administrator can delete servers of others
         server = self.create_test_server(wait_until='ACTIVE')
diff --git a/tempest/api/compute/servers/test_device_tagging.py b/tempest/api/compute/servers/test_device_tagging.py
index b2d5ae7..57aa72e 100644
--- a/tempest/api/compute/servers/test_device_tagging.py
+++ b/tempest/api/compute/servers/test_device_tagging.py
@@ -17,10 +17,11 @@
 from oslo_log import log as logging
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest.common.utils.linux import remote_client
-from tempest.common import waiters
 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 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):
@@ -84,7 +89,7 @@
                                               'net-2-100', 'net-2-200',
                                               'boot', 'other'])
 
-    @test.idempotent_id('a2e65a6c-66f1-4442-aaa8-498c31778d96')
+    @decorators.idempotent_id('a2e65a6c-66f1-4442-aaa8-498c31778d96')
     @test.services('network', 'volume', 'image')
     def test_device_tagging(self):
         # Create volumes
@@ -196,9 +201,7 @@
                 }
             ])
 
-        self.addCleanup(waiters.wait_for_server_termination,
-                        self.servers_client, server['id'])
-        self.addCleanup(self.servers_client.delete_server, server['id'])
+        self.addCleanup(self.delete_server, server['id'])
 
         self.ssh_client = remote_client.RemoteClient(
             self.get_server_ip(server),
@@ -247,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.')
 
@@ -264,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_disk_config.py b/tempest/api/compute/servers/test_disk_config.py
index ff8ea6e..4709180 100644
--- a/tempest/api/compute/servers/test_disk_config.py
+++ b/tempest/api/compute/servers/test_disk_config.py
@@ -18,7 +18,7 @@
 from tempest.api.compute import base
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -46,7 +46,7 @@
             server = self.client.show_server(server['id'])['server']
             self.assertEqual(disk_config, server['OS-DCF:diskConfig'])
 
-    @test.idempotent_id('bef56b09-2e8c-4883-a370-4950812f430e')
+    @decorators.idempotent_id('bef56b09-2e8c-4883-a370-4950812f430e')
     def test_rebuild_server_with_manual_disk_config(self):
         # A server should be rebuilt using the manual disk config option
         server = self.create_test_server(wait_until='ACTIVE')
@@ -65,7 +65,7 @@
         server = self.client.show_server(server['id'])['server']
         self.assertEqual('MANUAL', server['OS-DCF:diskConfig'])
 
-    @test.idempotent_id('9c9fae77-4feb-402f-8450-bf1c8b609713')
+    @decorators.idempotent_id('9c9fae77-4feb-402f-8450-bf1c8b609713')
     def test_rebuild_server_with_auto_disk_config(self):
         # A server should be rebuilt using the auto disk config option
         server = self.create_test_server(wait_until='ACTIVE')
@@ -84,7 +84,7 @@
         server = self.client.show_server(server['id'])['server']
         self.assertEqual('AUTO', server['OS-DCF:diskConfig'])
 
-    @test.idempotent_id('414e7e93-45b5-44bc-8e03-55159c6bfc97')
+    @decorators.idempotent_id('414e7e93-45b5-44bc-8e03-55159c6bfc97')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     def test_resize_server_from_manual_to_auto(self):
@@ -100,7 +100,7 @@
         server = self.client.show_server(server['id'])['server']
         self.assertEqual('AUTO', server['OS-DCF:diskConfig'])
 
-    @test.idempotent_id('693d16f3-556c-489a-8bac-3d0ca2490bad')
+    @decorators.idempotent_id('693d16f3-556c-489a-8bac-3d0ca2490bad')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     def test_resize_server_from_auto_to_manual(self):
@@ -116,7 +116,7 @@
         server = self.client.show_server(server['id'])['server']
         self.assertEqual('MANUAL', server['OS-DCF:diskConfig'])
 
-    @test.idempotent_id('5ef18867-358d-4de9-b3c9-94d4ba35742f')
+    @decorators.idempotent_id('5ef18867-358d-4de9-b3c9-94d4ba35742f')
     def test_update_server_from_auto_to_manual(self):
         # A server should be updated from auto to manual disk config
         server = self.create_test_server(wait_until='ACTIVE')
diff --git a/tempest/api/compute/servers/test_instance_actions.py b/tempest/api/compute/servers/test_instance_actions.py
index e50881f..b916a42 100644
--- a/tempest/api/compute/servers/test_instance_actions.py
+++ b/tempest/api/compute/servers/test_instance_actions.py
@@ -15,7 +15,7 @@
 
 from tempest.api.compute import base
 from tempest.common import waiters
-from tempest import test
+from tempest.lib import decorators
 
 
 class InstanceActionsTestJSON(base.BaseV2ComputeTest):
@@ -31,7 +31,7 @@
         cls.server = cls.create_test_server(wait_until='ACTIVE')
         cls.request_id = cls.server.response['x-compute-request-id']
 
-    @test.idempotent_id('77ca5cc5-9990-45e0-ab98-1de8fead201a')
+    @decorators.idempotent_id('77ca5cc5-9990-45e0-ab98-1de8fead201a')
     def test_list_instance_actions(self):
         # List actions of the provided server
         self.client.reboot_server(self.server['id'], type='HARD')
@@ -44,7 +44,7 @@
         self.assertEqual(sorted([i['action'] for i in body]),
                          ['create', 'reboot'])
 
-    @test.idempotent_id('aacc71ca-1d70-4aa5-bbf6-0ff71470e43c')
+    @decorators.idempotent_id('aacc71ca-1d70-4aa5-bbf6-0ff71470e43c')
     def test_get_instance_action(self):
         # Get the action details of the provided server
         body = self.client.show_instance_action(
@@ -63,7 +63,7 @@
         super(InstanceActionsV221TestJSON, cls).setup_clients()
         cls.client = cls.servers_client
 
-    @test.idempotent_id('0a0f85d4-10fa-41f6-bf80-a54fb4aa2ae1')
+    @decorators.idempotent_id('0a0f85d4-10fa-41f6-bf80-a54fb4aa2ae1')
     def test_get_list_deleted_instance_actions(self):
 
         # List actions of the deleted server
diff --git a/tempest/api/compute/servers/test_instance_actions_negative.py b/tempest/api/compute/servers/test_instance_actions_negative.py
index 33fed08..512bd1e 100644
--- a/tempest/api/compute/servers/test_instance_actions_negative.py
+++ b/tempest/api/compute/servers/test_instance_actions_negative.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
+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
 
@@ -32,7 +33,7 @@
         cls.server = cls.create_test_server(wait_until='ACTIVE')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('67e1fce6-7ec2-45c6-92d4-0a8f1a632910')
+    @decorators.idempotent_id('67e1fce6-7ec2-45c6-92d4-0a8f1a632910')
     def test_list_instance_actions_non_existent_server(self):
         # List actions of the non-existent server id
         non_existent_server_id = data_utils.rand_uuid()
@@ -41,7 +42,7 @@
                           non_existent_server_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0269f40a-6f18-456c-b336-c03623c897f1')
+    @decorators.idempotent_id('0269f40a-6f18-456c-b336-c03623c897f1')
     def test_get_instance_action_invalid_request(self):
         # Get the action details of the provided server with invalid request
         self.assertRaises(lib_exc.NotFound, self.client.show_instance_action,
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 611d5a2..1ad153a 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -12,14 +12,17 @@
 #    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 testtools
 
 from tempest.api.compute import base
 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.utils import data_utils
 from tempest.lib import decorators
-from tempest.lib import exceptions as lib_exc
-from tempest import test
+
+
+CONF = config.CONF
 
 
 class ListServerFiltersTestJSON(base.BaseV2ComputeTest):
@@ -38,31 +41,6 @@
     def resource_setup(cls):
         super(ListServerFiltersTestJSON, cls).resource_setup()
 
-        # Check to see if the alternate image ref actually exists...
-        images_client = cls.compute_images_client
-        images = images_client.list_images()['images']
-
-        if cls.image_ref != cls.image_ref_alt and \
-            any([image for image in images
-                 if image['id'] == cls.image_ref_alt]):
-            cls.multiple_images = True
-        else:
-            cls.image_ref_alt = cls.image_ref
-
-        # Do some sanity checks here. If one of the images does
-        # not exist, fail early since the tests won't work...
-        try:
-            cls.compute_images_client.show_image(cls.image_ref)
-        except lib_exc.NotFound:
-            raise RuntimeError("Image %s (image_ref) was not found!" %
-                               cls.image_ref)
-
-        try:
-            cls.compute_images_client.show_image(cls.image_ref_alt)
-        except lib_exc.NotFound:
-            raise RuntimeError("Image %s (image_ref_alt) was not found!" %
-                               cls.image_ref_alt)
-
         network = cls.get_tenant_network()
         if network:
             cls.fixed_network_name = network.get('name')
@@ -70,22 +48,28 @@
             cls.fixed_network_name = None
         network_kwargs = fixed_network.set_networks_kwarg(network)
         cls.s1_name = data_utils.rand_name(cls.__name__ + '-instance')
-        cls.s1 = cls.create_test_server(name=cls.s1_name,
-                                        wait_until='ACTIVE',
-                                        **network_kwargs)
+        cls.s1 = cls.create_test_server(name=cls.s1_name, **network_kwargs)
 
         cls.s2_name = data_utils.rand_name(cls.__name__ + '-instance')
-        cls.s2 = cls.create_test_server(name=cls.s2_name,
-                                        image_id=cls.image_ref_alt,
-                                        wait_until='ACTIVE')
+        # If image_ref_alt is "" or None then we still want to boot a server
+        # but we rely on `testtools.skipUnless` decorator to actually skip
+        # the irrelevant tests.
+        cls.s2 = cls.create_test_server(
+            name=cls.s2_name, image_id=cls.image_ref_alt or cls.image_ref)
 
         cls.s3_name = data_utils.rand_name(cls.__name__ + '-instance')
         cls.s3 = cls.create_test_server(name=cls.s3_name,
                                         flavor=cls.flavor_ref_alt,
                                         wait_until='ACTIVE')
 
-    @test.idempotent_id('05e8a8e7-9659-459a-989d-92c2f501f4ba')
-    @decorators.skip_unless_attr('multiple_images', 'Only one image found')
+        waiters.wait_for_server_status(cls.client, cls.s1['id'],
+                                       'ACTIVE')
+        waiters.wait_for_server_status(cls.client, cls.s2['id'],
+                                       'ACTIVE')
+
+    @decorators.idempotent_id('05e8a8e7-9659-459a-989d-92c2f501f4ba')
+    @testtools.skipUnless(CONF.compute.image_ref != CONF.compute.image_ref_alt,
+                          "Need distinct images to run this test")
     def test_list_servers_filter_by_image(self):
         # Filter the list of servers by image
         params = {'image': self.image_ref}
@@ -96,7 +80,7 @@
         self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
 
-    @test.idempotent_id('573637f5-7325-47bb-9144-3476d0416908')
+    @decorators.idempotent_id('573637f5-7325-47bb-9144-3476d0416908')
     def test_list_servers_filter_by_flavor(self):
         # Filter the list of servers by flavor
         params = {'flavor': self.flavor_ref_alt}
@@ -107,7 +91,7 @@
         self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
 
-    @test.idempotent_id('9b067a7b-7fee-4f6a-b29c-be43fe18fc5a')
+    @decorators.idempotent_id('9b067a7b-7fee-4f6a-b29c-be43fe18fc5a')
     def test_list_servers_filter_by_server_name(self):
         # Filter the list of servers by server name
         params = {'name': self.s1_name}
@@ -118,7 +102,7 @@
         self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
-    @test.idempotent_id('ca78e20e-fddb-4ce6-b7f7-bcbf8605e66e')
+    @decorators.idempotent_id('ca78e20e-fddb-4ce6-b7f7-bcbf8605e66e')
     def test_list_servers_filter_by_active_status(self):
         # Filter the list of servers by server active status
         params = {'status': 'active'}
@@ -129,7 +113,7 @@
         self.assertIn(self.s2['id'], map(lambda x: x['id'], servers))
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
 
-    @test.idempotent_id('451dbbb2-f330-4a9f-b0e1-5f5d2cb0f34c')
+    @decorators.idempotent_id('451dbbb2-f330-4a9f-b0e1-5f5d2cb0f34c')
     def test_list_servers_filter_by_shutoff_status(self):
         # Filter the list of servers by server shutoff status
         params = {'status': 'shutoff'}
@@ -146,21 +130,21 @@
         self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
         self.assertNotIn(self.s3['id'], map(lambda x: x['id'], servers))
 
-    @test.idempotent_id('614cdfc1-d557-4bac-915b-3e67b48eee76')
+    @decorators.idempotent_id('614cdfc1-d557-4bac-915b-3e67b48eee76')
     def test_list_servers_filter_by_limit(self):
         # Verify only the expected number of servers are returned
         params = {'limit': 1}
         servers = self.client.list_servers(**params)
         self.assertEqual(1, len([x for x in servers['servers'] if 'id' in x]))
 
-    @test.idempotent_id('b1495414-2d93-414c-8019-849afe8d319e')
+    @decorators.idempotent_id('b1495414-2d93-414c-8019-849afe8d319e')
     def test_list_servers_filter_by_zero_limit(self):
         # Verify only the expected number of servers are returned
         params = {'limit': 0}
         servers = self.client.list_servers(**params)
         self.assertEqual(0, len(servers['servers']))
 
-    @test.idempotent_id('37791bbd-90c0-4de0-831e-5f38cba9c6b3')
+    @decorators.idempotent_id('37791bbd-90c0-4de0-831e-5f38cba9c6b3')
     def test_list_servers_filter_by_exceed_limit(self):
         # Verify only the expected number of servers are returned
         params = {'limit': 100000}
@@ -169,8 +153,9 @@
         self.assertEqual(len([x for x in all_servers['servers'] if 'id' in x]),
                          len([x for x in servers['servers'] if 'id' in x]))
 
-    @test.idempotent_id('b3304c3b-97df-46d2-8cd3-e2b6659724e7')
-    @decorators.skip_unless_attr('multiple_images', 'Only one image found')
+    @decorators.idempotent_id('b3304c3b-97df-46d2-8cd3-e2b6659724e7')
+    @testtools.skipUnless(CONF.compute.image_ref != CONF.compute.image_ref_alt,
+                          "Need distinct images to run this test")
     def test_list_servers_detailed_filter_by_image(self):
         # Filter the detailed list of servers by image
         params = {'image': self.image_ref}
@@ -181,7 +166,7 @@
         self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
 
-    @test.idempotent_id('80c574cc-0925-44ba-8602-299028357dd9')
+    @decorators.idempotent_id('80c574cc-0925-44ba-8602-299028357dd9')
     def test_list_servers_detailed_filter_by_flavor(self):
         # Filter the detailed list of servers by flavor
         params = {'flavor': self.flavor_ref_alt}
@@ -192,7 +177,7 @@
         self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
 
-    @test.idempotent_id('f9eb2b70-735f-416c-b260-9914ac6181e4')
+    @decorators.idempotent_id('f9eb2b70-735f-416c-b260-9914ac6181e4')
     def test_list_servers_detailed_filter_by_server_name(self):
         # Filter the detailed list of servers by server name
         params = {'name': self.s1_name}
@@ -203,7 +188,7 @@
         self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
-    @test.idempotent_id('de2612ab-b7dd-4044-b0b1-d2539601911f')
+    @decorators.idempotent_id('de2612ab-b7dd-4044-b0b1-d2539601911f')
     def test_list_servers_detailed_filter_by_server_status(self):
         # Filter the detailed list of servers by server status
         params = {'status': 'active'}
@@ -217,7 +202,7 @@
         self.assertEqual(['ACTIVE'] * 3, [x['status'] for x in servers
                                           if x['id'] in test_ids])
 
-    @test.idempotent_id('e9f624ee-92af-4562-8bec-437945a18dcb')
+    @decorators.idempotent_id('e9f624ee-92af-4562-8bec-437945a18dcb')
     def test_list_servers_filtered_by_name_wildcard(self):
         # List all servers that contains '-instance' in name
         params = {'name': '-instance'}
@@ -239,7 +224,7 @@
         self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
-    @test.idempotent_id('24a89b0c-0d55-4a28-847f-45075f19b27b')
+    @decorators.idempotent_id('24a89b0c-0d55-4a28-847f-45075f19b27b')
     def test_list_servers_filtered_by_name_regex(self):
         # list of regex that should match s1, s2 and s3
         regexes = ['^.*\-instance\-[0-9]+$', '^.*\-instance\-.*$']
@@ -263,26 +248,44 @@
         self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
-    @test.idempotent_id('43a1242e-7b31-48d1-88f2-3f72aa9f2077')
+    @decorators.idempotent_id('43a1242e-7b31-48d1-88f2-3f72aa9f2077')
     def test_list_servers_filtered_by_ip(self):
         # Filter servers by ip
         # Here should be listed 1 server
         if not self.fixed_network_name:
             msg = 'fixed_network_name needs to be configured to run this test'
             raise self.skipException(msg)
+
+        # list servers filter by ip is something "regexp match", i.e,
+        # filter by "10.1.1.1" will return both "10.1.1.1" and "10.1.1.10".
+        # so here look for the longest server ip, and filter by that ip,
+        # so as to ensure only one server is returned.
+        ip_list = {}
         self.s1 = self.client.show_server(self.s1['id'])['server']
         # Get first ip address inspite of v4 or v6
-        addr_spec = self.s1['addresses'][self.fixed_network_name][0]
-        params = {'ip': addr_spec['addr']}
+        ip_addr = self.s1['addresses'][self.fixed_network_name][0]['addr']
+        ip_list[ip_addr] = self.s1['id']
+
+        self.s2 = self.client.show_server(self.s2['id'])['server']
+        ip_addr = self.s2['addresses'][self.fixed_network_name][0]['addr']
+        ip_list[ip_addr] = self.s2['id']
+
+        self.s3 = self.client.show_server(self.s3['id'])['server']
+        ip_addr = self.s3['addresses'][self.fixed_network_name][0]['addr']
+        ip_list[ip_addr] = self.s3['id']
+
+        longest_ip = max([[len(ip), ip] for ip in ip_list])[1]
+        params = {'ip': longest_ip}
         body = self.client.list_servers(**params)
         servers = body['servers']
 
-        self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
-        self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
-        self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
+        self.assertIn(ip_list[longest_ip], map(lambda x: x['id'], servers))
+        del ip_list[longest_ip]
+        for ip in ip_list:
+            self.assertNotIn(ip_list[ip], map(lambda x: x['id'], servers))
 
     @decorators.skip_because(bug="1540645")
-    @test.idempotent_id('a905e287-c35e-42f2-b132-d02b09f3654a')
+    @decorators.idempotent_id('a905e287-c35e-42f2-b132-d02b09f3654a')
     def test_list_servers_filtered_by_ip_regex(self):
         # Filter servers by regex ip
         # List all servers filtered by part of ip address.
@@ -312,7 +315,7 @@
                       "%s not found in %s, all servers %s" %
                       (self.s3_name, servers, all_servers))
 
-    @test.idempotent_id('67aec2d0-35fe-4503-9f92-f13272b867ed')
+    @decorators.idempotent_id('67aec2d0-35fe-4503-9f92-f13272b867ed')
     def test_list_servers_detailed_limit_results(self):
         # Verify only the expected number of detailed results are returned
         params = {'limit': 1}
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 3e408d2..2e3d2bb 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.compute import base
 from tempest.common import waiters
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -34,11 +35,8 @@
         # by the test methods in this class. These
         # servers are cleaned up automatically in the
         # tearDownClass method of the super-class.
-        cls.existing_fixtures = []
         cls.deleted_fixtures = []
-        for x in range(2):
-            srv = cls.create_test_server(wait_until='ACTIVE')
-            cls.existing_fixtures.append(srv)
+        cls.create_test_server(wait_until='ACTIVE', min_count=2)
 
         srv = cls.create_test_server(wait_until='ACTIVE')
         cls.client.delete_server(srv['id'])
@@ -46,7 +44,7 @@
         cls.deleted_fixtures.append(srv)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('24a26f1a-1ddc-4eea-b0d7-a90cc874ad8f')
+    @decorators.idempotent_id('24a26f1a-1ddc-4eea-b0d7-a90cc874ad8f')
     def test_list_servers_with_a_deleted_server(self):
         # Verify deleted servers do not show by default in list servers
         # List servers and verify server not returned
@@ -58,7 +56,7 @@
         self.assertEqual([], actual)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('ff01387d-c7ad-47b4-ae9e-64fa214638fe')
+    @decorators.idempotent_id('ff01387d-c7ad-47b4-ae9e-64fa214638fe')
     def test_list_servers_by_non_existing_image(self):
         # Listing servers for a non existing image returns empty list
         body = self.client.list_servers(image='non_existing_image')
@@ -66,7 +64,7 @@
         self.assertEqual([], servers)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5913660b-223b-44d4-a651-a0fbfd44ca75')
+    @decorators.idempotent_id('5913660b-223b-44d4-a651-a0fbfd44ca75')
     def test_list_servers_by_non_existing_flavor(self):
         # Listing servers by non existing flavor returns empty list
         body = self.client.list_servers(flavor='non_existing_flavor')
@@ -74,7 +72,7 @@
         self.assertEqual([], servers)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('e2c77c4a-000a-4af3-a0bd-629a328bde7c')
+    @decorators.idempotent_id('e2c77c4a-000a-4af3-a0bd-629a328bde7c')
     def test_list_servers_by_non_existing_server_name(self):
         # Listing servers for a non existent server name returns empty list
         body = self.client.list_servers(name='non_existing_server_name')
@@ -82,21 +80,21 @@
         self.assertEqual([], servers)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('fcdf192d-0f74-4d89-911f-1ec002b822c4')
+    @decorators.idempotent_id('fcdf192d-0f74-4d89-911f-1ec002b822c4')
     def test_list_servers_status_non_existing(self):
         # Return an empty list when invalid status is specified
         body = self.client.list_servers(status='non_existing_status')
         servers = body['servers']
         self.assertEqual([], servers)
 
-    @test.idempotent_id('12c80a9f-2dec-480e-882b-98ba15757659')
+    @decorators.idempotent_id('12c80a9f-2dec-480e-882b-98ba15757659')
     def test_list_servers_by_limits(self):
         # List servers by specifying limits
         body = self.client.list_servers(limit=1)
         self.assertEqual(1, len([x for x in body['servers'] if 'id' in x]))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d47c17fb-eebd-4287-8e95-f20a7e627b18')
+    @decorators.idempotent_id('d47c17fb-eebd-4287-8e95-f20a7e627b18')
     def test_list_servers_by_limits_greater_than_actual_count(self):
         # Gather the complete list of servers in the project for reference
         full_list = self.client.list_servers()['servers']
@@ -106,21 +104,21 @@
         self.assertEqual(len(full_list), len(body['servers']))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('679bc053-5e70-4514-9800-3dfab1a380a6')
+    @decorators.idempotent_id('679bc053-5e70-4514-9800-3dfab1a380a6')
     def test_list_servers_by_limits_pass_string(self):
         # Return an error if a string value is passed for limit
         self.assertRaises(lib_exc.BadRequest, self.client.list_servers,
                           limit='testing')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('62610dd9-4713-4ee0-8beb-fd2c1aa7f950')
+    @decorators.idempotent_id('62610dd9-4713-4ee0-8beb-fd2c1aa7f950')
     def test_list_servers_by_limits_pass_negative_value(self):
         # Return an error if a negative value for limit is passed
         self.assertRaises(lib_exc.BadRequest, self.client.list_servers,
                           limit=-1)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('87d12517-e20a-4c9c-97b6-dd1628d6d6c9')
+    @decorators.idempotent_id('87d12517-e20a-4c9c-97b6-dd1628d6d6c9')
     def test_list_servers_by_changes_since_invalid_date(self):
         # Return an error when invalid date format is passed
         params = {'changes-since': '2011/01/01'}
@@ -128,7 +126,7 @@
                           **params)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('74745ad8-b346-45b5-b9b8-509d7447fc1f')
+    @decorators.idempotent_id('74745ad8-b346-45b5-b9b8-509d7447fc1f')
     def test_list_servers_by_changes_since_future_date(self):
         # Return an empty list when a date in the future is passed
         changes_since = {'changes-since': '2051-01-01T12:34:00Z'}
@@ -136,7 +134,7 @@
         self.assertEqual(0, len(body['servers']))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('93055106-2d34-46fe-af68-d9ddbf7ee570')
+    @decorators.idempotent_id('93055106-2d34-46fe-af68-d9ddbf7ee570')
     def test_list_servers_detail_server_is_deleted(self):
         # Server details are not listed for a deleted server
         deleted_ids = [s['id'] for s in self.deleted_fixtures]
diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py
index 9fc30f9..7cbb513 100644
--- a/tempest/api/compute/servers/test_multiple_create.py
+++ b/tempest/api/compute/servers/test_multiple_create.py
@@ -14,22 +14,29 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import test
+from tempest.common import compute
+from tempest.lib import decorators
 
 
 class MultipleCreateTestJSON(base.BaseV2ComputeTest):
 
-    @test.idempotent_id('61e03386-89c3-449c-9bb1-a06f423fd9d1')
+    @decorators.idempotent_id('61e03386-89c3-449c-9bb1-a06f423fd9d1')
     def test_multiple_create(self):
-        body = self.create_test_server(wait_until='ACTIVE',
-                                       min_count=1,
-                                       max_count=2)
+        tenant_network = self.get_tenant_network()
+        body, servers = compute.create_test_server(
+            self.os,
+            wait_until='ACTIVE',
+            min_count=2,
+            tenant_network=tenant_network)
+        for server in servers:
+            self.addCleanup(self.servers_client.delete_server, server['id'])
         # NOTE(maurosr): do status response check and also make sure that
         # reservation_id is not in the response body when the request send
         # contains return_reservation_id=False
         self.assertNotIn('reservation_id', body)
+        self.assertEqual(2, len(servers))
 
-    @test.idempotent_id('864777fb-2f1e-44e3-b5b9-3eb6fa84f2f7')
+    @decorators.idempotent_id('864777fb-2f1e-44e3-b5b9-3eb6fa84f2f7')
     def test_multiple_create_with_reservation_return(self):
         body = self.create_test_server(wait_until='ACTIVE',
                                        min_count=1,
diff --git a/tempest/api/compute/servers/test_multiple_create_negative.py b/tempest/api/compute/servers/test_multiple_create_negative.py
index d9fb4ca..675cbee 100644
--- a/tempest/api/compute/servers/test_multiple_create_negative.py
+++ b/tempest/api/compute/servers/test_multiple_create_negative.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -21,35 +22,35 @@
 class MultipleCreateNegativeTestJSON(base.BaseV2ComputeTest):
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('daf29d8d-e928-4a01-9a8c-b129603f3fc0')
+    @decorators.idempotent_id('daf29d8d-e928-4a01-9a8c-b129603f3fc0')
     def test_min_count_less_than_one(self):
         invalid_min_count = 0
         self.assertRaises(lib_exc.BadRequest, self.create_test_server,
                           min_count=invalid_min_count)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('999aa722-d624-4423-b813-0d1ac9884d7a')
+    @decorators.idempotent_id('999aa722-d624-4423-b813-0d1ac9884d7a')
     def test_min_count_non_integer(self):
         invalid_min_count = 2.5
         self.assertRaises(lib_exc.BadRequest, self.create_test_server,
                           min_count=invalid_min_count)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a6f9c2ab-e060-4b82-b23c-4532cb9390ff')
+    @decorators.idempotent_id('a6f9c2ab-e060-4b82-b23c-4532cb9390ff')
     def test_max_count_less_than_one(self):
         invalid_max_count = 0
         self.assertRaises(lib_exc.BadRequest, self.create_test_server,
                           max_count=invalid_max_count)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9c5698d1-d7af-4c80-b971-9d403135eea2')
+    @decorators.idempotent_id('9c5698d1-d7af-4c80-b971-9d403135eea2')
     def test_max_count_non_integer(self):
         invalid_max_count = 2.5
         self.assertRaises(lib_exc.BadRequest, self.create_test_server,
                           max_count=invalid_max_count)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('476da616-f1ef-4271-a9b1-b9fc87727cdf')
+    @decorators.idempotent_id('476da616-f1ef-4271-a9b1-b9fc87727cdf')
     def test_max_count_less_than_min_count(self):
         min_count = 3
         max_count = 2
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
new file mode 100644
index 0000000..6354c57
--- /dev/null
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -0,0 +1,186 @@
+# Copyright 2016-2017 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 struct
+
+import six
+import urllib3
+
+from tempest.api.compute import base
+from tempest.common import compute
+from tempest import config
+from tempest.lib import decorators
+
+CONF = config.CONF
+
+if six.PY2:
+    ord_func = ord
+else:
+    ord_func = int
+
+
+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: ' + six.text_type(resp.status))
+        # Do some basic validation to make sure it is an expected HTML document
+        resp_data = resp.data.decode()
+        self.assertIn('<html>', resp_data,
+                      'Not a valid html document in the response.')
+        self.assertIn('</html>', 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.assertIn('noVNC', resp_data,
+                      'Not a valid noVNC javascript html document.')
+        self.assertIn('<script', 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 belong to the known supported RFB versions.
+        version = float("%d.%d" % (int(data[4:7], base=10),
+                                   int(data[8:11], base=10)))
+        # Add the max RFB versions supported
+        supported_versions = [3.3, 3.8]
+        self.assertIn(version, supported_versions,
+                      'Bad RFB Version: ' + str(version))
+        # Send our RFB version to the server
+        self._websocket.send_frame(data)
+        # Get the sever authentication type and make sure None is supported
+        data = self._websocket.receive_frame()
+        self.assertIsNotNone(data, 'Expected authentication type None.')
+        data_length = len(data)
+        if version == 3.3:
+            # For RFB 3.3: in the security handshake, rather than a two-way
+            # negotiation, the server decides the security type and sends a
+            # single word(4 bytes).
+            self.assertEqual(
+                data_length, 4, 'Expected authentication type None.')
+            self.assertIn(1, [ord_func(data[i]) for i in (0, 3)],
+                          'Expected authentication type None.')
+        else:
+            self.assertGreaterEqual(
+                len(data), 2, 'Expected authentication type None.')
+            self.assertIn(
+                1,
+                [ord_func(data[i + 1]) for i in range(ord_func(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_func(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(b'HTTP/1.1 101 Switching '
+                                                b'Protocols\r\n'),
+            'Did not get the expected 101 on the websockify call: '
+            + six.text_type(self._websocket.response))
+        self.assertTrue(
+            self._websocket.response.find(b'Server: WebSockify') > 0,
+            'Did not get the expected WebSocket HTTP Response.')
+
+    @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 = compute.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 = compute.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.")
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 0334eff..d810ff7 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -19,10 +19,10 @@
 
 from tempest.api.compute import base
 from tempest.common import compute
-from tempest.common.utils import data_utils
 from tempest.common.utils.linux import remote_client
 from tempest.common import waiters
 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
@@ -75,7 +75,7 @@
         super(ServerActionsTestJSON, cls).resource_setup()
         cls.server_id = cls.rebuild_server(None, validatable=True)
 
-    @test.idempotent_id('6158df09-4b82-4ab3-af6d-29cf36af858d')
+    @decorators.idempotent_id('6158df09-4b82-4ab3-af6d-29cf36af858d')
     @testtools.skipUnless(CONF.compute_feature_enabled.change_password,
                           'Change password not available.')
     def test_change_server_password(self):
@@ -134,13 +134,13 @@
                                '%s > %s' % (new_boot_time, boot_time))
 
     @test.attr(type='smoke')
-    @test.idempotent_id('2cb1baf6-ac8d-4429-bf0d-ba8a0ba53e32')
+    @decorators.idempotent_id('2cb1baf6-ac8d-4429-bf0d-ba8a0ba53e32')
     def test_reboot_server_hard(self):
         # The server should be power cycled
         self._test_reboot_server('HARD')
 
     @decorators.skip_because(bug="1014647")
-    @test.idempotent_id('4640e3ef-a5df-482e-95a1-ceeeb0faa84d')
+    @decorators.idempotent_id('4640e3ef-a5df-482e-95a1-ceeeb0faa84d')
     def test_reboot_server_soft(self):
         # The server should be signaled to reboot gracefully
         self._test_reboot_server('SOFT')
@@ -154,7 +154,7 @@
                .format(image_ref, rebuilt_server['image']['id']))
         self.assertEqual(image_ref, rebuilt_server['image']['id'], msg)
 
-    @test.idempotent_id('aaa6cdf3-55a7-461a-add9-1c8596b9a07c')
+    @decorators.idempotent_id('aaa6cdf3-55a7-461a-add9-1c8596b9a07c')
     def test_rebuild_server(self):
         # The server should be rebuilt using the provided image and data
         meta = {'rebuild': 'server'}
@@ -202,7 +202,7 @@
                 servers_client=self.client)
             linux_client.validate_authentication()
 
-    @test.idempotent_id('30449a88-5aff-4f9b-9866-6ee9b17f906d')
+    @decorators.idempotent_id('30449a88-5aff-4f9b-9866-6ee9b17f906d')
     def test_rebuild_server_in_stop_state(self):
         # The server in stop state  should be rebuilt using the provided
         # image and remain in SHUTOFF state
@@ -234,7 +234,7 @@
 
         self.client.start_server(self.server_id)
 
-    @test.idempotent_id('b68bd8d6-855d-4212-b59b-2e704044dace')
+    @decorators.idempotent_id('b68bd8d6-855d-4212-b59b-2e704044dace')
     @test.services('volume')
     def test_rebuild_server_with_volume_attached(self):
         # create a new volume and attach it to the server
@@ -281,19 +281,19 @@
             # NOTE(mriedem): tearDown requires the server to be started.
             self.client.start_server(self.server_id)
 
-    @test.idempotent_id('1499262a-9328-4eda-9068-db1ac57498d2')
+    @decorators.idempotent_id('1499262a-9328-4eda-9068-db1ac57498d2')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     def test_resize_server_confirm(self):
         self._test_resize_server_confirm(stop=False)
 
-    @test.idempotent_id('138b131d-66df-48c9-a171-64f45eb92962')
+    @decorators.idempotent_id('138b131d-66df-48c9-a171-64f45eb92962')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     def test_resize_server_confirm_from_stopped(self):
         self._test_resize_server_confirm(stop=True)
 
-    @test.idempotent_id('c03aab19-adb1-44f5-917d-c419577e9e68')
+    @decorators.idempotent_id('c03aab19-adb1-44f5-917d-c419577e9e68')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     def test_resize_server_revert(self):
@@ -313,7 +313,7 @@
         server = self.client.show_server(self.server_id)['server']
         self.assertEqual(self.flavor_ref, server['flavor']['id'])
 
-    @test.idempotent_id('b963d4f1-94b3-4c40-9e97-7b583f46e470')
+    @decorators.idempotent_id('b963d4f1-94b3-4c40-9e97-7b583f46e470')
     @testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
                           'Snapshotting not available, backup not possible.')
     @test.services('image')
@@ -428,7 +428,7 @@
         lines = len(output.split('\n'))
         self.assertEqual(lines, 10)
 
-    @test.idempotent_id('4b8867e6-fffa-4d54-b1d1-6fdda57be2f3')
+    @decorators.idempotent_id('4b8867e6-fffa-4d54-b1d1-6fdda57be2f3')
     @testtools.skipUnless(CONF.compute_feature_enabled.console_output,
                           'Console output not supported.')
     def test_get_console_output(self):
@@ -444,7 +444,7 @@
         waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
         self.wait_for(self._get_output)
 
-    @test.idempotent_id('89104062-69d8-4b19-a71b-f47b7af093d7')
+    @decorators.idempotent_id('89104062-69d8-4b19-a71b-f47b7af093d7')
     @testtools.skipUnless(CONF.compute_feature_enabled.console_output,
                           'Console output not supported.')
     def test_get_console_output_with_unlimited_size(self):
@@ -462,7 +462,7 @@
 
         self.wait_for(_check_full_length_console_log)
 
-    @test.idempotent_id('5b65d4e7-4ecd-437c-83c0-d6b79d927568')
+    @decorators.idempotent_id('5b65d4e7-4ecd-437c-83c0-d6b79d927568')
     @testtools.skipUnless(CONF.compute_feature_enabled.console_output,
                           'Console output not supported.')
     def test_get_console_output_server_id_in_shutoff_status(self):
@@ -471,7 +471,7 @@
 
         # NOTE: SHUTOFF is irregular status. To avoid test instability,
         #       one server is created only for this test without using
-        #       the server that was created in setupClass.
+        #       the server that was created in setUpClass.
         server = self.create_test_server(wait_until='ACTIVE')
         temp_server_id = server['id']
 
@@ -479,7 +479,7 @@
         waiters.wait_for_server_status(self.client, temp_server_id, 'SHUTOFF')
         self.wait_for(self._get_output)
 
-    @test.idempotent_id('bd61a9fd-062f-4670-972b-2d6c3e3b9e73')
+    @decorators.idempotent_id('bd61a9fd-062f-4670-972b-2d6c3e3b9e73')
     @testtools.skipUnless(CONF.compute_feature_enabled.pause,
                           'Pause is not available.')
     def test_pause_unpause_server(self):
@@ -488,7 +488,7 @@
         self.client.unpause_server(self.server_id)
         waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
 
-    @test.idempotent_id('0d8ee21e-b749-462d-83da-b85b41c86c7f')
+    @decorators.idempotent_id('0d8ee21e-b749-462d-83da-b85b41c86c7f')
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
                           'Suspend is not available.')
     def test_suspend_resume_server(self):
@@ -498,7 +498,7 @@
         self.client.resume_server(self.server_id)
         waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
 
-    @test.idempotent_id('77eba8e0-036e-4635-944b-f7a8f3b78dc9')
+    @decorators.idempotent_id('77eba8e0-036e-4635-944b-f7a8f3b78dc9')
     @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
                           'Shelve is not available.')
     def test_shelve_unshelve_server(self):
@@ -515,14 +515,14 @@
         self.client.unshelve_server(self.server_id)
         waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
 
-    @test.idempotent_id('af8eafd4-38a7-4a4b-bdbc-75145a580560')
+    @decorators.idempotent_id('af8eafd4-38a7-4a4b-bdbc-75145a580560')
     def test_stop_start_server(self):
         self.client.stop_server(self.server_id)
         waiters.wait_for_server_status(self.client, self.server_id, 'SHUTOFF')
         self.client.start_server(self.server_id)
         waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
 
-    @test.idempotent_id('80a8094c-211e-440a-ab88-9e59d556c7ee')
+    @decorators.idempotent_id('80a8094c-211e-440a-ab88-9e59d556c7ee')
     def test_lock_unlock_server(self):
         # Lock the server,try server stop(exceptions throw),unlock it and retry
         self.client.lock_server(self.server_id)
@@ -545,7 +545,7 @@
         self.assertNotEqual('None', parsed_url.hostname)
         self.assertIn(parsed_url.scheme, valid_scheme)
 
-    @test.idempotent_id('c6bc11bf-592e-4015-9319-1c98dc64daf5')
+    @decorators.idempotent_id('c6bc11bf-592e-4015-9319-1c98dc64daf5')
     @testtools.skipUnless(CONF.compute_feature_enabled.vnc_console,
                           'VNC Console feature is disabled.')
     def test_get_vnc_console(self):
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index d31b6f8..cf4ed85 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -13,9 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import six
-
 from tempest.api.compute import base
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -39,7 +38,7 @@
         cls.server = cls.create_test_server(wait_until='ACTIVE')
 
     @test.attr(type='smoke')
-    @test.idempotent_id('6eb718c0-02d9-4d5e-acd1-4e0c269cef39')
+    @decorators.idempotent_id('6eb718c0-02d9-4d5e-acd1-4e0c269cef39')
     @test.services('network')
     def test_list_server_addresses(self):
         # All public and private addresses for
@@ -50,14 +49,14 @@
         # We do not know the exact network configuration, but an instance
         # should at least have a single public or private address
         self.assertGreaterEqual(len(addresses), 1)
-        for network_name, network_addresses in six.iteritems(addresses):
+        for network_addresses in addresses.values():
             self.assertGreaterEqual(len(network_addresses), 1)
             for address in network_addresses:
                 self.assertTrue(address['addr'])
                 self.assertTrue(address['version'])
 
     @test.attr(type='smoke')
-    @test.idempotent_id('87bbc374-5538-4f64-b673-2b0e4443cc30')
+    @decorators.idempotent_id('87bbc374-5538-4f64-b673-2b0e4443cc30')
     @test.services('network')
     def test_list_server_addresses_by_network(self):
         # Providing a network type should filter
diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py
index b4753e1..1884e4f 100644
--- a/tempest/api/compute/servers/test_server_addresses_negative.py
+++ b/tempest/api/compute/servers/test_server_addresses_negative.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -36,7 +37,7 @@
         cls.server = cls.create_test_server(wait_until='ACTIVE')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('02c3f645-2d2e-4417-8525-68c0407d001b')
+    @decorators.idempotent_id('02c3f645-2d2e-4417-8525-68c0407d001b')
     @test.services('network')
     def test_list_server_addresses_invalid_server_id(self):
         # List addresses request should fail if server id not in system
@@ -44,7 +45,7 @@
                           '999')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a2ab5144-78c0-4942-a0ed-cc8edccfd9ba')
+    @decorators.idempotent_id('a2ab5144-78c0-4942-a0ed-cc8edccfd9ba')
     @test.services('network')
     def test_list_server_addresses_by_network_neg(self):
         # List addresses by network should fail if network name not valid
diff --git a/tempest/api/compute/servers/test_server_group.py b/tempest/api/compute/servers/test_server_group.py
index bc49e7b..69d7897 100644
--- a/tempest/api/compute/servers/test_server_group.py
+++ b/tempest/api/compute/servers/test_server_group.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -67,23 +68,23 @@
         server_group = self._create_server_group(name, policy)
         self._delete_server_group(server_group)
 
-    @test.idempotent_id('5dc57eda-35b7-4af7-9e5f-3c2be3d2d68b')
+    @decorators.idempotent_id('5dc57eda-35b7-4af7-9e5f-3c2be3d2d68b')
     def test_create_delete_server_group_with_affinity_policy(self):
         # Create and Delete the server-group with affinity policy
         self._create_delete_server_group(self.policy)
 
-    @test.idempotent_id('3645a102-372f-4140-afad-13698d850d23')
+    @decorators.idempotent_id('3645a102-372f-4140-afad-13698d850d23')
     def test_create_delete_server_group_with_anti_affinity_policy(self):
         # Create and Delete the server-group with anti-affinity policy
         policy = ['anti-affinity']
         self._create_delete_server_group(policy)
 
-    @test.idempotent_id('154dc5a4-a2fe-44b5-b99e-f15806a4a113')
+    @decorators.idempotent_id('154dc5a4-a2fe-44b5-b99e-f15806a4a113')
     def test_create_delete_multiple_server_groups_with_same_name_policy(self):
         # Create and Delete the server-groups with same name and same policy
         server_groups = []
         server_group_name = data_utils.rand_name('server-group')
-        for i in range(0, 2):
+        for _ in range(0, 2):
             server_groups.append(self._create_server_group(server_group_name,
                                                            self.policy))
         for key in ['name', 'policies']:
@@ -93,14 +94,14 @@
         for i in range(0, 2):
             self._delete_server_group(server_groups[i])
 
-    @test.idempotent_id('b3545034-dd78-48f0-bdc2-a4adfa6d0ead')
+    @decorators.idempotent_id('b3545034-dd78-48f0-bdc2-a4adfa6d0ead')
     def test_show_server_group(self):
         # Get the server-group
         body = self.client.show_server_group(
             self.created_server_group['id'])['server_group']
         self.assertEqual(self.created_server_group, body)
 
-    @test.idempotent_id('d4874179-27b4-4d7d-80e4-6c560cdfe321')
+    @decorators.idempotent_id('d4874179-27b4-4d7d-80e4-6c560cdfe321')
     def test_list_server_groups(self):
         # List the server-group
         body = self.client.list_server_groups()['server_groups']
diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py
index 847b7a1..f77e7d3 100644
--- a/tempest/api/compute/servers/test_server_metadata.py
+++ b/tempest/api/compute/servers/test_server_metadata.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class ServerMetadataTestJSON(base.BaseV2ComputeTest):
@@ -34,7 +34,7 @@
         meta = {'key1': 'value1', 'key2': 'value2'}
         self.client.set_server_metadata(self.server['id'], meta)['metadata']
 
-    @test.idempotent_id('479da087-92b3-4dcf-aeb3-fd293b2d14ce')
+    @decorators.idempotent_id('479da087-92b3-4dcf-aeb3-fd293b2d14ce')
     def test_list_server_metadata(self):
         # All metadata key/value pairs for a server should be returned
         resp_metadata = (self.client.list_server_metadata(self.server['id'])
@@ -44,7 +44,7 @@
         expected = {'key1': 'value1', 'key2': 'value2'}
         self.assertEqual(expected, resp_metadata)
 
-    @test.idempotent_id('211021f6-21de-4657-a68f-908878cfe251')
+    @decorators.idempotent_id('211021f6-21de-4657-a68f-908878cfe251')
     def test_set_server_metadata(self):
         # The server's metadata should be replaced with the provided values
         # Create a new set of metadata for the server
@@ -58,7 +58,7 @@
                          ['metadata'])
         self.assertEqual(resp_metadata, req_metadata)
 
-    @test.idempotent_id('344d981e-0c33-4997-8a5d-6c1d803e4134')
+    @decorators.idempotent_id('344d981e-0c33-4997-8a5d-6c1d803e4134')
     def test_update_server_metadata(self):
         # The server's metadata values should be updated to the
         # provided values
@@ -71,7 +71,7 @@
         expected = {'key1': 'alt1', 'key2': 'value2', 'key3': 'value3'}
         self.assertEqual(expected, resp_metadata)
 
-    @test.idempotent_id('0f58d402-e34a-481d-8af8-b392b17426d9')
+    @decorators.idempotent_id('0f58d402-e34a-481d-8af8-b392b17426d9')
     def test_update_metadata_empty_body(self):
         # The original metadata should not be lost if empty metadata body is
         # passed
@@ -82,14 +82,14 @@
         expected = {'key1': 'value1', 'key2': 'value2'}
         self.assertEqual(expected, resp_metadata)
 
-    @test.idempotent_id('3043c57d-7e0e-49a6-9a96-ad569c265e6a')
+    @decorators.idempotent_id('3043c57d-7e0e-49a6-9a96-ad569c265e6a')
     def test_get_server_metadata_item(self):
         # The value for a specific metadata key should be returned
         meta = self.client.show_server_metadata_item(self.server['id'],
                                                      'key2')['meta']
         self.assertEqual('value2', meta['key2'])
 
-    @test.idempotent_id('58c02d4f-5c67-40be-8744-d3fa5982eb1c')
+    @decorators.idempotent_id('58c02d4f-5c67-40be-8744-d3fa5982eb1c')
     def test_set_server_metadata_item(self):
         # The item's value should be updated to the provided value
         # Update the metadata value
@@ -102,7 +102,7 @@
         expected = {'key1': 'value1', 'key2': 'value2', 'nova': 'alt'}
         self.assertEqual(expected, resp_metadata)
 
-    @test.idempotent_id('127642d6-4c7b-4486-b7cd-07265a378658')
+    @decorators.idempotent_id('127642d6-4c7b-4486-b7cd-07265a378658')
     def test_delete_server_metadata_item(self):
         # The metadata value/key pair should be deleted from the server
         self.client.delete_server_metadata_item(self.server['id'], 'key1')
diff --git a/tempest/api/compute/servers/test_server_metadata_negative.py b/tempest/api/compute/servers/test_server_metadata_negative.py
index 62b8962..22ce37d 100644
--- a/tempest/api/compute/servers/test_server_metadata_negative.py
+++ b/tempest/api/compute/servers/test_server_metadata_negative.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
+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 @@
         cls.server = cls.create_test_server(metadata={}, wait_until='ACTIVE')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('fe114a8f-3a57-4eff-9ee2-4e14628df049')
+    @decorators.idempotent_id('fe114a8f-3a57-4eff-9ee2-4e14628df049')
     def test_server_create_metadata_key_too_long(self):
         # Attempt to start a server with a meta-data key that is > 255
         # characters
@@ -49,7 +50,7 @@
         # no teardown - all creates should fail
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('92431555-4d8b-467c-b95b-b17daa5e57ff')
+    @decorators.idempotent_id('92431555-4d8b-467c-b95b-b17daa5e57ff')
     def test_create_server_metadata_blank_key(self):
         # Blank key should trigger an error.
         meta = {'': 'data1'}
@@ -58,7 +59,7 @@
                           metadata=meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('4d9cd7a3-2010-4b41-b8fe-3bbf0b169466')
+    @decorators.idempotent_id('4d9cd7a3-2010-4b41-b8fe-3bbf0b169466')
     def test_server_metadata_non_existent_server(self):
         # GET on a non-existent server should not succeed
         non_existent_server_id = data_utils.rand_uuid()
@@ -68,7 +69,7 @@
                           'test2')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f408e78e-3066-4097-9299-3b0182da812e')
+    @decorators.idempotent_id('f408e78e-3066-4097-9299-3b0182da812e')
     def test_list_server_metadata_non_existent_server(self):
         # List metadata on a non-existent server should not succeed
         non_existent_server_id = data_utils.rand_uuid()
@@ -77,7 +78,7 @@
                           non_existent_server_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0025fbd6-a4ba-4cde-b8c2-96805dcfdabc')
+    @decorators.idempotent_id('0025fbd6-a4ba-4cde-b8c2-96805dcfdabc')
     def test_wrong_key_passed_in_body(self):
         # Raise BadRequest if key in uri does not match
         # the key passed in body.
@@ -87,7 +88,7 @@
                           self.server['id'], 'key', meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0df38c2a-3d4e-4db5-98d8-d4d9fa843a12')
+    @decorators.idempotent_id('0df38c2a-3d4e-4db5-98d8-d4d9fa843a12')
     def test_set_metadata_non_existent_server(self):
         # Set metadata on a non-existent server should not succeed
         non_existent_server_id = data_utils.rand_uuid()
@@ -98,7 +99,7 @@
                           meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('904b13dc-0ef2-4e4c-91cd-3b4a0f2f49d8')
+    @decorators.idempotent_id('904b13dc-0ef2-4e4c-91cd-3b4a0f2f49d8')
     def test_update_metadata_non_existent_server(self):
         # An update should not happen for a non-existent server
         non_existent_server_id = data_utils.rand_uuid()
@@ -109,7 +110,7 @@
                           meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a452f38c-05c2-4b47-bd44-a4f0bf5a5e48')
+    @decorators.idempotent_id('a452f38c-05c2-4b47-bd44-a4f0bf5a5e48')
     def test_update_metadata_with_blank_key(self):
         # Blank key should trigger an error
         meta = {'': 'data1'}
@@ -118,7 +119,7 @@
                           self.server['id'], meta=meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('6bbd88e1-f8b3-424d-ba10-ae21c45ada8d')
+    @decorators.idempotent_id('6bbd88e1-f8b3-424d-ba10-ae21c45ada8d')
     def test_delete_metadata_non_existent_server(self):
         # Should not be able to delete metadata item from a non-existent server
         non_existent_server_id = data_utils.rand_uuid()
@@ -128,7 +129,7 @@
                           'd')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d8c0a210-a5c3-4664-be04-69d96746b547')
+    @decorators.idempotent_id('d8c0a210-a5c3-4664-be04-69d96746b547')
     def test_metadata_items_limit(self):
         # A 403 Forbidden or 413 Overlimit (old behaviour) exception
         # will be raised while exceeding metadata items limit for
@@ -154,7 +155,7 @@
                           self.server['id'], req_metadata)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('96100343-7fa9-40d8-80fa-d29ef588ce1c')
+    @decorators.idempotent_id('96100343-7fa9-40d8-80fa-d29ef588ce1c')
     def test_set_server_metadata_blank_key(self):
         # Raise a bad request error for blank key.
         # set_server_metadata will replace all metadata with new value
@@ -164,7 +165,7 @@
                           self.server['id'], meta=meta)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('64a91aee-9723-4863-be44-4c9d9f1e7d0e')
+    @decorators.idempotent_id('64a91aee-9723-4863-be44-4c9d9f1e7d0e')
     def test_set_server_metadata_missing_metadata(self):
         # Raise a bad request error for a missing metadata field
         # set_server_metadata will replace all metadata with new value
diff --git a/tempest/api/compute/servers/test_server_password.py b/tempest/api/compute/servers/test_server_password.py
index 9b41708..e7591a5 100644
--- a/tempest/api/compute/servers/test_server_password.py
+++ b/tempest/api/compute/servers/test_server_password.py
@@ -15,7 +15,7 @@
 
 
 from tempest.api.compute import base
-from tempest import test
+from tempest.lib import decorators
 
 
 class ServerPasswordTestJSON(base.BaseV2ComputeTest):
@@ -30,10 +30,10 @@
         super(ServerPasswordTestJSON, cls).resource_setup()
         cls.server = cls.create_test_server(wait_until="ACTIVE")
 
-    @test.idempotent_id('f83b582f-62a8-4f22-85b0-0dee50ff783a')
+    @decorators.idempotent_id('f83b582f-62a8-4f22-85b0-0dee50ff783a')
     def test_get_server_password(self):
         self.client.show_password(self.server['id'])
 
-    @test.idempotent_id('f8229e8b-b625-4493-800a-bde86ac611ea')
+    @decorators.idempotent_id('f8229e8b-b625-4493-800a-bde86ac611ea')
     def test_delete_server_password(self):
         self.client.delete_password(self.server['id'])
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index ab291b4..90b9da4 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -20,8 +20,8 @@
 from tempest.common import waiters
 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
 
@@ -50,7 +50,7 @@
         cls.client = cls.servers_client
         cls.user_client = cls.limits_client
 
-    @test.idempotent_id('3cfe87fd-115b-4a02-b942-7dc36a337fdf')
+    @decorators.idempotent_id('3cfe87fd-115b-4a02-b942-7dc36a337fdf')
     def test_create_server_with_personality(self):
         file_contents = 'This is a test file.'
         file_path = '/test.txt'
@@ -73,7 +73,7 @@
                              linux_client.exec_command(
                                  'sudo cat %s' % file_path))
 
-    @test.idempotent_id('128966d8-71fc-443c-8cab-08e24114ecc9')
+    @decorators.idempotent_id('128966d8-71fc-443c-8cab-08e24114ecc9')
     def test_rebuild_server_with_personality(self):
         server = self.create_test_server(wait_until='ACTIVE', validatable=True)
         server_id = server['id']
@@ -87,7 +87,7 @@
         self.assertEqual(self.image_ref_alt,
                          rebuilt_server['server']['image']['id'])
 
-    @test.idempotent_id('176cd8c9-b9e8-48ee-a480-180beab292bf')
+    @decorators.idempotent_id('176cd8c9-b9e8-48ee-a480-180beab292bf')
     def test_personality_files_exceed_limit(self):
         # Server creation should fail if greater than the maximum allowed
         # number of files are injected into the server.
@@ -97,7 +97,7 @@
         max_file_limit = limits['absolute']['maxPersonality']
         if max_file_limit == -1:
             raise self.skipException("No limit for personality files")
-        for i in range(0, int(max_file_limit) + 1):
+        for i in range(0, max_file_limit + 1):
             path = 'etc/test' + str(i) + '.txt'
             personality.append({'path': path,
                                 'contents': base64.encode_as_text(
@@ -107,7 +107,7 @@
         self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit),
                           self.create_test_server, personality=personality)
 
-    @test.idempotent_id('52f12ee8-5180-40cc-b417-31572ea3d555')
+    @decorators.idempotent_id('52f12ee8-5180-40cc-b417-31572ea3d555')
     def test_can_create_server_with_max_number_personality_files(self):
         # Server should be created successfully if maximum allowed number of
         # files is injected into the server during creation.
@@ -117,7 +117,7 @@
         if max_file_limit == -1:
             raise self.skipException("No limit for personality files")
         person = []
-        for i in range(0, int(max_file_limit)):
+        for i in range(0, max_file_limit):
             # NOTE(andreaf) The cirros disk image is blank before boot
             # so we can only inject safely to /
             path = '/test' + str(i) + '.txt'
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 9834d02..8760af6 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -13,11 +13,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -48,18 +50,16 @@
 
         # Security group creation
         cls.sg_name = data_utils.rand_name('sg')
-        cls.sg_desc = data_utils.rand_name('sg-desc')
+        sg_desc = data_utils.rand_name('sg-desc')
         cls.sg = cls.security_groups_client.create_security_group(
-            name=cls.sg_name, description=cls.sg_desc)['security_group']
+            name=cls.sg_name, description=sg_desc)['security_group']
         cls.sg_id = cls.sg['id']
 
         cls.password = data_utils.rand_password()
         # Server for positive tests
         server = cls.create_test_server(adminPass=cls.password,
-                                        wait_until='BUILD')
+                                        wait_until='ACTIVE')
         cls.server_id = server['id']
-        waiters.wait_for_server_status(cls.servers_client, cls.server_id,
-                                       'ACTIVE')
 
     @classmethod
     def resource_cleanup(cls):
@@ -74,7 +74,7 @@
         waiters.wait_for_server_status(self.servers_client, server_id,
                                        'ACTIVE')
 
-    @test.idempotent_id('fd032140-714c-42e4-a8fd-adcd8df06be6')
+    @decorators.idempotent_id('fd032140-714c-42e4-a8fd-adcd8df06be6')
     def test_rescue_unrescue_instance(self):
         self.servers_client.rescue_server(
             self.server_id, adminPass=self.password)
@@ -84,7 +84,9 @@
         waiters.wait_for_server_status(self.servers_client, self.server_id,
                                        'ACTIVE')
 
-    @test.idempotent_id('4842e0cf-e87d-4d9d-b61f-f4791da3cacc')
+    @decorators.idempotent_id('4842e0cf-e87d-4d9d-b61f-f4791da3cacc')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     def test_rescued_vm_associate_dissociate_floating_ip(self):
         # Rescue the server
         self.servers_client.rescue_server(
@@ -102,7 +104,7 @@
         client.disassociate_floating_ip_from_server(self.floating_ip,
                                                     self.server_id)
 
-    @test.idempotent_id('affca41f-7195-492d-8065-e09eee245404')
+    @decorators.idempotent_id('affca41f-7195-492d-8065-e09eee245404')
     def test_rescued_vm_add_remove_security_group(self):
         # Rescue the server
         self.servers_client.rescue_server(
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index 41b648c..565d76d 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -16,9 +16,10 @@
 import testtools
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 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
 
@@ -70,7 +71,7 @@
         waiters.wait_for_server_status(self.servers_client,
                                        server_id, 'ACTIVE')
 
-    @test.idempotent_id('cc3a883f-43c0-4fb6-a9bb-5579d64984ed')
+    @decorators.idempotent_id('cc3a883f-43c0-4fb6-a9bb-5579d64984ed')
     @testtools.skipUnless(CONF.compute_feature_enabled.pause,
                           'Pause is not available.')
     @test.attr(type=['negative'])
@@ -85,13 +86,13 @@
                           self.server_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('db22b618-f157-4566-a317-1b6d467a8094')
+    @decorators.idempotent_id('db22b618-f157-4566-a317-1b6d467a8094')
     def test_rescued_vm_reboot(self):
         self.assertRaises(lib_exc.Conflict, self.servers_client.reboot_server,
                           self.rescue_id, type='HARD')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('6dfc0a55-3a77-4564-a144-1587b7971dde')
+    @decorators.idempotent_id('6dfc0a55-3a77-4564-a144-1587b7971dde')
     def test_rescue_non_existent_server(self):
         # Rescue a non-existing server
         non_existent_server = data_utils.rand_uuid()
@@ -100,14 +101,14 @@
                           non_existent_server)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('70cdb8a1-89f8-437d-9448-8844fd82bf46')
+    @decorators.idempotent_id('70cdb8a1-89f8-437d-9448-8844fd82bf46')
     def test_rescued_vm_rebuild(self):
         self.assertRaises(lib_exc.Conflict,
                           self.servers_client.rebuild_server,
                           self.rescue_id,
                           self.image_ref_alt)
 
-    @test.idempotent_id('d0ccac79-0091-4cf4-a1ce-26162d0cc55f')
+    @decorators.idempotent_id('d0ccac79-0091-4cf4-a1ce-26162d0cc55f')
     @test.services('volume')
     @test.attr(type=['negative'])
     def test_rescued_vm_attach_volume(self):
@@ -127,7 +128,7 @@
                           volumeId=volume['id'],
                           device='/dev/%s' % self.device)
 
-    @test.idempotent_id('f56e465b-fe10-48bf-b75d-646cda3a8bc9')
+    @decorators.idempotent_id('f56e465b-fe10-48bf-b75d-646cda3a8bc9')
     @test.services('volume')
     @test.attr(type=['negative'])
     def test_rescued_vm_detach_volume(self):
diff --git a/tempest/api/compute/servers/test_server_tags.py b/tempest/api/compute/servers/test_server_tags.py
new file mode 100644
index 0000000..0370215
--- /dev/null
+++ b/tempest/api/compute/servers/test_server_tags.py
@@ -0,0 +1,108 @@
+# Copyright 2017 AT&T Corp.
+# 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 six
+
+from tempest.api.compute import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest import test
+
+
+class ServerTagsTestJSON(base.BaseV2ComputeTest):
+
+    min_microversion = '2.26'
+    max_microversion = 'latest'
+
+    @classmethod
+    def skip_checks(cls):
+        super(ServerTagsTestJSON, cls).skip_checks()
+        if not test.is_extension_enabled('os-server-tags', 'compute'):
+            msg = "os-server-tags extension is not enabled."
+            raise cls.skipException(msg)
+
+    @classmethod
+    def setup_clients(cls):
+        super(ServerTagsTestJSON, cls).setup_clients()
+        cls.client = cls.servers_client
+
+    @classmethod
+    def resource_setup(cls):
+        super(ServerTagsTestJSON, cls).resource_setup()
+        cls.server = cls.create_test_server(wait_until='ACTIVE')
+
+    def _update_server_tags(self, server_id, tags):
+        if not isinstance(tags, (list, tuple)):
+            tags = [tags]
+        for tag in tags:
+            self.client.update_tag(server_id, tag)
+        self.addCleanup(self.client.delete_all_tags, server_id)
+
+    @decorators.idempotent_id('8d95abe2-c658-4c42-9a44-c0258500306b')
+    def test_create_delete_tag(self):
+        # Check that no tags exist.
+        fetched_tags = self.client.list_tags(self.server['id'])['tags']
+        self.assertEmpty(fetched_tags)
+
+        # Add server tag to the server.
+        assigned_tag = data_utils.rand_name('tag')
+        self._update_server_tags(self.server['id'], assigned_tag)
+
+        # Check that added tag exists.
+        fetched_tags = self.client.list_tags(self.server['id'])['tags']
+        self.assertEqual([assigned_tag], fetched_tags)
+
+        # Remove assigned tag from server and check that it was removed.
+        self.client.delete_tag(self.server['id'], assigned_tag)
+        fetched_tags = self.client.list_tags(self.server['id'])['tags']
+        self.assertEmpty(fetched_tags)
+
+    @decorators.idempotent_id('a2c1af8c-127d-417d-974b-8115f7e3d831')
+    def test_update_all_tags(self):
+        # Add server tags to the server.
+        tags = [data_utils.rand_name('tag'), data_utils.rand_name('tag')]
+        self._update_server_tags(self.server['id'], tags)
+
+        # Replace tags with new tags and check that they are present.
+        new_tags = [data_utils.rand_name('tag'), data_utils.rand_name('tag')]
+        replaced_tags = self.client.update_all_tags(
+            self.server['id'], new_tags)['tags']
+        six.assertCountEqual(self, new_tags, replaced_tags)
+
+        # List the tags and check that the tags were replaced.
+        fetched_tags = self.client.list_tags(self.server['id'])['tags']
+        six.assertCountEqual(self, new_tags, fetched_tags)
+
+    @decorators.idempotent_id('a63b2a74-e918-4b7c-bcab-10c855f3a57e')
+    def test_delete_all_tags(self):
+        # Add server tags to the server.
+        assigned_tags = [data_utils.rand_name('tag'),
+                         data_utils.rand_name('tag')]
+        self._update_server_tags(self.server['id'], assigned_tags)
+
+        # Delete tags from the server and check that they were deleted.
+        self.client.delete_all_tags(self.server['id'])
+        fetched_tags = self.client.list_tags(self.server['id'])['tags']
+        self.assertEmpty(fetched_tags)
+
+    @decorators.idempotent_id('81279a66-61c3-4759-b830-a2dbe64cbe08')
+    def test_check_tag_existence(self):
+        # Add server tag to the server.
+        assigned_tag = data_utils.rand_name('tag')
+        self._update_server_tags(self.server['id'], assigned_tag)
+
+        # Check that added tag exists. Throws a 404 if not found, else a 204,
+        # which was already checked by the schema validation.
+        self.client.check_tag_existence(self.server['id'], assigned_tag)
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index 5aeba4e..11f236b 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -16,10 +16,10 @@
 import testtools
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -35,7 +35,7 @@
         self.clear_servers()
         super(ServersTestJSON, self).tearDown()
 
-    @test.idempotent_id('b92d5ec7-b1dd-44a2-87e4-45e888c46ef0')
+    @decorators.idempotent_id('b92d5ec7-b1dd-44a2-87e4-45e888c46ef0')
     @testtools.skipUnless(CONF.compute_feature_enabled.
                           enable_instance_password,
                           'Instance password not available.')
@@ -47,7 +47,7 @@
         # Verify the password is set correctly in the response
         self.assertEqual('testpassword', server['adminPass'])
 
-    @test.idempotent_id('8fea6be7-065e-47cf-89b8-496e6f96c699')
+    @decorators.idempotent_id('8fea6be7-065e-47cf-89b8-496e6f96c699')
     def test_create_with_existing_server_name(self):
         # Creating a server with a name that already exists is allowed
 
@@ -67,7 +67,7 @@
         name2 = server['name']
         self.assertEqual(name1, name2)
 
-    @test.idempotent_id('f9e15296-d7f9-4e62-b53f-a04e89160833')
+    @decorators.idempotent_id('f9e15296-d7f9-4e62-b53f-a04e89160833')
     def test_create_specify_keypair(self):
         # Specify a keypair while creating a server
 
@@ -94,7 +94,7 @@
         self.assertEqual(new_name, server['name'])
         return server
 
-    @test.idempotent_id('5e6ccff8-349d-4852-a8b3-055df7988dd2')
+    @decorators.idempotent_id('5e6ccff8-349d-4852-a8b3-055df7988dd2')
     def test_update_server_name(self):
         # The server name should be changed to the provided value
         server = self.create_test_server(wait_until='ACTIVE')
@@ -102,7 +102,7 @@
         prefix_name = u'\u00CD\u00F1st\u00E1\u00F1c\u00E9'
         self._update_server_name(server['id'], 'ACTIVE', prefix_name)
 
-    @test.idempotent_id('6ac19cb1-27a3-40ec-b350-810bdc04c08e')
+    @decorators.idempotent_id('6ac19cb1-27a3-40ec-b350-810bdc04c08e')
     def test_update_server_name_in_stop_state(self):
         # The server name should be changed to the provided value
         server = self.create_test_server(wait_until='ACTIVE')
@@ -115,7 +115,7 @@
                                                   prefix_name)
         self.assertNotIn('progress', updated_server)
 
-    @test.idempotent_id('89b90870-bc13-4b73-96af-f9d4f2b70077')
+    @decorators.idempotent_id('89b90870-bc13-4b73-96af-f9d4f2b70077')
     def test_update_access_server_address(self):
         # The server's access addresses should reflect the provided values
         server = self.create_test_server(wait_until='ACTIVE')
@@ -131,7 +131,7 @@
         self.assertEqual('1.1.1.1', server['accessIPv4'])
         self.assertEqual('::babe:202:202', server['accessIPv6'])
 
-    @test.idempotent_id('38fb1d02-c3c5-41de-91d3-9bc2025a75eb')
+    @decorators.idempotent_id('38fb1d02-c3c5-41de-91d3-9bc2025a75eb')
     def test_create_server_with_ipv6_addr_only(self):
         # Create a server without an IPv4 address(only IPv6 address).
         server = self.create_test_server(accessIPv6='2001:2001::3')
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 1b1b339..c6b3b40 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -19,9 +19,10 @@
 
 from tempest.api.compute import base
 from tempest.common import compute
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 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
 
@@ -54,7 +55,7 @@
         cls.server_id = server['id']
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('dbbfd247-c40c-449e-8f6c-d2aa7c7da7cf')
+    @decorators.idempotent_id('dbbfd247-c40c-449e-8f6c-d2aa7c7da7cf')
     def test_server_name_blank(self):
         # Create a server with name parameter empty
 
@@ -63,7 +64,7 @@
                           name='')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('b8a7235e-5246-4a8f-a08e-b34877c6586f')
+    @decorators.idempotent_id('b8a7235e-5246-4a8f-a08e-b34877c6586f')
     @testtools.skipUnless(CONF.compute_feature_enabled.personality,
                           'Nova personality feature disabled')
     def test_personality_file_contents_not_encoded(self):
@@ -78,7 +79,7 @@
                           personality=person)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('fcba1052-0a50-4cf3-b1ac-fae241edf02f')
+    @decorators.idempotent_id('fcba1052-0a50-4cf3-b1ac-fae241edf02f')
     def test_create_with_invalid_image(self):
         # Create a server with an unknown image
 
@@ -87,7 +88,7 @@
                           image_id=-1)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('18f5227f-d155-4429-807c-ccb103887537')
+    @decorators.idempotent_id('18f5227f-d155-4429-807c-ccb103887537')
     def test_create_with_invalid_flavor(self):
         # Create a server with an unknown flavor
 
@@ -96,7 +97,7 @@
                           flavor=-1,)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7f70a4d1-608f-4794-9e56-cb182765972c')
+    @decorators.idempotent_id('7f70a4d1-608f-4794-9e56-cb182765972c')
     def test_invalid_access_ip_v4_address(self):
         # An access IPv4 address must match a valid address pattern
 
@@ -105,7 +106,7 @@
                           self.create_test_server, accessIPv4=IPv4)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5226dd80-1e9c-4d8a-b5f9-b26ca4763fd0')
+    @decorators.idempotent_id('5226dd80-1e9c-4d8a-b5f9-b26ca4763fd0')
     def test_invalid_ip_v6_address(self):
         # An access IPv6 address must match a valid address pattern
 
@@ -114,7 +115,7 @@
         self.assertRaises(lib_exc.BadRequest,
                           self.create_test_server, accessIPv6=IPv6)
 
-    @test.idempotent_id('7ea45b3e-e770-46fa-bfcc-9daaf6d987c0')
+    @decorators.idempotent_id('7ea45b3e-e770-46fa-bfcc-9daaf6d987c0')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     @test.attr(type=['negative'])
@@ -125,7 +126,7 @@
                           self.client.resize_server,
                           nonexistent_server, self.flavor_ref)
 
-    @test.idempotent_id('ced1a1d7-2ab6-45c9-b90f-b27d87b30efd')
+    @decorators.idempotent_id('ced1a1d7-2ab6-45c9-b90f-b27d87b30efd')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     @test.attr(type=['negative'])
@@ -135,7 +136,7 @@
         self.assertRaises(lib_exc.BadRequest, self.client.resize_server,
                           self.server_id, flavor_ref=nonexistent_flavor)
 
-    @test.idempotent_id('45436a7d-a388-4a35-a9d8-3adc5d0d940b')
+    @decorators.idempotent_id('45436a7d-a388-4a35-a9d8-3adc5d0d940b')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     @test.attr(type=['negative'])
@@ -145,14 +146,14 @@
                           self.server_id, flavor_ref="")
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d4c023a0-9c55-4747-9dd5-413b820143c7')
+    @decorators.idempotent_id('d4c023a0-9c55-4747-9dd5-413b820143c7')
     def test_reboot_non_existent_server(self):
         # Reboot a non existent server
         nonexistent_server = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound, self.client.reboot_server,
                           nonexistent_server, type='SOFT')
 
-    @test.idempotent_id('d1417e7f-a509-41b5-a102-d5eed8613369')
+    @decorators.idempotent_id('d1417e7f-a509-41b5-a102-d5eed8613369')
     @testtools.skipUnless(CONF.compute_feature_enabled.pause,
                           'Pause is not available.')
     @test.attr(type=['negative'])
@@ -166,7 +167,7 @@
         self.client.unpause_server(self.server_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('98fa0458-1485-440f-873b-fe7f0d714930')
+    @decorators.idempotent_id('98fa0458-1485-440f-873b-fe7f0d714930')
     def test_rebuild_deleted_server(self):
         # Rebuild a deleted server
         server = self.create_test_server()
@@ -175,10 +176,11 @@
 
         self.assertRaises(lib_exc.NotFound,
                           self.client.rebuild_server,
-                          server['id'], self.image_ref_alt)
+                          server['id'], self.image_ref)
 
+    @test.related_bug('1660878', status_code=409)
     @test.attr(type=['negative'])
-    @test.idempotent_id('581a397d-5eab-486f-9cf9-1014bbd4c984')
+    @decorators.idempotent_id('581a397d-5eab-486f-9cf9-1014bbd4c984')
     def test_reboot_deleted_server(self):
         # Reboot a deleted server
         server = self.create_test_server()
@@ -189,17 +191,17 @@
                           server['id'], type='SOFT')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d86141a7-906e-4731-b187-d64a2ea61422')
+    @decorators.idempotent_id('d86141a7-906e-4731-b187-d64a2ea61422')
     def test_rebuild_non_existent_server(self):
         # Rebuild a non existent server
         nonexistent_server = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound,
                           self.client.rebuild_server,
                           nonexistent_server,
-                          self.image_ref_alt)
+                          self.image_ref)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('fd57f159-68d6-4c2a-902b-03070828a87e')
+    @decorators.idempotent_id('fd57f159-68d6-4c2a-902b-03070828a87e')
     def test_create_numeric_server_name(self):
         server_name = 12345
         self.assertRaises(lib_exc.BadRequest,
@@ -207,9 +209,9 @@
                           name=server_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('c3e0fb12-07fc-4d76-a22e-37409887afe8')
+    @decorators.idempotent_id('c3e0fb12-07fc-4d76-a22e-37409887afe8')
     def test_create_server_name_length_exceeds_256(self):
-        # Create a server with name length exceeding 256 characters
+        # Create a server with name length exceeding 255 characters
 
         server_name = 'a' * 256
         self.assertRaises(lib_exc.BadRequest,
@@ -217,7 +219,27 @@
                           name=server_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('4e72dc2d-44c5-4336-9667-f7972e95c402')
+    @test.related_bug('1651064', status_code=500)
+    @decorators.idempotent_id('12146ac1-d7df-4928-ad25-b1f99e5286cd')
+    def test_create_server_invalid_bdm_in_2nd_dict(self):
+        volume = self.create_volume()
+        bdm_1st = {"source_type": "image",
+                   "delete_on_termination": True,
+                   "boot_index": 0,
+                   "uuid": self.image_ref,
+                   "destination_type": "local"}
+        bdm_2nd = {"source_type": "volume",
+                   "uuid": volume["id"],
+                   "destination_type": "invalid"}
+        bdm = [bdm_1st, bdm_2nd]
+
+        self.assertRaises(lib_exc.BadRequest,
+                          self.create_test_server,
+                          image_id=self.image_ref,
+                          block_device_mapping_v2=bdm)
+
+    @test.attr(type=['negative'])
+    @decorators.idempotent_id('4e72dc2d-44c5-4336-9667-f7972e95c402')
     def test_create_with_invalid_network_uuid(self):
         # Pass invalid network uuid while creating a server
 
@@ -228,7 +250,7 @@
                           networks=networks)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7a2efc39-530c-47de-b875-2dd01c8d39bd')
+    @decorators.idempotent_id('7a2efc39-530c-47de-b875-2dd01c8d39bd')
     def test_create_with_non_existent_keypair(self):
         # Pass a non-existent keypair while creating a server
 
@@ -238,7 +260,7 @@
                           key_name=key_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7fc74810-0bd2-4cd7-8244-4f33a9db865a')
+    @decorators.idempotent_id('7fc74810-0bd2-4cd7-8244-4f33a9db865a')
     def test_create_server_metadata_exceeds_length_limit(self):
         # Pass really long metadata while creating a server
 
@@ -248,7 +270,7 @@
                           metadata=metadata)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('aa8eed43-e2cb-4ebf-930b-da14f6a21d81')
+    @decorators.idempotent_id('aa8eed43-e2cb-4ebf-930b-da14f6a21d81')
     def test_update_name_of_non_existent_server(self):
         # Update name of a non-existent server
 
@@ -260,7 +282,7 @@
                           nonexistent_server, name=new_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('38204696-17c6-44da-9590-40f87fb5a899')
+    @decorators.idempotent_id('38204696-17c6-44da-9590-40f87fb5a899')
     def test_update_server_set_empty_name(self):
         # Update name of the server to an empty string
 
@@ -270,7 +292,7 @@
                           self.server_id, name=new_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5c8e244c-dada-4590-9944-749c455b431f')
+    @decorators.idempotent_id('5c8e244c-dada-4590-9944-749c455b431f')
     def test_update_server_name_length_exceeds_256(self):
         # Update name of server exceed the name length limit
 
@@ -281,7 +303,7 @@
                           name=new_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('1041b4e6-514b-4855-96a5-e974b60870a3')
+    @decorators.idempotent_id('1041b4e6-514b-4855-96a5-e974b60870a3')
     def test_delete_non_existent_server(self):
         # Delete a non existent server
 
@@ -290,14 +312,14 @@
                           nonexistent_server)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('75f79124-277c-45e6-a373-a1d6803f4cc4')
+    @decorators.idempotent_id('75f79124-277c-45e6-a373-a1d6803f4cc4')
     def test_delete_server_pass_negative_id(self):
         # Pass an invalid string parameter to delete server
 
         self.assertRaises(lib_exc.NotFound, self.client.delete_server, -1)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('f4d7279b-5fd2-4bf2-9ba4-ae35df0d18c5')
+    @decorators.idempotent_id('f4d7279b-5fd2-4bf2-9ba4-ae35df0d18c5')
     def test_delete_server_pass_id_exceeding_length_limit(self):
         # Pass a server ID that exceeds length limit to delete server
 
@@ -305,7 +327,7 @@
                           sys.maxsize + 1)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('c5fa6041-80cd-483b-aa6d-4e45f19d093c')
+    @decorators.idempotent_id('c5fa6041-80cd-483b-aa6d-4e45f19d093c')
     def test_create_with_nonexistent_security_group(self):
         # Create a server with a nonexistent security group
 
@@ -315,7 +337,7 @@
                           security_groups=security_groups)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('3436b02f-1b1e-4f03-881e-c6a602327439')
+    @decorators.idempotent_id('3436b02f-1b1e-4f03-881e-c6a602327439')
     def test_get_non_existent_server(self):
         # Get a non existent server details
         nonexistent_server = data_utils.rand_uuid()
@@ -323,14 +345,14 @@
                           nonexistent_server)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('a31460a9-49e1-42aa-82ee-06e0bb7c2d03')
+    @decorators.idempotent_id('a31460a9-49e1-42aa-82ee-06e0bb7c2d03')
     def test_stop_non_existent_server(self):
         # Stop a non existent server
         nonexistent_server = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound, self.servers_client.stop_server,
                           nonexistent_server)
 
-    @test.idempotent_id('6a8dc0c6-6cd4-4c0a-9f32-413881828091')
+    @decorators.idempotent_id('6a8dc0c6-6cd4-4c0a-9f32-413881828091')
     @testtools.skipUnless(CONF.compute_feature_enabled.pause,
                           'Pause is not available.')
     @test.attr(type=['negative'])
@@ -340,7 +362,7 @@
         self.assertRaises(lib_exc.NotFound, self.client.pause_server,
                           nonexistent_server)
 
-    @test.idempotent_id('705b8e3a-e8a7-477c-a19b-6868fc24ac75')
+    @decorators.idempotent_id('705b8e3a-e8a7-477c-a19b-6868fc24ac75')
     @testtools.skipUnless(CONF.compute_feature_enabled.pause,
                           'Pause is not available.')
     @test.attr(type=['negative'])
@@ -350,7 +372,7 @@
         self.assertRaises(lib_exc.NotFound, self.client.unpause_server,
                           nonexistent_server)
 
-    @test.idempotent_id('c8e639a7-ece8-42dd-a2e0-49615917ba4f')
+    @decorators.idempotent_id('c8e639a7-ece8-42dd-a2e0-49615917ba4f')
     @testtools.skipUnless(CONF.compute_feature_enabled.pause,
                           'Pause is not available.')
     @test.attr(type=['negative'])
@@ -360,7 +382,7 @@
                           self.client.unpause_server,
                           self.server_id)
 
-    @test.idempotent_id('d1f032d5-7b6e-48aa-b252-d5f16dd994ca')
+    @decorators.idempotent_id('d1f032d5-7b6e-48aa-b252-d5f16dd994ca')
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
                           'Suspend is not available.')
     @test.attr(type=['negative'])
@@ -370,7 +392,7 @@
         self.assertRaises(lib_exc.NotFound, self.client.suspend_server,
                           nonexistent_server)
 
-    @test.idempotent_id('7f323206-05a9-4bf8-996b-dd5b2036501b')
+    @decorators.idempotent_id('7f323206-05a9-4bf8-996b-dd5b2036501b')
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
                           'Suspend is not available.')
     @test.attr(type=['negative'])
@@ -384,7 +406,7 @@
                           self.server_id)
         self.client.resume_server(self.server_id)
 
-    @test.idempotent_id('221cd282-bddb-4837-a683-89c2487389b6')
+    @decorators.idempotent_id('221cd282-bddb-4837-a683-89c2487389b6')
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
                           'Suspend is not available.')
     @test.attr(type=['negative'])
@@ -394,7 +416,7 @@
         self.assertRaises(lib_exc.NotFound, self.client.resume_server,
                           nonexistent_server)
 
-    @test.idempotent_id('ccb6294d-c4c9-498f-8a43-554c098bfadb')
+    @decorators.idempotent_id('ccb6294d-c4c9-498f-8a43-554c098bfadb')
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
                           'Suspend is not available.')
     @test.attr(type=['negative'])
@@ -405,7 +427,7 @@
                           self.server_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7dd919e7-413f-4198-bebb-35e2a01b13e9')
+    @decorators.idempotent_id('7dd919e7-413f-4198-bebb-35e2a01b13e9')
     def test_get_console_output_of_non_existent_server(self):
         # get the console output for a non existent server
         nonexistent_server = data_utils.rand_uuid()
@@ -414,7 +436,7 @@
                           nonexistent_server, length=10)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('6f47992b-5144-4250-9f8b-f00aa33950f3')
+    @decorators.idempotent_id('6f47992b-5144-4250-9f8b-f00aa33950f3')
     def test_force_delete_nonexistent_server_id(self):
         # force-delete a non existent server
         nonexistent_server = data_utils.rand_uuid()
@@ -423,7 +445,7 @@
                           nonexistent_server)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('9c6d38cc-fcfb-437a-85b9-7b788af8bf01')
+    @decorators.idempotent_id('9c6d38cc-fcfb-437a-85b9-7b788af8bf01')
     def test_restore_nonexistent_server_id(self):
         # restore-delete a non existent server
         nonexistent_server = data_utils.rand_uuid()
@@ -432,14 +454,14 @@
                           nonexistent_server)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7fcadfab-bd6a-4753-8db7-4a51e51aade9')
+    @decorators.idempotent_id('7fcadfab-bd6a-4753-8db7-4a51e51aade9')
     def test_restore_server_invalid_state(self):
         # we can only restore-delete a server in 'soft-delete' state
         self.assertRaises(lib_exc.Conflict,
                           self.client.restore_soft_deleted_server,
                           self.server_id)
 
-    @test.idempotent_id('abca56e2-a892-48ea-b5e5-e07e69774816')
+    @decorators.idempotent_id('abca56e2-a892-48ea-b5e5-e07e69774816')
     @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
                           'Shelve is not available.')
     @test.attr(type=['negative'])
@@ -449,7 +471,7 @@
         self.assertRaises(lib_exc.NotFound, self.client.shelve_server,
                           nonexistent_server)
 
-    @test.idempotent_id('443e4f9b-e6bf-4389-b601-3a710f15fddd')
+    @decorators.idempotent_id('443e4f9b-e6bf-4389-b601-3a710f15fddd')
     @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
                           'Shelve is not available.')
     @test.attr(type=['negative'])
@@ -470,7 +492,7 @@
 
         self.client.unshelve_server(self.server_id)
 
-    @test.idempotent_id('23d23b37-afaf-40d7-aa5d-5726f82d8821')
+    @decorators.idempotent_id('23d23b37-afaf-40d7-aa5d-5726f82d8821')
     @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
                           'Shelve is not available.')
     @test.attr(type=['negative'])
@@ -480,7 +502,7 @@
         self.assertRaises(lib_exc.NotFound, self.client.unshelve_server,
                           nonexistent_server)
 
-    @test.idempotent_id('8f198ded-1cca-4228-9e65-c6b449c54880')
+    @decorators.idempotent_id('8f198ded-1cca-4228-9e65-c6b449c54880')
     @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
                           'Shelve is not available.')
     @test.attr(type=['negative'])
@@ -491,7 +513,7 @@
                           self.server_id)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('74085be3-a370-4ca2-bc51-2d0e10e0f573')
+    @decorators.idempotent_id('74085be3-a370-4ca2-bc51-2d0e10e0f573')
     @test.services('volume', 'image')
     def test_create_server_from_non_bootable_volume(self):
         # Create a volume
@@ -545,7 +567,7 @@
         cls.server_id = server['id']
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('543d84c1-dd2e-4c6d-8cb2-b9da0efaa384')
+    @decorators.idempotent_id('543d84c1-dd2e-4c6d-8cb2-b9da0efaa384')
     def test_update_server_of_another_tenant(self):
         # Update name of a server that belongs to another tenant
 
@@ -555,7 +577,7 @@
                           name=new_name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5c75009d-3eea-423e-bea3-61b09fd25f9c')
+    @decorators.idempotent_id('5c75009d-3eea-423e-bea3-61b09fd25f9c')
     def test_delete_a_server_of_another_tenant(self):
         # Delete a server that belongs to another tenant
         self.assertRaises(lib_exc.NotFound,
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 08c34d3..610121b 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -18,6 +18,7 @@
 
 from tempest.api.compute import base
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions
 from tempest import test
 
@@ -42,7 +43,7 @@
         super(VirtualInterfacesTestJSON, cls).resource_setup()
         cls.server = cls.create_test_server(wait_until='ACTIVE')
 
-    @test.idempotent_id('96c4e2ef-5e4d-4d7f-87f5-fed6dca18016')
+    @decorators.idempotent_id('96c4e2ef-5e4d-4d7f-87f5-fed6dca18016')
     @test.services('network')
     def test_list_virtual_interfaces(self):
         # Positive test:Should be able to GET the virtual interfaces list
diff --git a/tempest/api/compute/servers/test_virtual_interfaces_negative.py b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
index 912b0a1..b1374d2 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces_negative.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.compute 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
 
@@ -33,7 +34,7 @@
         cls.client = cls.servers_client
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('64ebd03c-1089-4306-93fa-60f5eb5c803c')
+    @decorators.idempotent_id('64ebd03c-1089-4306-93fa-60f5eb5c803c')
     @test.services('network')
     def test_list_virtual_interfaces_invalid_server_id(self):
         # Negative test: Should not be able to GET virtual interfaces
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index d171cd5..f87bf6d 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -17,6 +17,7 @@
 
 from tempest.api.compute import base
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -27,7 +28,7 @@
 
 class ExtensionsTestJSON(base.BaseV2ComputeTest):
 
-    @test.idempotent_id('3bb27738-b759-4e0d-a5fa-37d7a6df07d1')
+    @decorators.idempotent_id('3bb27738-b759-4e0d-a5fa-37d7a6df07d1')
     def test_list_extensions(self):
         # List of all extensions
         if len(CONF.compute_feature_enabled.api_extensions) == 0:
@@ -44,7 +45,7 @@
         extension_list = map(lambda x: x['alias'], extensions)
         LOG.debug("Nova extensions: %s", ','.join(extension_list))
 
-    @test.idempotent_id('05762f39-bdfa-4cdb-9b46-b78f8e78e2fd')
+    @decorators.idempotent_id('05762f39-bdfa-4cdb-9b46-b78f8e78e2fd')
     @test.requires_ext(extension='os-consoles', service='compute')
     def test_get_extension(self):
         # get the specified extensions
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
index f072b81..0f5ea57 100644
--- a/tempest/api/compute/test_live_block_migration_negative.py
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -14,9 +14,10 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 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
 
@@ -30,20 +31,14 @@
         if not CONF.compute_feature_enabled.live_migration:
             raise cls.skipException("Live migration is not enabled")
 
-    @classmethod
-    def setup_clients(cls):
-        super(LiveBlockMigrationNegativeTestJSON, cls).setup_clients()
-        cls.admin_servers_client = cls.os_adm.servers_client
-
     def _migrate_server_to(self, server_id, dest_host):
         bmflm = CONF.compute_feature_enabled.block_migration_for_live_migration
-        body = self.admin_servers_client.live_migrate_server(
+        self.admin_servers_client.live_migrate_server(
             server_id, host=dest_host, block_migration=bmflm,
             disk_over_commit=False)
-        return body
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('7fb7856e-ae92-44c9-861a-af62d7830bcb')
+    @decorators.idempotent_id('7fb7856e-ae92-44c9-861a-af62d7830bcb')
     def test_invalid_host_for_migration(self):
         # Migrating to an invalid host should not change the status
         target_host = data_utils.rand_name('host')
diff --git a/tempest/api/compute/test_networks.py b/tempest/api/compute/test_networks.py
index d4b8003..4d21fed 100644
--- a/tempest/api/compute/test_networks.py
+++ b/tempest/api/compute/test_networks.py
@@ -14,7 +14,7 @@
 
 from tempest.api.compute import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -31,7 +31,7 @@
         super(ComputeNetworksTest, cls).setup_clients()
         cls.client = cls.os.compute_networks_client
 
-    @test.idempotent_id('3fe07175-312e-49a5-a623-5f52eeada4c2')
+    @decorators.idempotent_id('3fe07175-312e-49a5-a623-5f52eeada4c2')
     def test_list_networks(self):
         networks = self.client.list_networks()['networks']
         self.assertNotEmpty(networks, "No networks found.")
diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py
index b9e0c35..9d83ee1 100644
--- a/tempest/api/compute/test_quotas.py
+++ b/tempest/api/compute/test_quotas.py
@@ -15,6 +15,7 @@
 
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -51,7 +52,7 @@
                                      'cores', 'security_groups',
                                      'server_group_members', 'server_groups'))
 
-    @test.idempotent_id('f1ef0a97-dbbb-4cca-adc5-c9fbc4f76107')
+    @decorators.idempotent_id('f1ef0a97-dbbb-4cca-adc5-c9fbc4f76107')
     def test_get_quotas(self):
         # User can get the quota set for it's tenant
         expected_quota_set = self.default_quota_set | set(['id'])
@@ -61,13 +62,13 @@
             self.assertIn(quota, quota_set.keys())
 
         # get the quota set using user id
-        quota_set = self.client.show_quota_set(self.tenant_id,
-                                               self.user_id)['quota_set']
+        quota_set = self.client.show_quota_set(
+            self.tenant_id, user_id=self.user_id)['quota_set']
         self.assertEqual(quota_set['id'], self.tenant_id)
         for quota in expected_quota_set:
             self.assertIn(quota, quota_set.keys())
 
-    @test.idempotent_id('9bfecac7-b966-4f47-913f-1a9e2c12134a')
+    @decorators.idempotent_id('9bfecac7-b966-4f47-913f-1a9e2c12134a')
     def test_get_default_quotas(self):
         # User can get the default quota set for it's tenant
         expected_quota_set = self.default_quota_set | set(['id'])
@@ -77,7 +78,7 @@
         for quota in expected_quota_set:
             self.assertIn(quota, quota_set.keys())
 
-    @test.idempotent_id('cd65d997-f7e4-4966-a7e9-d5001b674fdc')
+    @decorators.idempotent_id('cd65d997-f7e4-4966-a7e9-d5001b674fdc')
     def test_compare_tenant_quotas_with_default_quotas(self):
         # Tenants are created with the default quota values
         default_quota_set = \
diff --git a/tempest/api/compute/test_tenant_networks.py b/tempest/api/compute/test_tenant_networks.py
index 96b7ef6..b203c7e 100644
--- a/tempest/api/compute/test_tenant_networks.py
+++ b/tempest/api/compute/test_tenant_networks.py
@@ -13,6 +13,7 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -29,7 +30,7 @@
         cls.set_network_resources(network=True)
         super(ComputeTenantNetworksTest, cls).setup_credentials()
 
-    @test.idempotent_id('edfea98e-bbe3-4c7a-9739-87b986baff26')
+    @decorators.idempotent_id('edfea98e-bbe3-4c7a-9739-87b986baff26')
     @test.services('network')
     def test_list_show_tenant_networks(self):
         # Fetch all networks that are visible to the tenant: this may include
diff --git a/tempest/api/compute/test_versions.py b/tempest/api/compute/test_versions.py
index 8b84a21..dcab067 100644
--- a/tempest/api/compute/test_versions.py
+++ b/tempest/api/compute/test_versions.py
@@ -13,12 +13,14 @@
 # under the License.
 
 from tempest.api.compute import base
+from tempest.lib import decorators
 from tempest import test
 
 
 class TestVersions(base.BaseV2ComputeTest):
 
-    @test.idempotent_id('6c0a0990-43b6-4529-9b61-5fd8daf7c55c')
+    @decorators.idempotent_id('6c0a0990-43b6-4529-9b61-5fd8daf7c55c')
+    @test.attr(type='smoke')
     def test_list_api_versions(self):
         """Test that a get of the unversioned url returns the choices doc.
 
@@ -36,7 +38,8 @@
         self.assertEqual(versions[0]['id'], 'v2.0',
                          "The first listed version should be v2.0")
 
-    @test.idempotent_id('b953a29e-929c-4a8e-81be-ec3a7e03cb76')
+    @decorators.idempotent_id('b953a29e-929c-4a8e-81be-ec3a7e03cb76')
+    @test.attr(type='smoke')
     def test_get_version_details(self):
         """Test individual version endpoints info works.
 
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 30549ec..b0a6622 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -13,7 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import logging
 import testtools
 
 from tempest.api.compute import base
@@ -21,13 +20,10 @@
 from tempest.common.utils.linux import remote_client
 from tempest.common import waiters
 from tempest import config
-from tempest.lib import exceptions as lib_exc
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
-LOG = logging.getLogger(__name__)
-
 
 class AttachVolumeTestJSON(base.BaseV2ComputeTest):
     max_microversion = '2.19'
@@ -61,38 +57,28 @@
             server['id'])['addresses']
         return server
 
-    def _detach_volume(self, server_id, volume_id):
-        try:
-            self.servers_client.detach_volume(server_id, volume_id)
-            waiters.wait_for_volume_status(self.volumes_client,
-                                           volume_id, 'available')
-        except lib_exc.NotFound:
-            LOG.warning("Unable to detach volume %s from server %s "
-                        "possibly it was already detached", volume_id,
-                        server_id)
-
-    def _attach_volume(self, server_id, volume_id, device=None):
-        # Attach the volume to the server
-        kwargs = {'volumeId': volume_id}
-        if device:
-            kwargs.update({'device': '/dev/%s' % device})
-        attachment = self.servers_client.attach_volume(
-            server_id, **kwargs)['volumeAttachment']
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume_id, 'in-use')
-        self.addCleanup(self._detach_volume, server_id,
-                        volume_id)
-
-        return attachment
-
-    @test.idempotent_id('52e9045a-e90d-4c0d-9087-79d657faffff')
+    @decorators.idempotent_id('52e9045a-e90d-4c0d-9087-79d657faffff')
     def test_attach_detach_volume(self):
         # Stop and Start a server with an attached volume, ensuring that
         # the volume remains attached.
         server = self._create_server()
+
+        # NOTE(andreaf) Create one remote client used throughout the test.
+        if CONF.validation.run_validation:
+            linux_client = remote_client.RemoteClient(
+                self.get_server_ip(server),
+                self.image_ssh_user,
+                self.image_ssh_password,
+                self.validation_resources['keypair']['private_key'],
+                server=server,
+                servers_client=self.servers_client)
+            # NOTE(andreaf) We need to ensure the ssh key has been
+            # injected in the guest before we power cycle
+            linux_client.validate_authentication()
+
         volume = self.create_volume()
-        attachment = self._attach_volume(server['id'], volume['id'],
-                                         device=self.device)
+        attachment = self.attach_volume(server, volume,
+                                        device=('/dev/%s' % self.device))
 
         self.servers_client.stop_server(server['id'])
         waiters.wait_for_server_status(self.servers_client, server['id'],
@@ -103,19 +89,14 @@
                                        'ACTIVE')
 
         if CONF.validation.run_validation:
-            linux_client = remote_client.RemoteClient(
-                self.get_server_ip(server),
-                self.image_ssh_user,
-                self.image_ssh_password,
-                self.validation_resources['keypair']['private_key'],
-                server=server,
-                servers_client=self.servers_client)
-
             disks = linux_client.get_disks()
             device_name_to_match = '\n' + self.device + ' '
             self.assertIn(device_name_to_match, disks)
 
-        self._detach_volume(server['id'], attachment['volumeId'])
+        self.servers_client.detach_volume(server['id'], attachment['volumeId'])
+        waiters.wait_for_volume_resource_status(
+            self.volumes_client, attachment['volumeId'], 'available')
+
         self.servers_client.stop_server(server['id'])
         waiters.wait_for_server_status(self.servers_client, server['id'],
                                        'SHUTOFF')
@@ -125,24 +106,16 @@
                                        'ACTIVE')
 
         if CONF.validation.run_validation:
-            linux_client = remote_client.RemoteClient(
-                self.get_server_ip(server),
-                self.image_ssh_user,
-                self.image_ssh_password,
-                self.validation_resources['keypair']['private_key'],
-                server=server,
-                servers_client=self.servers_client)
-
             disks = linux_client.get_disks()
             self.assertNotIn(device_name_to_match, disks)
 
-    @test.idempotent_id('7fa563fe-f0f7-43eb-9e22-a1ece036b513')
+    @decorators.idempotent_id('7fa563fe-f0f7-43eb-9e22-a1ece036b513')
     def test_list_get_volume_attachments(self):
         # List volume attachment of the server
         server = self._create_server()
         volume = self.create_volume()
-        attachment = self._attach_volume(server['id'], volume['id'],
-                                         device=self.device)
+        attachment = self.attach_volume(server, volume,
+                                        device=('/dev/%s' % self.device))
         body = self.servers_client.list_volume_attachments(
             server['id'])['volumeAttachments']
         self.assertEqual(1, len(body))
@@ -156,7 +129,7 @@
         self.assertEqual(volume['id'], body['volumeId'])
         self.assertEqual(attachment['id'], body['id'])
 
-    @test.idempotent_id('757d488b-a951-4bc7-b3cd-f417028da08a')
+    @decorators.idempotent_id('757d488b-a951-4bc7-b3cd-f417028da08a')
     def test_list_get_two_volume_attachments(self):
         # NOTE: This test is using the volume device auto-assignment
         # without specifying the device ("/dev/sdb", etc). The feature
@@ -165,8 +138,8 @@
         server = self._create_server()
         volume_1st = self.create_volume()
         volume_2nd = self.create_volume()
-        attachment_1st = self._attach_volume(server['id'], volume_1st['id'])
-        attachment_2nd = self._attach_volume(server['id'], volume_2nd['id'])
+        attachment_1st = self.attach_volume(server, volume_1st)
+        attachment_2nd = self.attach_volume(server, volume_2nd)
 
         body = self.servers_client.list_volume_attachments(
             server['id'])['volumeAttachments']
@@ -243,7 +216,7 @@
             counted_volumes = self._count_volumes(server)
             self.assertEqual(number_of_volumes, counted_volumes)
 
-    @test.idempotent_id('13a940b6-3474-4c3c-b03f-29b89112bfee')
+    @decorators.idempotent_id('13a940b6-3474-4c3c-b03f-29b89112bfee')
     @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
                           'Shelve is not available.')
     def test_attach_volume_shelved_or_offload_server(self):
@@ -253,8 +226,8 @@
         volume = self.create_volume()
         num_vol = self._count_volumes(server)
         self._shelve_server(server)
-        attachment = self._attach_volume(server['id'], volume['id'],
-                                         device=self.device)
+        attachment = self.attach_volume(server, volume,
+                                        device=('/dev/%s' % self.device))
 
         # Unshelve the instance and check that attached volume exists
         self._unshelve_server_and_check_volumes(server, num_vol + 1)
@@ -269,7 +242,7 @@
         # case of shelved_offloaded.
         self.assertIsNotNone(volume_attachment['device'])
 
-    @test.idempotent_id('b54e86dd-a070-49c4-9c07-59ae6dae15aa')
+    @decorators.idempotent_id('b54e86dd-a070-49c4-9c07-59ae6dae15aa')
     @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
                           'Shelve is not available.')
     def test_detach_volume_shelved_or_offload_server(self):
@@ -279,9 +252,12 @@
         volume = self.create_volume()
         num_vol = self._count_volumes(server)
         self._shelve_server(server)
-        self._attach_volume(server['id'], volume['id'], device=self.device)
-        # Detach the volume
-        self._detach_volume(server['id'], volume['id'])
+
+        # Attach and then detach the volume
+        self.attach_volume(server, volume, device=('/dev/%s' % self.device))
+        self.servers_client.detach_volume(server['id'], volume['id'])
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'available')
 
         # Unshelve the instance and check that we have the expected number of
         # volume(s)
diff --git a/tempest/api/compute/volumes/test_attach_volume_negative.py b/tempest/api/compute/volumes/test_attach_volume_negative.py
index 1f18bfe..c017690 100644
--- a/tempest/api/compute/volumes/test_attach_volume_negative.py
+++ b/tempest/api/compute/volumes/test_attach_volume_negative.py
@@ -14,6 +14,7 @@
 
 from tempest.api.compute import base
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -29,8 +30,9 @@
             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)
-    @test.idempotent_id('a313b5cd-fbd0-49cc-94de-870e99f763c7')
+    @decorators.idempotent_id('a313b5cd-fbd0-49cc-94de-870e99f763c7')
     def test_delete_attached_volume(self):
         server = self.create_test_server(wait_until='ACTIVE')
         volume = self.create_volume()
diff --git a/tempest/api/compute/volumes/test_volume_snapshots.py b/tempest/api/compute/volumes/test_volume_snapshots.py
index 01718cc..2f3a06e 100644
--- a/tempest/api/compute/volumes/test_volume_snapshots.py
+++ b/tempest/api/compute/volumes/test_volume_snapshots.py
@@ -16,10 +16,10 @@
 import testtools
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 
 CONF = config.CONF
@@ -40,7 +40,7 @@
         cls.volumes_client = cls.volumes_extensions_client
         cls.snapshots_client = cls.snapshots_extensions_client
 
-    @test.idempotent_id('cd4ec87d-7825-450d-8040-6e2068f2da8f')
+    @decorators.idempotent_id('cd4ec87d-7825-450d-8040-6e2068f2da8f')
     @testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
                           'Cinder volume snapshots are disabled')
     def test_volume_snapshot_create_get_list_delete(self):
@@ -54,9 +54,9 @@
             display_name=s_name)['snapshot']
 
         def delete_snapshot(snapshot_id):
-            waiters.wait_for_snapshot_status(self.snapshots_client,
-                                             snapshot_id,
-                                             'available')
+            waiters.wait_for_volume_resource_status(self.snapshots_client,
+                                                    snapshot_id,
+                                                    'available')
             # Delete snapshot
             self.snapshots_client.delete_snapshot(snapshot_id)
             self.snapshots_client.wait_for_resource_deletion(snapshot_id)
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
index 7549d4a..43c837a 100644
--- a/tempest/api/compute/volumes/test_volumes_get.py
+++ b/tempest/api/compute/volumes/test_volumes_get.py
@@ -16,10 +16,10 @@
 from testtools import matchers
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 
 CONF = config.CONF
@@ -39,7 +39,7 @@
         super(VolumesGetTestJSON, cls).setup_clients()
         cls.client = cls.volumes_extensions_client
 
-    @test.idempotent_id('f10f25eb-9775-4d9d-9cbe-1cf54dae9d5f')
+    @decorators.idempotent_id('f10f25eb-9775-4d9d-9cbe-1cf54dae9d5f')
     def test_volume_create_get_delete(self):
         # CREATE, GET, DELETE Volume
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
@@ -57,7 +57,8 @@
         self.assertIsNotNone(volume['id'],
                              "Field volume id is empty or not found.")
         # Wait for Volume status to become ACTIVE
-        waiters.wait_for_volume_status(self.client, volume['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.client, volume['id'],
+                                                'available')
         # GET Volume
         fetched_volume = self.client.show_volume(volume['id'])['volume']
         # Verification of details of fetched Volume
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index 82cc653..0d8214f 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -15,7 +15,7 @@
 
 from tempest.api.compute import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -44,15 +44,13 @@
         super(VolumesTestJSON, cls).resource_setup()
         # Create 3 Volumes
         cls.volume_list = []
-        cls.volume_id_list = []
-        for i in range(3):
+        for _ in range(3):
             metadata = {'Type': 'work'}
             volume = cls.create_volume(metadata=metadata)
             volume = cls.client.show_volume(volume['id'])['volume']
             cls.volume_list.append(volume)
-            cls.volume_id_list.append(volume['id'])
 
-    @test.idempotent_id('bc2dd1a0-15af-48e5-9990-f2e75a48325d')
+    @decorators.idempotent_id('bc2dd1a0-15af-48e5-9990-f2e75a48325d')
     def test_volume_list(self):
         # Should return the list of Volumes
         # Fetch all Volumes
@@ -67,7 +65,7 @@
                          ', '.join(m_vol['displayName']
                                    for m_vol in missing_volumes))
 
-    @test.idempotent_id('bad0567a-5a4f-420b-851e-780b55bb867c')
+    @decorators.idempotent_id('bad0567a-5a4f-420b-851e-780b55bb867c')
     def test_volume_list_with_details(self):
         # Should return the list of Volumes with details
         # Fetch all Volumes
@@ -82,7 +80,7 @@
                          ', '.join(m_vol['displayName']
                                    for m_vol in missing_volumes))
 
-    @test.idempotent_id('1048ed81-2baf-487a-b284-c0622b86e7b8')
+    @decorators.idempotent_id('1048ed81-2baf-487a-b284-c0622b86e7b8')
     def test_volume_list_param_limit(self):
         # Return the list of volumes based on limit set
         params = {'limit': 2}
@@ -91,7 +89,7 @@
         self.assertEqual(len(fetched_vol_list), params['limit'],
                          "Failed to list volumes by limit set")
 
-    @test.idempotent_id('33985568-4965-49d5-9bcc-0aa007ca5b7a')
+    @decorators.idempotent_id('33985568-4965-49d5-9bcc-0aa007ca5b7a')
     def test_volume_list_with_detail_param_limit(self):
         # Return the list of volumes with details based on limit set.
         params = {'limit': 2}
@@ -101,7 +99,7 @@
         self.assertEqual(len(fetched_vol_list), params['limit'],
                          "Failed to list volume details by limit set")
 
-    @test.idempotent_id('51c22651-a074-4ea7-af0b-094f9331303e')
+    @decorators.idempotent_id('51c22651-a074-4ea7-af0b-094f9331303e')
     def test_volume_list_param_offset_and_limit(self):
         # Return the list of volumes based on offset and limit set.
         # get all volumes list
@@ -118,7 +116,7 @@
                              all_vol_list[index + params['offset']]['id'],
                              "Failed to list volumes by offset and limit")
 
-    @test.idempotent_id('06b6abc4-3f10-48e9-a7a1-3facc98f03e5')
+    @decorators.idempotent_id('06b6abc4-3f10-48e9-a7a1-3facc98f03e5')
     def test_volume_list_with_detail_param_offset_and_limit(self):
         # Return the list of volumes details based on offset and limit set.
         # get all volumes list
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
index c4041cb..7676ee8 100644
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -14,8 +14,9 @@
 #    under the License.
 
 from tempest.api.compute 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
 
@@ -37,7 +38,7 @@
         cls.client = cls.volumes_extensions_client
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('c03ea686-905b-41a2-8748-9635154b7c57')
+    @decorators.idempotent_id('c03ea686-905b-41a2-8748-9635154b7c57')
     def test_volume_get_nonexistent_volume_id(self):
         # Negative: Should not be able to get details of nonexistent volume
         # Creating a nonexistent volume id
@@ -46,7 +47,7 @@
                           data_utils.rand_uuid())
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('54a34226-d910-4b00-9ef8-8683e6c55846')
+    @decorators.idempotent_id('54a34226-d910-4b00-9ef8-8683e6c55846')
     def test_volume_delete_nonexistent_volume_id(self):
         # Negative: Should not be able to delete nonexistent Volume
         # Creating nonexistent volume id
@@ -55,7 +56,7 @@
                           data_utils.rand_uuid())
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('5125ae14-152b-40a7-b3c5-eae15e9022ef')
+    @decorators.idempotent_id('5125ae14-152b-40a7-b3c5-eae15e9022ef')
     def test_create_volume_with_invalid_size(self):
         # Negative: Should not be able to create volume with invalid size
         # in request
@@ -65,7 +66,7 @@
                           size='#$%', display_name=v_name, metadata=metadata)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('131cb3a1-75cc-4d40-b4c3-1317f64719b0')
+    @decorators.idempotent_id('131cb3a1-75cc-4d40-b4c3-1317f64719b0')
     def test_create_volume_without_passing_size(self):
         # Negative: Should not be able to create volume without passing size
         # in request
@@ -75,7 +76,7 @@
                           size='', display_name=v_name, metadata=metadata)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('8cce995e-0a83-479a-b94d-e1e40b8a09d1')
+    @decorators.idempotent_id('8cce995e-0a83-479a-b94d-e1e40b8a09d1')
     def test_create_volume_with_size_zero(self):
         # Negative: Should not be able to create volume with size zero
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
@@ -84,21 +85,22 @@
                           size='0', display_name=v_name, metadata=metadata)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('62bab09a-4c03-4617-8cca-8572bc94af9b')
+    @decorators.idempotent_id('62bab09a-4c03-4617-8cca-8572bc94af9b')
     def test_get_volume_without_passing_volume_id(self):
         # Negative: Should not be able to get volume when empty ID is passed
         self.assertRaises(lib_exc.NotFound, self.client.show_volume, '')
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('62972737-124b-4513-b6cf-2f019f178494')
+    @decorators.idempotent_id('62972737-124b-4513-b6cf-2f019f178494')
     def test_delete_invalid_volume_id(self):
         # Negative: Should not be able to delete volume when invalid ID is
         # passed
         self.assertRaises(lib_exc.NotFound,
-                          self.client.delete_volume, '!@#$%^&*()')
+                          self.client.delete_volume,
+                          data_utils.rand_name('invalid'))
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('0d1417c5-4ae8-4c2c-adc5-5f0b864253e5')
+    @decorators.idempotent_id('0d1417c5-4ae8-4c2c-adc5-5f0b864253e5')
     def test_delete_volume_without_passing_volume_id(self):
         # Negative: Should not be able to delete volume when empty ID is passed
         self.assertRaises(lib_exc.NotFound, self.client.delete_volume, '')
diff --git a/tempest/api/identity/admin/v2/test_endpoints.py b/tempest/api/identity/admin/v2/test_endpoints.py
index 651a316..db32f5a 100644
--- a/tempest/api/identity/admin/v2/test_endpoints.py
+++ b/tempest/api/identity/admin/v2/test_endpoints.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 
 class EndPointsTestJSON(base.BaseIdentityV2AdminTest):
@@ -27,14 +27,14 @@
         s_name = data_utils.rand_name('service')
         s_type = data_utils.rand_name('type')
         s_description = data_utils.rand_name('description')
-        cls.service_data = cls.services_client.create_service(
+        service_data = cls.services_client.create_service(
             name=s_name, type=s_type,
             description=s_description)['OS-KSADM:service']
-        cls.service_id = cls.service_data['id']
+        cls.service_id = service_data['id']
         cls.service_ids.append(cls.service_id)
         # Create endpoints so as to use for LIST and GET test cases
         cls.setup_endpoints = list()
-        for i in range(2):
+        for _ in range(2):
             region = data_utils.rand_name('region')
             url = data_utils.rand_url()
             endpoint = cls.endpoints_client.create_endpoint(
@@ -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..479663c 100644
--- a/tempest/api/identity/admin/v2/test_roles.py
+++ b/tempest/api/identity/admin/v2/test_roles.py
@@ -14,9 +14,9 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+from tempest.lib.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..f80721c 100644
--- a/tempest/api/identity/admin/v2/test_roles_negative.py
+++ b/tempest/api/identity/admin/v2/test_roles_negative.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+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
 
@@ -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..f6d4a24 100644
--- a/tempest/api/identity/admin/v2/test_services.py
+++ b/tempest/api/identity/admin/v2/test_services.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+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
 
@@ -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..69f0920 100644
--- a/tempest/api/identity/admin/v2/test_tenant_negative.py
+++ b/tempest/api/identity/admin/v2/test_tenant_negative.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+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
 
@@ -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..6b7413c 100644
--- a/tempest/api/identity/admin/v2/test_tenants.py
+++ b/tempest/api/identity/admin/v2/test_tenants.py
@@ -14,14 +14,14 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+from tempest.lib.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..3428c07 100644
--- a/tempest/api/identity/admin/v2/test_tokens.py
+++ b/tempest/api/identity/admin/v2/test_tokens.py
@@ -14,13 +14,13 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+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..df4ded8 100644
--- a/tempest/api/identity/admin/v2/test_users.py
+++ b/tempest/api/identity/admin/v2/test_users.py
@@ -18,8 +18,9 @@
 from testtools import matchers
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+from tempest.lib.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..442c1a7 100644
--- a/tempest/api/identity/admin/v2/test_users_negative.py
+++ b/tempest/api/identity/admin/v2/test_users_negative.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+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
 
@@ -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 a0d8748..c752532 100644
--- a/tempest/api/identity/admin/v3/test_credentials.py
+++ b/tempest/api/identity/admin/v3/test_credentials.py
@@ -15,7 +15,8 @@
 from oslo_serialization import jsonutils as json
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -31,7 +32,7 @@
         u_desc = '%s description' % u_name
         u_email = '%s@testmail.tm' % u_name
         u_password = data_utils.rand_password()
-        for i in range(2):
+        for _ in range(2):
             cls.project = cls.projects_client.create_project(
                 data_utils.rand_name('project'),
                 description=data_utils.rand_name('project-desc'))['project']
@@ -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,12 +88,12 @@
             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()
 
-        for i in range(2):
+        for _ in range(2):
             blob = '{"access": "%s", "secret": "%s"}' % (
                 data_utils.rand_name('Access'), data_utils.rand_name('Secret'))
             cred = self.creds_client.create_credential(
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..c2ab488 100644
--- a/tempest/api/identity/admin/v3/test_default_project_id.py
+++ b/tempest/api/identity/admin/v3/test_default_project_id.py
@@ -11,10 +11,10 @@
 #    under the License.
 from tempest.api.identity import base
 from tempest import clients
-from tempest.common.utils import data_utils
 from tempest import config
 from tempest.lib import auth
-from tempest import test
+from tempest.lib.common.utils import data_utils
+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..d04e774 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -14,9 +14,10 @@
 #    under the License.
 
 from tempest.api.identity import base
-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 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..280a5a8 100644
--- a/tempest/api/identity/admin/v3/test_domains_negative.py
+++ b/tempest/api/identity/admin/v3/test_domains_negative.py
@@ -15,6 +15,7 @@
 
 from tempest.api.identity 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
 
@@ -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 655e4ef..0786d82 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -32,15 +33,14 @@
         s_name = data_utils.rand_name('service')
         s_type = data_utils.rand_name('type')
         s_description = data_utils.rand_name('description')
-        cls.service_data = (
+        service_data = (
             cls.services_client.create_service(name=s_name, type=s_type,
                                                description=s_description))
-        cls.service_data = cls.service_data['service']
-        cls.service_id = cls.service_data['id']
+        cls.service_id = service_data['service']['id']
         cls.service_ids.append(cls.service_id)
         # Create endpoints so as to use for LIST and GET test cases
         cls.setup_endpoints = list()
-        for i in range(2):
+        for _ in range(2):
             region = data_utils.rand_name('region')
             url = data_utils.rand_url()
             interface = 'public'
@@ -58,7 +58,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 +69,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 +110,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..d46e1f0 100644
--- a/tempest/api/identity/admin/v3/test_endpoints_negative.py
+++ b/tempest/api/identity/admin/v3/test_endpoints_negative.py
@@ -15,7 +15,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+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,11 +35,11 @@
         s_name = data_utils.rand_name('service')
         s_type = data_utils.rand_name('type')
         s_description = data_utils.rand_name('description')
-        cls.service_data = (
+        service_data = (
             cls.services_client.create_service(name=s_name, type=s_type,
                                                description=s_description)
             ['service'])
-        cls.service_id = cls.service_data['id']
+        cls.service_id = service_data['id']
         cls.service_ids.append(cls.service_id)
 
     @classmethod
@@ -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 3cbcc1f..a423a12 100644
--- a/tempest/api/identity/admin/v3/test_groups.py
+++ b/tempest/api/identity/admin/v3/test_groups.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+from tempest.lib.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(
@@ -80,7 +81,7 @@
         self.addCleanup(self.groups_client.delete_group, group['id'])
         # add user into group
         users = []
-        for i in range(3):
+        for _ in range(3):
             name = data_utils.rand_name('User')
             password = data_utils.rand_password()
             user = self.users_client.create_user(name=name,
@@ -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(
@@ -110,7 +111,7 @@
         self.addCleanup(self.users_client.delete_user, user['id'])
         # create two groups, and add user into them
         groups = []
-        for i in range(2):
+        for _ in range(2):
             name = data_utils.rand_name('Group')
             group = self.groups_client.create_group(
                 name=name, domain_id=self.domain['id'])['group']
@@ -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..3fe591b 100644
--- a/tempest/api/identity/admin/v3/test_inherits.py
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -11,7 +11,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+from tempest.lib.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..7e70c14 100644
--- a/tempest/api/identity/admin/v3/test_list_projects.py
+++ b/tempest/api/identity/admin/v3/test_list_projects.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+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..bcbf6b6 100644
--- a/tempest/api/identity/admin/v3/test_list_users.py
+++ b/tempest/api/identity/admin/v3/test_list_users.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+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_oauth_consumers.py b/tempest/api/identity/admin/v3/test_oauth_consumers.py
new file mode 100644
index 0000000..f06fb8f
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_oauth_consumers.py
@@ -0,0 +1,91 @@
+# Copyright 2017 AT&T 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.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 exceptions
+
+
+class OAUTHConsumersV3Test(base.BaseIdentityV3AdminTest):
+
+    def _create_consumer(self):
+        """Creates a consumer with a random description."""
+        description = data_utils.rand_name('test_create_consumer')
+        consumer = self.oauth_consumers_client.create_consumer(
+            description)['consumer']
+        # cleans up created consumers after tests
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.oauth_consumers_client.delete_consumer,
+                        consumer['id'])
+        return consumer
+
+    @decorators.idempotent_id('c8307ea6-a86c-47fd-ae7b-5b3b2caca76d')
+    def test_create_and_show_consumer(self):
+        """Tests to make sure that a consumer with parameters is made"""
+        consumer = self._create_consumer()
+        # fetch created consumer from client
+        fetched_consumer = self.oauth_consumers_client.show_consumer(
+            consumer['id'])['consumer']
+        # assert that the fetched consumer matches the created one and
+        # has all parameters
+        for key in ['description', 'id', 'links']:
+            self.assertEqual(consumer[key], fetched_consumer[key])
+
+    @decorators.idempotent_id('fdfa1b7f-2a31-4354-b2c7-f6ae20554f93')
+    def test_delete_consumer(self):
+        """Tests the delete function."""
+        consumer = self._create_consumer()
+        # fetch consumer from client to confirm it exists
+        fetched_consumer = self.oauth_consumers_client.show_consumer(
+            consumer['id'])['consumer']
+        self.assertEqual(consumer['id'], fetched_consumer['id'])
+        # delete existing consumer
+        self.oauth_consumers_client.delete_consumer(consumer['id'])
+        # check that consumer no longer exists
+        self.assertRaises(exceptions.NotFound,
+                          self.oauth_consumers_client.show_consumer,
+                          consumer['id'])
+
+    @decorators.idempotent_id('080a9b1a-c009-47c0-9979-5305bf72e3dc')
+    def test_update_consumer(self):
+        """Tests the update functionality"""
+        # create a new consumer to update
+        consumer = self._create_consumer()
+        # create new description
+        new_description = data_utils.rand_name('test_update_consumer')
+        # update consumer
+        self.oauth_consumers_client.update_consumer(consumer['id'],
+                                                    new_description)
+        # check that the same consumer now has the new description
+        updated_consumer = self.oauth_consumers_client.show_consumer(
+            consumer['id'])['consumer']
+        self.assertEqual(new_description, updated_consumer['description'])
+
+    @decorators.idempotent_id('09ca50de-78f2-4ffb-ac71-f2254036b2b8')
+    def test_list_consumers(self):
+        """Test for listing consumers"""
+        # create two consumers to populate list
+        new_consumer_one = self._create_consumer()
+        new_consumer_two = self._create_consumer()
+        # fetch the list of consumers
+        consumer_list = self.oauth_consumers_client \
+                            .list_consumers()['consumers']
+        # add fetched consumer ids to a list
+        id_list = [consumer['id'] for consumer in consumer_list]
+        # check if created consumers are in the list
+        self.assertIn(new_consumer_one['id'], id_list)
+        self.assertIn(new_consumer_two['id'], id_list)
diff --git a/tempest/api/identity/admin/v3/test_policies.py b/tempest/api/identity/admin/v3/test_policies.py
index 3b5e5d4..f74cb1c 100644
--- a/tempest/api/identity/admin/v3/test_policies.py
+++ b/tempest/api/identity/admin/v3/test_policies.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+from tempest.lib.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..258581b 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -13,19 +13,17 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
 from tempest import config
-from tempest import test
+from tempest.lib.common.utils import data_utils
+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 +40,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()
@@ -57,9 +55,7 @@
         self.assertEqual(project_name, body['name'])
         self.assertEqual(domain['id'], body['domain_id'])
 
-    @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 +84,29 @@
         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')
+    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 +120,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 +135,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 +157,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 +180,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 +204,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..31e7302 100644
--- a/tempest/api/identity/admin/v3/test_projects_negative.py
+++ b/tempest/api/identity/admin/v3/test_projects_negative.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+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
 
@@ -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 95894a6..56ee496 100644
--- a/tempest/api/identity/admin/v3/test_regions.py
+++ b/tempest/api/identity/admin/v3/test_regions.py
@@ -14,8 +14,9 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -30,7 +31,7 @@
     def resource_setup(cls):
         super(RegionsTestJSON, cls).resource_setup()
         cls.setup_regions = list()
-        for i in range(2):
+        for _ in range(2):
             r_description = data_utils.rand_name('description')
             region = cls.client.create_region(
                 description=r_description)['region']
@@ -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..04be00b 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -14,9 +14,15 @@
 #    under the License.
 
 from tempest.api.identity import base
-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 decorators
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
+CONF = config.CONF
+
 
 class RolesV3TestJSON(base.BaseIdentityV3AdminTest):
 
@@ -69,7 +75,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 +98,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 +119,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 +139,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 +174,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 +194,235 @@
         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)
+
+    @decorators.idempotent_id('d92a41d2-5501-497a-84bb-6e294330e8f8')
+    def test_domain_roles_create_delete(self):
+        domain_role = self.roles_client.create_role(
+            name=data_utils.rand_name('domain_role'),
+            domain_id=self.domain['id'])['role']
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.roles_client.delete_role,
+            domain_role['id'])
+
+        domain_roles = self.roles_client.list_roles(
+            domain_id=self.domain['id'])['roles']
+        self.assertEqual(1, len(domain_roles))
+        self.assertIn(domain_role, domain_roles)
+
+        self.roles_client.delete_role(domain_role['id'])
+        domain_roles = self.roles_client.list_roles(
+            domain_id=self.domain['id'])['roles']
+        self.assertEmpty(domain_roles)
+
+    @decorators.idempotent_id('eb1e1c24-1bc4-4d47-9748-e127a1852c82')
+    def test_implied_domain_roles(self):
+        # Create two roles in the same domain
+        domain_role1 = self.setup_test_role(domain_id=self.domain['id'])
+        domain_role2 = self.setup_test_role(domain_id=self.domain['id'])
+
+        # Check if we can create an inference rule from roles in the same
+        # domain
+        self._create_implied_role(domain_role1['id'], domain_role2['id'])
+
+        # Create another role in a different domain
+        domain2 = self.setup_test_domain()
+        domain_role3 = self.setup_test_role(domain_id=domain2['id'])
+
+        # Check if we can create cross domain implied roles
+        self._create_implied_role(domain_role1['id'], domain_role3['id'])
+
+        # Finally, we also should be able to create an implied from a
+        # domain role to a global one
+        self._create_implied_role(domain_role1['id'], self.role['id'])
+
+        if CONF.identity_feature_enabled.forbid_global_implied_dsr:
+            # The contrary is not true: we can't create an inference rule
+            # from a global role to a domain role
+            self.assertRaises(
+                lib_exc.Forbidden,
+                self.roles_client.create_role_inference_rule,
+                self.role['id'],
+                domain_role1['id'])
+
+    @decorators.idempotent_id('3859df7e-5b78-4e4d-b10e-214c8953842a')
+    def test_assignments_for_domain_roles(self):
+        domain_role = self.setup_test_role(domain_id=self.domain['id'])
+
+        # Create a grant using "domain_role"
+        self.roles_client.create_user_role_on_project(
+            self.project['id'], self.user_body['id'], domain_role['id'])
+        self.addCleanup(
+            self.roles_client.delete_role_from_user_on_project,
+            self.project['id'], self.user_body['id'], domain_role['id'])
+
+        # NOTE(rodrigods): Regular roles would appear in the effective
+        # list of role assignments (meaning the role would be returned in
+        # a token) as a result from the grant above. This is not the case
+        # for domain roles, they should not appear in the effective role
+        # assignments list.
+        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.assertEmpty(role_assignments)
+
+    @decorators.idempotent_id('3748c316-c18f-4b08-997b-c60567bc6235')
+    def test_list_all_implied_roles(self):
+        # Create inference rule from "roles[0]" to "roles[1]"
+        self._create_implied_role(
+            self.roles[0]['id'], self.roles[1]['id'])
+
+        # Create inference rule from "roles[0]" to "roles[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'])
+
+        rules = self.roles_client.list_all_role_inference_rules()[
+            'role_inferences']
+        # Sort the rules by the number of inferences, since there should be 1
+        # inference between "roles[2]" and "role" and 2 inferences for
+        # "roles[0]": between "roles[1]" and "roles[2]".
+        sorted_rules = sorted(rules, key=lambda r: len(r['implies']))
+
+        # Check that 2 sets of rules are returned.
+        self.assertEqual(2, len(sorted_rules))
+        # Check that only 1 inference rule exists between "roles[2]" and "role"
+        self.assertEqual(1, len(sorted_rules[0]['implies']))
+        # Check that 2 inference rules exist for "roles[0]": one between
+        # "roles[1]" and one between "roles[2]".
+        self.assertEqual(2, len(sorted_rules[1]['implies']))
+
+        # Check that "roles[2]" is the "prior_role" and that "role" is the
+        # "implies" role.
+        self.assertEqual(self.roles[2]['id'],
+                         sorted_rules[0]['prior_role']['id'])
+        self.assertEqual(self.role['id'],
+                         sorted_rules[0]['implies'][0]['id'])
+
+        # Check that "roles[0]" is the "prior_role" and that "roles[1]" and
+        # "roles[2]" are the "implies" roles.
+        self.assertEqual(self.roles[0]['id'],
+                         sorted_rules[1]['prior_role']['id'])
+
+        implies_ids = [r['id'] for r in sorted_rules[1]['implies']]
+        self.assertIn(self.roles[1]['id'], implies_ids)
+        self.assertIn(self.roles[2]['id'], implies_ids)
diff --git a/tempest/api/identity/admin/v3/test_services.py b/tempest/api/identity/admin/v3/test_services.py
index 2c3cae5..53e005d 100644
--- a/tempest/api/identity/admin/v3/test_services.py
+++ b/tempest/api/identity/admin/v3/test_services.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+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
 
@@ -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..fabb91c 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -16,14 +16,17 @@
 import six
 
 from tempest.api.identity 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
 
 
 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 +52,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.
 
@@ -150,3 +153,34 @@
                          token_auth['token']['project']['id'])
         self.assertEqual(project2['name'],
                          token_auth['token']['project']['name'])
+
+    @decorators.idempotent_id('08ed85ce-2ba8-4864-b442-bcc61f16ae89')
+    def test_get_available_project_scopes(self):
+        manager_project_id = self.manager.credentials.project_id
+        admin_user_id = self.os_adm.credentials.user_id
+        admin_role_id = self.get_role_by_name(CONF.identity.admin_role)['id']
+
+        # Grant the user the role on both projects.
+        self.roles_client.create_user_role_on_project(
+            manager_project_id, admin_user_id, admin_role_id)
+        self.addCleanup(
+            self.roles_client.delete_role_from_user_on_project,
+            manager_project_id, admin_user_id, admin_role_id)
+
+        assigned_project_ids = [self.os_adm.credentials.project_id,
+                                manager_project_id]
+
+        # Get available project scopes
+        available_projects =\
+            self.client.list_auth_projects()['projects']
+
+        # create list to save fetched project's id
+        fetched_project_ids = [i['id'] for i in available_projects]
+
+        # verifying the project ids in list
+        missing_project_ids = \
+            [p for p in assigned_project_ids
+             if p not in fetched_project_ids]
+        self.assertEmpty(missing_project_ids,
+                         "Failed to find project_id %s in fetched list" %
+                         ', '.join(missing_project_ids))
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index 4e69de8..ec64e0c 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -18,8 +18,9 @@
 from tempest.api.identity import base
 from tempest import clients
 from tempest.common import credentials_factory as common_creds
-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
 
@@ -45,21 +46,21 @@
 
     def create_trustor_and_roles(self):
         # create a project that trusts will be granted on
-        self.trustor_project_name = data_utils.rand_name(name='project')
+        trustor_project_name = data_utils.rand_name(name='project')
         project = self.projects_client.create_project(
-            self.trustor_project_name, domain_id='default')['project']
+            trustor_project_name, domain_id='default')['project']
         self.trustor_project_id = project['id']
         self.assertIsNotNone(self.trustor_project_id)
 
         # Create a trustor User
-        self.trustor_username = data_utils.rand_name('user')
-        u_desc = self.trustor_username + 'description'
-        u_email = self.trustor_username + '@testmail.xx'
-        self.trustor_password = data_utils.rand_password()
+        trustor_username = data_utils.rand_name('user')
+        u_desc = trustor_username + 'description'
+        u_email = trustor_username + '@testmail.xx'
+        trustor_password = data_utils.rand_password()
         user = self.users_client.create_user(
-            name=self.trustor_username,
+            name=trustor_username,
             description=u_desc,
-            password=self.trustor_password,
+            password=trustor_password,
             email=u_email,
             project_id=self.trustor_project_id,
             domain_id='default')['user']
@@ -94,10 +95,10 @@
         # Initialize a new client with the trustor credentials
         creds = common_creds.get_credentials(
             identity_version='v3',
-            username=self.trustor_username,
-            password=self.trustor_password,
+            username=trustor_username,
+            password=trustor_password,
             user_domain_id='default',
-            tenant_name=self.trustor_project_name,
+            tenant_name=trustor_project_name,
             project_domain_id='default',
             domain_id='default')
         os = clients.Manager(credentials=creds)
@@ -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 3ec4ff1..0d12ba9 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -18,9 +18,9 @@
 import testtools
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
 from tempest import config
-from tempest import test
+from tempest.lib.common.utils import data_utils
+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()
@@ -125,7 +125,7 @@
 
         user = self.users_client.show_user(user_body['id'])['user']
         role = self.roles_client.show_role(role_body['id'])['role']
-        for i in range(2):
+        for _ in range(2):
             # Creating project so as to assign role
             project_body = self.projects_client.create_project(
                 data_utils.rand_name('project'),
@@ -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..93241c5 100644
--- a/tempest/api/identity/admin/v3/test_users_negative.py
+++ b/tempest/api/identity/admin/v3/test_users_negative.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+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
 
@@ -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/base.py b/tempest/api/identity/base.py
index 14bf4f8..8317535 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -13,8 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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
 import tempest.test
 
 CONF = config.CONF
@@ -67,20 +68,27 @@
             return role[0]
 
     def _create_test_user(self, **kwargs):
-        if kwargs['password'] is None:
+        if kwargs.get('password', None) is None:
             user_password = data_utils.rand_password()
             kwargs['password'] = user_password
         user = self.users_client.create_user(**kwargs)['user']
         # Delete the user at the end of the test
-        self.addCleanup(self.users_client.delete_user, user['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.users_client.delete_user, user['id'])
         return user
 
-    def setup_test_role(self):
+    def setup_test_role(self, domain_id=None):
         """Set up a test role."""
-        role = self.roles_client.create_role(
-            name=data_utils.rand_name('test_role'))['role']
+        params = {'name': data_utils.rand_name('test_role')}
+        if domain_id:
+            params['domain_id'] = domain_id
+
+        role = self.roles_client.create_role(**params)['role']
         # Delete the role at the end of the test
-        self.addCleanup(self.roles_client.delete_role, role['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.roles_client.delete_role, role['id'])
         return role
 
 
@@ -105,6 +113,15 @@
 
     credentials = ['primary', 'admin']
 
+    # NOTE(andreaf) Identity tests work with credentials, so it is safer
+    # for them to always use disposable credentials. Forcing dynamic creds
+    # on regular identity tests would be however to restrictive, since it
+    # would prevent any identity test from being executed against clouds where
+    # admin credentials are not available.
+    # Since All admin tests require admin credentials to be
+    # executed, so this will not impact the ability to execute tests.
+    force_tenant_isolation = True
+
     @classmethod
     def setup_clients(cls):
         super(BaseIdentityV2AdminTest, cls).setup_clients()
@@ -140,7 +157,9 @@
             name=data_utils.rand_name('test_tenant'),
             description=data_utils.rand_name('desc'))['tenant']
         # Delete the tenant at the end of the test
-        self.addCleanup(self.tenants_client.delete_tenant, tenant['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.tenants_client.delete_tenant, tenant['id'])
         return tenant
 
 
@@ -159,12 +178,22 @@
         cls.non_admin_users_client = cls.os.users_v3_client
         cls.non_admin_token = cls.os.token_v3_client
         cls.non_admin_projects_client = cls.os.projects_client
+        cls.non_admin_versions_client = cls.os.identity_versions_v3_client
 
 
 class BaseIdentityV3AdminTest(BaseIdentityV3Test):
 
     credentials = ['primary', 'admin']
 
+    # NOTE(andreaf) Identity tests work with credentials, so it is safer
+    # for them to always use disposable credentials. Forcing dynamic creds
+    # on regular identity tests would be however to restrictive, since it
+    # would prevent any identity test from being executed against clouds where
+    # admin credentials are not available.
+    # Since All admin tests require admin credentials to be
+    # executed, so this will not impact the ability to execute tests.
+    force_tenant_isolation = True
+
     @classmethod
     def setup_clients(cls):
         super(BaseIdentityV3AdminTest, cls).setup_clients()
@@ -183,6 +212,7 @@
         cls.groups_client = cls.os_adm.groups_client
         cls.projects_client = cls.os_adm.projects_client
         cls.role_assignments = cls.os_admin.role_assignments_client
+        cls.oauth_consumers_client = cls.os_adm.oauth_consumers_client
         if CONF.identity.admin_domain_scope:
             # NOTE(andreaf) When keystone policy requires it, the identity
             # admin clients for these tests shall use 'domain' scoped tokens.
@@ -225,12 +255,16 @@
             name=data_utils.rand_name('test_project'),
             description=data_utils.rand_name('desc'))['project']
         # Delete the project at the end of the test
-        self.addCleanup(self.projects_client.delete_project, project['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.projects_client.delete_project, project['id'])
         return project
 
     def setup_test_domain(self):
         """Set up a test domain."""
         domain = self.create_domain()
         # Delete the domain at the end of the test
-        self.addCleanup(self.delete_domain, domain['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.delete_domain, domain['id'])
         return domain
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/test_extension.py b/tempest/api/identity/v2/test_extension.py
similarity index 86%
rename from tempest/api/identity/test_extension.py
rename to tempest/api/identity/v2/test_extension.py
index 01e5661..c538c14 100644
--- a/tempest/api/identity/test_extension.py
+++ b/tempest/api/identity/v2/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):
+class ExtensionTestJSON(base.BaseIdentityV2Test):
 
-    @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_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 bafb1f2..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
@@ -58,7 +58,7 @@
         if CONF.identity_feature_enabled.security_compliance:
             # First we need to clear the password history
             unique_count = CONF.identity.user_unique_last_password_count
-            for i in range(unique_count):
+            for _ in range(unique_count):
                 random_pass = data_utils.rand_password()
                 self._update_password(
                     user_id, original_password=new_pass, password=random_pass)
@@ -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..177a49d 100644
--- a/tempest/api/identity/v3/test_api_discovery.py
+++ b/tempest/api/identity/v3/test_api_discovery.py
@@ -14,14 +14,29 @@
 #    under the License.
 
 from tempest.api.identity import base
+from tempest.lib import decorators
 from tempest import test
 
 
 class TestApiDiscovery(base.BaseIdentityV3Test):
     """Tests for API discovery features."""
 
+    @decorators.idempotent_id('721f480f-35b6-46c7-846e-047e6acea0dc')
     @test.attr(type='smoke')
-    @test.idempotent_id('b9232f5e-d9e5-4d97-b96c-28d3db4de1bd')
+    def test_list_api_versions(self):
+        # NOTE: Actually this API doesn't depend on v3 API at all, because
+        # the API operation is "GET /" without v3's endpoint. The reason of
+        # this test path is just v3 API is CURRENT on Keystone side.
+        versions = self.non_admin_versions_client.list_versions()
+        expected_resources = ('id', 'links', 'media-types', 'status',
+                              'updated')
+
+        for version in versions['versions']["values"]:
+            for res in expected_resources:
+                self.assertIn(res, version)
+
+    @test.attr(type='smoke')
+    @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 +47,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 +62,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 f5b357c..e7998ee 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
@@ -34,8 +34,6 @@
         super(IdentityV3UsersTest, cls).resource_setup()
         cls.creds = cls.os.credentials
         cls.user_id = cls.creds.user_id
-        cls.username = cls.creds.username
-        cls.password = cls.creds.password
 
     def _update_password(self, original_password, password):
         self.non_admin_users_client.update_user_password(
@@ -60,7 +58,7 @@
         if CONF.identity_feature_enabled.security_compliance:
             # First we need to clear the password history
             unique_count = CONF.identity.user_unique_last_password_count
-            for i in range(unique_count):
+            for _ in range(unique_count):
                 random_pass = data_utils.rand_password()
                 self._update_password(
                     original_password=new_pass, password=random_pass)
@@ -78,7 +76,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 +101,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 +131,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
 
@@ -142,7 +140,7 @@
 
         # Lock user account by using the wrong password to login
         bad_password = data_utils.rand_password()
-        for i in range(CONF.identity.user_lockout_failure_attempts):
+        for _ in range(CONF.identity.user_lockout_failure_attempts):
             self.assertRaises(exceptions.Unauthorized,
                               self.non_admin_token.auth,
                               user_id=self.user_id,
@@ -157,4 +155,4 @@
 
         # If we wait the required time, the user account will be unlocked
         time.sleep(CONF.identity.user_lockout_duration + 1)
-        self.token.auth(user_id=self.user_id, password=password)
+        self.non_admin_token.auth(user_id=self.user_id, password=password)
diff --git a/tempest/api/image/admin/v2/test_images.py b/tempest/api/image/admin/v2/test_images.py
index f22f321..fc5ed79 100644
--- a/tempest/api/image/admin/v2/test_images.py
+++ b/tempest/api/image/admin/v2/test_images.py
@@ -19,8 +19,8 @@
 from tempest.api.image import 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
 
 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/base.py b/tempest/api/image/base.py
index 812c436..c586960 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -15,8 +15,8 @@
 import six
 
 from tempest.common import image as common_image
-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
 import tempest.test
 
@@ -142,7 +142,10 @@
         cls.namespaces_client = cls.os.namespaces_client
         cls.resource_types_client = cls.os.resource_types_client
         cls.namespace_properties_client = cls.os.namespace_properties_client
+        cls.namespace_objects_client = cls.os.namespace_objects_client
+        cls.namespace_tags_client = cls.os.namespace_tags_client
         cls.schemas_client = cls.os.schemas_client
+        cls.versions_client = cls.os.image_versions_client
 
     def create_namespace(cls, namespace_name=None, visibility='public',
                          description='Tempest', protected=False,
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..f075cab 100644
--- a/tempest/api/image/v1/test_image_members_negative.py
+++ b/tempest/api/image/v1/test_image_members_negative.py
@@ -13,7 +13,8 @@
 #    under the License.
 
 from tempest.api.image import base
-from tempest.common.utils import data_utils
+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
 
@@ -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 0caaa67..b341ab7 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -17,11 +17,11 @@
 
 from tempest.api.image import base
 from tempest.common import image as common_image
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 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
 
@@ -30,13 +30,23 @@
     a_formats = ['ami', 'ari', 'aki']
 
     container_format = CONF.image.container_formats[0]
-    disk_format = CONF.image.disk_formats[0]
 
-    if container_format in a_formats and container_format != disk_format:
-        msg = ("The container format and the disk format don't match. "
-               "Container format: %(container)s, Disk format: %(disk)s." %
-               {'container': container_format, 'disk': disk_format})
-        raise exceptions.InvalidConfiguration(msg)
+    # In v1, If container_format is one of ['ami', 'ari', 'aki'], then
+    # disk_format must be same with container_format.
+    # If they are of different item sequence in tempest.conf, such as:
+    #     container_formats = ami,ari,aki,bare
+    #     disk_formats = ari,ami,aki,vhd
+    # we can select one in disk_format list that is same with container_format.
+    if container_format in a_formats:
+        if container_format in CONF.image.disk_formats:
+            disk_format = container_format
+        else:
+            msg = ("The container format and the disk format don't match. "
+                   "Container format: %(container)s, Disk format: %(disk)s." %
+                   {'container': container_format, 'disk': disk_format})
+            raise exceptions.InvalidConfiguration(msg)
+    else:
+        disk_format = CONF.image.disk_formats[0]
 
     return container_format, disk_format
 
@@ -44,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'}
@@ -66,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()
@@ -83,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',
@@ -95,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()
@@ -135,24 +145,24 @@
         a_formats = ['ami', 'ari', 'aki']
 
         (cls.container_format,
-         cls.container_format_alt) = CONF.image.container_formats[:2]
+         container_format_alt) = CONF.image.container_formats[:2]
         cls.disk_format, cls.disk_format_alt = CONF.image.disk_formats[:2]
         if cls.container_format in a_formats:
             cls.disk_format = cls.container_format
-        if cls.container_format_alt in a_formats:
-            cls.disk_format_alt = cls.container_format_alt
+        if container_format_alt in a_formats:
+            cls.disk_format_alt = container_format_alt
 
         img1 = cls._create_remote_image('one', cls.container_format,
                                         cls.disk_format)
-        img2 = cls._create_remote_image('two', cls.container_format_alt,
+        img2 = cls._create_remote_image('two', container_format_alt,
                                         cls.disk_format_alt)
         img3 = cls._create_remote_image('dup', cls.container_format,
                                         cls.disk_format)
         img4 = cls._create_remote_image('dup', cls.container_format,
                                         cls.disk_format)
-        img5 = cls._create_standard_image('1', cls.container_format_alt,
+        img5 = cls._create_standard_image('1', container_format_alt,
                                           cls.disk_format_alt, 42)
-        img6 = cls._create_standard_image('2', cls.container_format_alt,
+        img6 = cls._create_standard_image('2', container_format_alt,
                                           cls.disk_format_alt, 142)
         img7 = cls._create_standard_image('33', cls.container_format,
                                           cls.disk_format, 142)
@@ -200,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']
@@ -208,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']
@@ -219,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']
@@ -230,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:
@@ -239,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:
@@ -248,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',
@@ -261,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,
@@ -295,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)
@@ -303,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 d8f103a..42ff02f 100644
--- a/tempest/api/image/v1/test_images_negative.py
+++ b/tempest/api/image/v1/test_images_negative.py
@@ -15,6 +15,8 @@
 
 
 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
 
@@ -23,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,
@@ -32,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',
@@ -40,37 +42,38 @@
                                    '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
 
-        non_existent_image_id = '11a22b9-12a9-5555-cc11-00ab112223fa'
+        non_existent_image_id = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound, self.client.delete_image,
                           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
-        image_id = '11a22b9-120q-5555-cc11-00ab112223gj'
+        invalid_image_id = data_utils.rand_uuid()[:-1] + "j"
         self.assertRaises(lib_exc.NotFound, self.client.delete_image,
-                          image_id)
+                          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')
-    def test_delete_image_id_is_over_35_character_limit(self):
+    @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"
         self.assertRaises(lib_exc.NotFound, self.client.delete_image,
-                          '11a22b9-12a9-5555-cc11-00ab112223fa-3fac')
+                          overlimit_image_id)
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 453bb34..30f9ae2 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -20,8 +20,9 @@
 
 from oslo_log import log as logging
 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 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
 
@@ -126,11 +127,12 @@
         self.assertEqual(new_image_name, body['name'])
 
 
-class ListImagesTest(base.BaseV2ImageTest):
+class ListUserImagesTest(base.BaseV2ImageTest):
+    """Here we test the listing of image information"""
 
     @classmethod
     def resource_setup(cls):
-        super(ListImagesTest, cls).resource_setup()
+        super(ListUserImagesTest, cls).resource_setup()
         # We add a few images here to test the listing functionality of
         # the images API
         container_fmts = CONF.image.container_formats
@@ -162,14 +164,9 @@
         cls.client.store_image_file(image['id'], data=image_file)
         # Keep the data of one test image so it can be used to filter lists
         cls.test_data = image
-        cls.test_data['size'] = size
 
         return image['id']
 
-
-class ListUserImagesTest(ListImagesTest):
-    """Here we test the listing of image information"""
-
     def _list_by_param_value_and_assert(self, params):
         """Perform list action with given params and validates result."""
         # Retrieve the list of images that meet the filter
@@ -197,7 +194,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']
@@ -206,25 +203,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]
@@ -234,7 +231,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]
@@ -252,13 +249,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}
@@ -267,7 +264,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]
@@ -277,13 +274,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]}
@@ -298,24 +295,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"
@@ -323,7 +320,7 @@
         self.assertEqual("images", body['name'])
 
 
-class ListSharedImagesTest(ListImagesTest):
+class ListSharedImagesTest(base.BaseV2ImageTest):
     """Here we test the listing of a shared image information"""
 
     credentials = ['primary', 'alt']
@@ -334,19 +331,24 @@
         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):
-        # Share one of the images created with the alt user
+        # Create an image to be shared using default visibility
+        image_file = six.BytesIO(data_utils.random_bytes(2048))
+        container_format = CONF.image.container_formats[0]
+        disk_format = CONF.image.disk_formats[0]
+        image = self.create_image(container_format=container_format,
+                                  disk_format=disk_format)
+        self.client.store_image_file(image['id'], data=image_file)
+
+        # Share the image created with the alt user
         self.image_member_client.create_image_member(
-            image_id=self.test_data['id'],
-            member=self.alt_img_client.tenant_id)
-        # Update the info on the test data so it remains accurate
-        self.test_data['updated_at'] = self.client.show_image(
-            self.test_data['id'])['updated_at']
+            image_id=image['id'], member=self.alt_img_client.tenant_id)
+
         # As an image consumer you need to provide the member_status parameter
         # along with the visibility=shared parameter in order for it to show
         # results
         params = {'member_status': 'pending', 'visibility': 'shared'}
         fetched_images = self.alt_img_client.list_images(params)['images']
         self.assertEqual(1, len(fetched_images))
-        self.assertEqual(self.test_data['id'], fetched_images[0]['id'])
+        self.assertEqual(image['id'], fetched_images[0]['id'])
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
new file mode 100644
index 0000000..80f8112
--- /dev/null
+++ b/tempest/api/image/v2/test_images_metadefs_namespace_objects.py
@@ -0,0 +1,73 @@
+#    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.api.image import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+
+class MetadataNamespaceObjectsTest(base.BaseV2ImageTest):
+    """Test the Metadata definition namespace objects basic functionality"""
+
+    def _create_namespace_object(self, namespace):
+        object_name = data_utils.rand_name(self.__class__.__name__ + '-object')
+        namespace_object = self.namespace_objects_client.\
+            create_namespace_object(namespace['namespace'], name=object_name)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.namespace_objects_client.delete_namespace_object,
+                        namespace['namespace'], object_name)
+        return namespace_object
+
+    @decorators.idempotent_id('b1a3775e-3b5c-4f6a-a3b4-1ba3574ae718')
+    def test_create_update_delete_meta_namespace_objects(self):
+        # Create a namespace
+        namespace = self.create_namespace()
+        # Create a namespace object
+        body = self._create_namespace_object(namespace)
+        # Update a namespace object
+        up_object_name = data_utils.rand_name('update-object')
+        body = self.namespace_objects_client.update_namespace_object(
+            namespace['namespace'], body['name'],
+            name=up_object_name)
+        self.assertEqual(up_object_name, body['name'])
+        # Delete a namespace object
+        self.namespace_objects_client.delete_namespace_object(
+            namespace['namespace'], up_object_name)
+        # List namespace objects and validate deletion
+        namespace_objects = [
+            namespace_object['name'] for namespace_object in
+            self.namespace_objects_client.list_namespace_objects(
+                namespace['namespace'])['objects']]
+        self.assertNotIn(up_object_name, namespace_objects)
+
+    @decorators.idempotent_id('a2a3615e-3b5c-3f6a-a2b1-1ba3574ae738')
+    def test_list_meta_namespace_objects(self):
+        # Create a namespace object
+        namespace = self.create_namespace()
+        meta_namespace_object = self._create_namespace_object(namespace)
+        # List namespace objects
+        namespace_objects = [
+            namespace_object['name'] for namespace_object in
+            self.namespace_objects_client.list_namespace_objects(
+                namespace['namespace'])['objects']]
+        self.assertIn(meta_namespace_object['name'], namespace_objects)
+
+    @decorators.idempotent_id('b1a3674e-3b4c-3f6a-a3b4-1ba3573ca768')
+    def test_show_meta_namespace_objects(self):
+        # Create a namespace object
+        namespace = self.create_namespace()
+        namespace_object = self._create_namespace_object(namespace)
+        # Show a namespace object
+        body = self.namespace_objects_client.show_namespace_object(
+            namespace['namespace'], namespace_object['name'])
+        self.assertEqual(namespace_object['name'], body['name'])
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..ed91726 100644
--- a/tempest/api/image/v2/test_images_metadefs_namespace_properties.py
+++ b/tempest/api/image/v2/test_images_metadefs_namespace_properties.py
@@ -11,14 +11,14 @@
 #    under the License.
 
 from tempest.api.image import base
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+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
new file mode 100644
index 0000000..e2a3617
--- /dev/null
+++ b/tempest/api/image/v2/test_images_metadefs_namespace_tags.py
@@ -0,0 +1,90 @@
+#    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.api.image import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+
+class MetadataNamespaceTagsTest(base.BaseV2ImageTest):
+    """Test the Metadata definition namespace tags basic functionality"""
+
+    tags = [
+        {
+            "name": "sample-tag1"
+        },
+        {
+            "name": "sample-tag2"
+        },
+        {
+            "name": "sample-tag3"
+        }
+    ]
+    tag_list = ["sample-tag1", "sample-tag2", "sample-tag3"]
+
+    def _create_namespace_tags(self, namespace):
+        # Create a namespace
+        namespace_tags = self.namespace_tags_client.create_namespace_tags(
+            namespace['namespace'], tags=self.tags)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.namespace_tags_client.delete_namespace_tags,
+                        namespace['namespace'])
+        return namespace_tags
+
+    @decorators.idempotent_id('a2a3765e-3a6d-4f6d-a3a7-3cc3476aa876')
+    def test_create_list_delete_namespace_tags(self):
+        # Create a namespace
+        namespace = self.create_namespace()
+        self._create_namespace_tags(namespace)
+        # List namespace tags
+        body = self.namespace_tags_client.list_namespace_tags(
+            namespace['namespace'])
+        self.assertTrue(3, len(body['tags']))
+        self.assertIn(body['tags'][0]['name'], self.tag_list)
+        self.assertIn(body['tags'][1]['name'], self.tag_list)
+        self.assertIn(body['tags'][2]['name'], self.tag_list)
+        # Delete all tag definitions
+        self.namespace_tags_client.delete_namespace_tags(
+            namespace['namespace'])
+        body = self.namespace_tags_client.list_namespace_tags(
+            namespace['namespace'])
+        self.assertEqual([], body['tags'])
+
+    @decorators.idempotent_id('a2a3765e-1a2c-3f6d-a3a7-3cc3466ab875')
+    def test_create_update_delete_tag(self):
+        # Create a namespace
+        namespace = self.create_namespace()
+        self._create_namespace_tags(namespace)
+        # Create a tag
+        tag_name = data_utils.rand_name('tag_name')
+        self.namespace_tags_client.create_namespace_tag(
+            namespace=namespace['namespace'], tag_name=tag_name)
+
+        body = self.namespace_tags_client.show_namespace_tag(
+            namespace['namespace'], tag_name)
+        self.assertEqual(tag_name, body['name'])
+        # Update tag definition
+        update_tag_definition = data_utils.rand_name('update-tag')
+        body = self.namespace_tags_client.update_namespace_tag(
+            namespace['namespace'], tag_name=tag_name,
+            name=update_tag_definition)
+        self.assertEqual(update_tag_definition, body['name'])
+        # Delete tag definition
+        self.namespace_tags_client.delete_namespace_tag(
+            namespace['namespace'], update_tag_definition)
+        # List namespace tags and validate deletion
+        namespace_tags = [
+            namespace_tag['name'] for namespace_tag in
+            self.namespace_tags_client.list_namespace_tags(
+                namespace['namespace'])['tags']]
+        self.assertNotIn(update_tag_definition, namespace_tags)
diff --git a/tempest/api/image/v2/test_images_metadefs_namespaces.py b/tempest/api/image/v2/test_images_metadefs_namespaces.py
index a80a0cf..f71b16c 100644
--- a/tempest/api/image/v2/test_images_metadefs_namespaces.py
+++ b/tempest/api/image/v2/test_images_metadefs_namespaces.py
@@ -14,16 +14,16 @@
 #    under the License.
 
 from tempest.api.image import base
-from tempest.common.utils import data_utils
+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 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..6e5e726 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,8 +93,21 @@
                           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',
                           disk_format='wrong')
+
+    @test.attr(type=['negative'])
+    @decorators.idempotent_id('ab980a34-8410-40eb-872b-f264752f46e5')
+    def test_delete_protected_image(self):
+        # Create a protected image
+        image = self.create_image(protected=True)
+        self.addCleanup(self.client.update_image, image['id'],
+                        [dict(replace="/protected", value=False)])
+
+        # Try deleting the protected image
+        self.assertRaises(lib_exc.Forbidden,
+                          self.client.delete_image,
+                          image['id'])
diff --git a/tempest/api/image/v2/test_images_tags.py b/tempest/api/image/v2/test_images_tags.py
index 03f29bd..601826e 100644
--- a/tempest/api/image/v2/test_images_tags.py
+++ b/tempest/api/image/v2/test_images_tags.py
@@ -13,13 +13,13 @@
 # under the License.
 
 from tempest.api.image import base
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+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..7032dd4 100644
--- a/tempest/api/image/v2/test_images_tags_negative.py
+++ b/tempest/api/image/v2/test_images_tags_negative.py
@@ -13,7 +13,8 @@
 # under the License.
 
 from tempest.api.image import base
-from tempest.common.utils import data_utils
+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
 
@@ -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/image/v2/test_versions.py b/tempest/api/image/v2/test_versions.py
new file mode 100644
index 0000000..24f104c
--- /dev/null
+++ b/tempest/api/image/v2/test_versions.py
@@ -0,0 +1,30 @@
+# Copyright 2017 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.api.image import base
+from tempest.lib import decorators
+from tempest import test
+
+
+class VersionsTest(base.BaseV2ImageTest):
+
+    @decorators.idempotent_id('659ea30a-a17c-4317-832c-0f68ed23c31d')
+    @test.attr(type='smoke')
+    def test_list_versions(self):
+        versions = self.versions_client.list_versions()['versions']
+        expected_resources = ('id', 'links', 'status')
+
+        for version in versions:
+            for res in expected_resources:
+                self.assertIn(res, version)
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..485c8f5 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
 
 
@@ -31,15 +32,15 @@
         # Create a network and make sure it will be hosted by a
         # dhcp agent: this is done by creating a regular port
         cls.network = cls.create_network()
-        cls.subnet = cls.create_subnet(cls.network)
+        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..c83dd7f 100644
--- a/tempest/api/network/admin/test_external_network_extension.py
+++ b/tempest/api/network/admin/test_external_network_extension.py
@@ -11,9 +11,9 @@
 #    under the License.
 
 from tempest.api.network import base
-from tempest.common.utils import data_utils
+from tempest.lib.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..770d91f 100644
--- a/tempest/api/network/admin/test_external_networks_negative.py
+++ b/tempest/api/network/admin/test_external_networks_negative.py
@@ -12,10 +12,12 @@
 #    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 testtools
 
 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 +27,9 @@
 class ExternalNetworksAdminNegativeTestJSON(base.BaseAdminNetworkTest):
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('d402ae6c-0be0-4d8e-833b-a738895d98d0')
+    @decorators.idempotent_id('d402ae6c-0be0-4d8e-833b-a738895d98d0')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     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..9a17817 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
@@ -30,6 +31,9 @@
         if not test.is_extension_enabled('router', 'network'):
             msg = "router extension not enabled."
             raise cls.skipException(msg)
+        if not CONF.network.public_network_id:
+            msg = "The public_network_id option must be specified."
+            raise cls.skipException(msg)
 
     @classmethod
     def setup_clients(cls):
@@ -42,12 +46,12 @@
         cls.ext_net_id = CONF.network.public_network_id
         cls.floating_ip = cls.create_floatingip(cls.ext_net_id)
         cls.network = cls.create_network()
-        cls.subnet = cls.create_subnet(cls.network)
-        cls.router = cls.create_router(external_network_id=cls.ext_net_id)
-        cls.create_router_interface(cls.router['id'], cls.subnet['id'])
+        subnet = cls.create_subnet(cls.network)
+        router = cls.create_router(external_network_id=cls.ext_net_id)
+        cls.create_router_interface(router['id'], 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 +82,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..e7460af 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
 
@@ -27,7 +28,6 @@
 
 class L3AgentSchedulerTestJSON(base.BaseAdminNetworkTest):
     _agent_mode = 'legacy'
-    is_dvr_router = False
 
     """
     Tests the following operations in the Neutron API using the REST client for
@@ -67,47 +67,11 @@
             raise exceptions.InvalidConfiguration(msg)
         cls.router = cls.create_router()
 
-        if CONF.network.dvr_extra_resources:
-            # NOTE(armax): If DVR is an available extension, and the created
-            # router is indeed a distributed one, more resources need to be
-            # provisioned in order to bind the router to the L3 agent in the
-            # Liberty release or older, and are not required since the Mitaka
-            # release.
-            if test.is_extension_enabled('dvr', 'network'):
-                cls.is_dvr_router = cls.admin_routers_client.show_router(
-                    cls.router['id'])['router'].get('distributed', False)
-                if cls.is_dvr_router:
-                    cls.network = cls.create_network()
-                    cls.subnet = cls.create_subnet(cls.network)
-                    cls.port = cls.create_port(cls.network)
-                    cls.routers_client.add_router_interface(
-                        cls.router['id'], port_id=cls.port['id'])
-                    # NOTE: Sometimes we have seen this test fail with dvr in,
-                    # multinode tests, since the dhcp port is not created
-                    # before the test gets executed and so the router is not
-                    # scheduled on the given agent. By adding the external
-                    # gateway info to the router, the router should be properly
-                    # scheduled in the dvr_snat node. This is a temporary work
-                    # around to prevent a race condition.
-                    external_gateway_info = {
-                        'network_id': CONF.network.public_network_id,
-                        'enable_snat': True}
-                    cls.admin_routers_client.update_router(
-                        cls.router['id'],
-                        external_gateway_info=external_gateway_info)
-
-    @classmethod
-    def resource_cleanup(cls):
-        if cls.is_dvr_router:
-            cls.routers_client.remove_router_interface(cls.router['id'],
-                                                       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 c256b5b..2c639da 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,8 @@
             msg = "quotas extension not enabled."
             raise cls.skipException(msg)
 
-    @test.idempotent_id('644f4e1b-1bf9-4af0-9fd8-eb56ac0f51cf')
+    @test.attr(type=['negative'])
+    @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,
@@ -57,8 +59,7 @@
         # Try to create a third network while the quota is two
         with self.assertRaisesRegex(
                 lib_exc.Conflict,
-                "An object with that identifier already exists\\n" +
-                "Details.*Quota exceeded for resources: \['network'\].*"):
+                "Quota exceeded for resources: \['network'\].*"):
             n3 = self.networks_client.create_network()
             self.addCleanup(self.networks_client.delete_network,
                             n3['network']['id'])
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 978fb8f..aa8b2dc 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -13,11 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import six
-
 from tempest.api.network import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -57,7 +56,7 @@
             project_id, **new_quotas)['quota']
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.admin_quotas_client.reset_quotas, project_id)
-        for key, value in six.iteritems(new_quotas):
+        for key, value in new_quotas.items():
             self.assertEqual(value, quota_set[key])
 
         # Confirm our project is listed among projects with non default quotas
@@ -71,7 +70,7 @@
         # Confirm from API quotas were changed as requested for project
         quota_set = self.admin_quotas_client.show_quotas(project_id)
         quota_set = quota_set['quota']
-        for key, value in six.iteritems(new_quotas):
+        for key, value in new_quotas.items():
             self.assertEqual(value, quota_set[key])
 
         # Reset quotas to default and confirm
@@ -80,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..4ccad30 100644
--- a/tempest/api/network/admin/test_routers_dvr.py
+++ b/tempest/api/network/admin/test_routers_dvr.py
@@ -16,7 +16,8 @@
 import testtools
 
 from tempest.api.network import base_routers as base
-from tempest.common.utils import data_utils
+from tempest.lib.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.py b/tempest/api/network/base.py
index c2c42bb..a724dc9 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -15,9 +15,9 @@
 
 import netaddr
 
-from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
+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
@@ -108,10 +108,10 @@
             # Not all classes in the hierarchy have the client class variable
             if len(cls.metering_label_rules) > 0:
                 label_rules_client = cls.admin_metering_label_rules_client
-            for metering_label_rule in cls.metering_label_rules:
-                test_utils.call_and_ignore_notfound_exc(
-                    label_rules_client.delete_metering_label_rule,
-                    metering_label_rule['id'])
+                for metering_label_rule in cls.metering_label_rules:
+                    test_utils.call_and_ignore_notfound_exc(
+                        label_rules_client.delete_metering_label_rule,
+                        metering_label_rule['id'])
             # Clean up metering labels
             for metering_label in cls.metering_labels:
                 test_utils.call_and_ignore_notfound_exc(
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/base_security_groups.py b/tempest/api/network/base_security_groups.py
index 3ea3aea..b8d677a 100644
--- a/tempest/api/network/base_security_groups.py
+++ b/tempest/api/network/base_security_groups.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.api.network import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
 
 
 class BaseSecGroupTest(base.BaseNetworkTest):
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 84c48ec..a7ae765 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -13,17 +13,16 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import netaddr
 import random
 
-import six
+import netaddr
 
 from tempest.api.network import base
-from tempest.common.utils import data_utils
 from tempest.common.utils import net_info
 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
 
@@ -97,7 +96,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
@@ -115,7 +114,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
@@ -126,7 +125,7 @@
         ):
             kwargs = {'ipv6_ra_mode': ra_mode,
                       'ipv6_address_mode': add_mode}
-            kwargs = dict((k, v) for k, v in six.iteritems(kwargs) if v)
+            kwargs = dict((k, v) for k, v in kwargs.items() if v)
             real_ip, eui_ip = self._get_ips_from_subnet(**kwargs)
             self._clean_network()
             self.assertEqual(eui_ip, real_ip,
@@ -136,7 +135,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 (
@@ -154,7 +153,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.
@@ -166,7 +165,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
@@ -215,7 +214,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
@@ -258,7 +257,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.
@@ -269,7 +268,7 @@
         ):
             kwargs = {'ipv6_ra_mode': ra_mode,
                       'ipv6_address_mode': add_mode}
-            kwargs = dict((k, v) for k, v in six.iteritems(kwargs) if v)
+            kwargs = dict((k, v) for k, v in kwargs.items() if v)
             subnet = self.create_subnet(self.network, **kwargs)
             port = self.create_port(self.network)
             port_ip = next(iter(port['fixed_ips']), None)['ip_address']
@@ -279,7 +278,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
@@ -291,7 +290,7 @@
         ):
             kwargs = {'ipv6_ra_mode': ra_mode,
                       'ipv6_address_mode': add_mode}
-            kwargs = dict((k, v) for k, v in six.iteritems(kwargs) if v)
+            kwargs = dict((k, v) for k, v in kwargs.items() if v)
             subnet = self.create_subnet(self.network, **kwargs)
             ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
                                        subnet["allocation_pools"][0]["end"])
@@ -307,7 +306,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.
@@ -324,7 +323,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.
@@ -340,7 +339,7 @@
                              {'subnet_id': subnet['id'],
                               'ip_address': ip}])
         self.assertRaisesRegex(lib_exc.Conflict,
-                               "object with that identifier already exists",
+                               "IpAddressAlreadyAllocated|IpAddressInUse",
                                self.create_port,
                                self.network,
                                fixed_ips=[{'subnet_id': subnet['id'],
@@ -354,7 +353,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.
@@ -364,7 +363,7 @@
         ):
             kwargs = {'ipv6_ra_mode': ra_mode,
                       'ipv6_address_mode': add_mode}
-            kwargs = dict((k, v) for k, v in six.iteritems(kwargs) if v)
+            kwargs = dict((k, v) for k, v in kwargs.items() if v)
             subnet, port = self._create_subnet_router(kwargs)
             port_ip = next(iter(port['fixed_ips']), None)['ip_address']
             self._clean_network()
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..dc9042e 100644
--- a/tempest/api/network/test_extra_dhcp_options.py
+++ b/tempest/api/network/test_extra_dhcp_options.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.network import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -42,19 +43,19 @@
     def resource_setup(cls):
         super(ExtraDHCPOptionsTestJSON, cls).resource_setup()
         cls.network = cls.create_network()
-        cls.subnet = cls.create_subnet(cls.network)
+        cls.create_subnet(cls.network)
         cls.port = cls.create_port(cls.network)
-        cls.ip_tftp = ('123.123.123.123' if cls._ip_version == 4
-                       else '2015::dead')
-        cls.ip_server = ('123.123.123.45' if cls._ip_version == 4
-                         else '2015::badd')
+        ip_tftp = ('123.123.123.123' if cls._ip_version == 4
+                   else '2015::dead')
+        ip_server = ('123.123.123.45' if cls._ip_version == 4
+                     else '2015::badd')
         cls.extra_dhcp_opts = [
             {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'},
-            {'opt_value': cls.ip_tftp, 'opt_name': 'tftp-server'},
-            {'opt_value': cls.ip_server, 'opt_name': 'server-ip-address'}
+            {'opt_value': ip_tftp, 'opt_name': 'tftp-server'},
+            {'opt_value': 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..1dc574b 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
@@ -45,6 +46,9 @@
         if not test.is_extension_enabled('router', 'network'):
             msg = "router extension not enabled."
             raise cls.skipException(msg)
+        if not CONF.network.public_network_id:
+            msg = "The public_network_id option must be specified."
+            raise cls.skipException(msg)
 
     @classmethod
     def resource_setup(cls):
@@ -61,7 +65,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 +120,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 +146,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 +172,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 +189,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..cb29d3d 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
 
@@ -36,6 +37,9 @@
         if not test.is_extension_enabled('router', 'network'):
             msg = "router extension not enabled."
             raise cls.skipException(msg)
+        if not CONF.network.public_network_id:
+            msg = "The public_network_id option must be specified."
+            raise cls.skipException(msg)
 
     @classmethod
     def resource_setup(cls):
@@ -43,13 +47,13 @@
         cls.ext_net_id = CONF.network.public_network_id
         # Create a network with a subnet connected to a router.
         cls.network = cls.create_network()
-        cls.subnet = cls.create_subnet(cls.network)
-        cls.router = cls.create_router()
-        cls.create_router_interface(cls.router['id'], cls.subnet['id'])
+        subnet = cls.create_subnet(cls.network)
+        router = cls.create_router()
+        cls.create_router_interface(router['id'], subnet['id'])
         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 +62,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 +72,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..18dccc3 100644
--- a/tempest/api/network/test_metering_extensions.py
+++ b/tempest/api/network/test_metering_extensions.py
@@ -13,7 +13,8 @@
 # under the License.
 
 from tempest.api.network import base
-from tempest.common.utils import data_utils
+from tempest.lib.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 acac22b..fc9f465 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -18,9 +18,10 @@
 
 from tempest.api.network import base
 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 decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -33,7 +34,6 @@
     def resource_setup(cls):
         super(BaseNetworkTestResources, cls).resource_setup()
         cls.network = cls.create_network()
-        cls.name = cls.network['name']
         cls.subnet = cls._create_subnet_with_last_subnet_block(cls.network,
                                                                cls._ip_version)
         cls._subnet_data = {6: {'gateway':
@@ -130,7 +130,7 @@
                                     **kwargs)
         compare_args_full = dict(gateway_ip=gateway, cidr=cidr,
                                  mask_bits=mask_bits, **kwargs)
-        compare_args = dict((k, v) for k, v in six.iteritems(compare_args_full)
+        compare_args = dict((k, v) for k, v in compare_args_full.items()
                             if v is not None)
 
         if 'dns_nameservers' in set(subnet).intersection(compare_args):
@@ -175,7 +175,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 +197,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 +205,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 +221,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 +229,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 +242,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 +252,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 +264,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 +272,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 +282,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 +301,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 +362,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 +391,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 +453,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 +469,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 +504,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 +537,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 +546,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 +555,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 +594,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 +633,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 +643,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..5cb12fe 100644
--- a/tempest/api/network/test_networks_negative.py
+++ b/tempest/api/network/test_networks_negative.py
@@ -15,7 +15,8 @@
 #    under the License.
 
 from tempest.api.network import base
-from tempest.common.utils import data_utils
+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
 
@@ -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..376d4ae 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -21,8 +21,9 @@
 from tempest.api.network import base
 from tempest.api.network import base_security_groups as sec_base
 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 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 f2170ad..8df5248 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -14,11 +14,12 @@
 #    under the License.
 
 import netaddr
-import six
+import testtools
 
 from tempest.api.network import base_routers as 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 import test
 
 CONF = config.CONF
@@ -41,7 +42,9 @@
                            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')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     def test_create_show_list_update_delete_router(self):
         # Create a router
         router = self._create_router(
@@ -70,7 +73,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_')
@@ -87,8 +90,10 @@
                         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')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     def test_create_router_with_default_snat_value(self):
         # Create a router with default snat rule
         router = self._create_router(
@@ -97,8 +102,10 @@
             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')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     def test_create_router_with_snat_explicit(self):
         name = data_utils.rand_name('snat-router')
         # Create a router enabling snat attributes
@@ -116,7 +123,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)
@@ -135,7 +142,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)
@@ -163,7 +170,7 @@
             self.assertIsNone(actual_ext_gw_info)
             return
         # Verify only keys passed in exp_ext_gw_info
-        for k, v in six.iteritems(exp_ext_gw_info):
+        for k, v in exp_ext_gw_info.items():
             self.assertEqual(v, actual_ext_gw_info[k])
 
     def _verify_gateway_port(self, router_id):
@@ -183,7 +190,9 @@
             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')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     def test_update_router_set_gateway(self):
         router = self._create_router()
         self.routers_client.update_router(
@@ -196,8 +205,10 @@
             {'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')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     def test_update_router_set_gateway_with_snat_explicit(self):
         router = self._create_router()
         self.admin_routers_client.update_router(
@@ -211,8 +222,10 @@
              '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')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     def test_update_router_set_gateway_without_snat(self):
         router = self._create_router()
         self.admin_routers_client.update_router(
@@ -226,7 +239,40 @@
              'enable_snat': False})
         self._verify_gateway_port(router['id'])
 
-    @test.idempotent_id('ad81b7ee-4f81-407b-a19c-17e623f763e8')
+    @decorators.idempotent_id('cbe42f84-04c2-11e7-8adb-fa163e4fa634')
+    @test.requires_ext(extension='ext-gw-mode', service='network')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
+    @decorators.skip_because(bug='1676207')
+    def test_create_router_set_gateway_with_fixed_ip(self):
+        # Don't know public_network_address, so at first create address
+        # from public_network and delete
+        port = self.admin_ports_client.create_port(
+            network_id=CONF.network.public_network_id)['port']
+        self.admin_ports_client.delete_port(port_id=port['id'])
+
+        fixed_ip = {
+            'subnet_id': port['fixed_ips'][0]['subnet_id'],
+            'ip_address': port['fixed_ips'][0]['ip_address']
+        }
+        external_gateway_info = {
+            'network_id': CONF.network.public_network_id,
+            'external_fixed_ips': [fixed_ip]
+        }
+
+        # Create a router and set gateway to fixed_ip
+        router = self.admin_routers_client.create_router(
+            external_gateway_info=external_gateway_info)['router']
+        self.addCleanup(self.admin_routers_client.delete_router,
+                        router_id=router['id'])
+        # Examine router's gateway is equal to fixed_ip
+        self.assertEqual(router['external_gateway_info'][
+                         'external_fixed_ips'][0]['ip_address'],
+                         fixed_ip['ip_address'])
+
+    @decorators.idempotent_id('ad81b7ee-4f81-407b-a19c-17e623f763e8')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     def test_update_router_unset_gateway(self):
         router = self._create_router(
             external_network_id=CONF.network.public_network_id)
@@ -239,8 +285,10 @@
             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')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     def test_update_router_reset_gateway_without_snat(self):
         router = self._create_router(
             external_network_id=CONF.network.public_network_id)
@@ -255,7 +303,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
@@ -317,7 +365,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'])
@@ -329,7 +377,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-'))
@@ -348,7 +396,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..8d680e9 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -14,10 +14,12 @@
 #    under the License.
 
 import netaddr
+import testtools
 
 from tempest.api.network import base_routers as 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
 
@@ -44,7 +46,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 +55,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 +67,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 +83,32 @@
                           subnet02['id'])
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('04df80f9-224d-47f5-837a-bf23e33d1c20')
+    @decorators.idempotent_id('7101cc02-058a-11e7-93e1-fa163e4fa634')
+    @test.requires_ext(extension='ext-gw-mode', service='network')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
+    def test_router_set_gateway_used_ip_returns_409(self):
+        # At first create a address from public_network_id
+        port = self.admin_ports_client.create_port(
+            network_id=CONF.network.public_network_id)['port']
+        self.addCleanup(self.admin_ports_client.delete_port,
+                        port_id=port['id'])
+        # Add used ip and subnet_id in external_fixed_ips
+        fixed_ip = {
+            'subnet_id': port['fixed_ips'][0]['subnet_id'],
+            'ip_address': port['fixed_ips'][0]['ip_address']
+        }
+        external_gateway_info = {
+            'network_id': CONF.network.public_network_id,
+            'external_fixed_ips': [fixed_ip]
+        }
+        # Create a router and set gateway to used ip
+        self.assertRaises(lib_exc.Conflict,
+                          self.admin_routers_client.create_router,
+                          external_gateway_info=external_gateway_info)
+
+    @test.attr(type=['negative'])
+    @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 +117,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 +159,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 1031ab8..d7e5149 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -13,11 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import six
-
 from tempest.api.network import base_security_groups as 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 import test
 
 CONF = config.CONF
@@ -62,14 +61,14 @@
                     'port_range_max': port_range_max,
                     'remote_group_id': remote_group_id,
                     'remote_ip_prefix': remote_ip_prefix}
-        for key, value in six.iteritems(expected):
+        for key, value in expected.items():
             self.assertEqual(value, sec_group_rule[key],
                              "Field %s of the created security group "
                              "rule does not match with %s." %
                              (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()
@@ -82,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()
 
@@ -111,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()
 
@@ -131,7 +130,7 @@
                 rule_create_body['security_group_rule']['id']
             )
             create_dict = rule_create_body['security_group_rule']
-            for key, value in six.iteritems(create_dict):
+            for key, value in create_dict.items():
                 self.assertEqual(value,
                                  show_rule_body['security_group_rule'][key],
                                  "%s does not match." % key)
@@ -144,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.
 
@@ -162,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.
 
@@ -182,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()
@@ -200,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()
@@ -217,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..218a79a 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,17 @@
                           name=name)
 
     @test.attr(type=['negative'])
-    @test.idempotent_id('8fde898f-ce88-493b-adc9-4e4692879fc5')
+    @decorators.idempotent_id('966e2b96-023a-11e7-a9e4-fa163e4fa634')
+    def test_create_security_group_update_name_default(self):
+        # Update security group name to 'default', it should be failed.
+        group_create_body, _ = self._create_security_group()
+        self.assertRaises(lib_exc.Conflict,
+                          self.security_groups_client.update_security_group,
+                          group_create_body['security_group']['id'],
+                          name="default")
+
+    @test.attr(type=['negative'])
+    @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 +212,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 +228,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..be6bffc 100644
--- a/tempest/api/network/test_subnetpools_extensions.py
+++ b/tempest/api/network/test_subnetpools_extensions.py
@@ -13,9 +13,10 @@
 # under the License.
 
 from tempest.api.network import base
-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 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 535137e..e0216fd 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -121,7 +121,7 @@
         if object_name is None:
             object_name = data_utils.rand_name(name='TestObject')
         if data is None:
-            data = data_utils.arbitrary_string()
+            data = data_utils.random_bytes()
         cls.object_client.create_object(container_name,
                                         object_name,
                                         data,
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..84e4508 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -13,8 +13,9 @@
 # under the License.
 
 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 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..de64dfe 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -20,8 +20,9 @@
 
 from tempest.api.object_storage import base
 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 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)
@@ -252,8 +253,20 @@
             self.assertEqual(True, container.decode(
                 'utf-8').startswith(prefix))
 
+    @decorators.idempotent_id('b1811cff-d1ed-4c15-a52e-efd8de41cf34')
+    def test_list_containers_reverse_order(self):
+        # list containers in reverse order
+        _, orig_container_list = self.account_client.list_account_containers()
+
+        params = {'reverse': True}
+        resp, container_list = self.account_client.list_account_containers(
+            params=params)
+        self.assertHeaders(resp, 'Account', 'GET')
+        self.assertEqual(sorted(orig_container_list, reverse=True),
+                         container_list)
+
     @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 +281,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,8 +302,8 @@
 
         self.account_client.delete_account_metadata(metadata)
 
-    @test.idempotent_id('9f60348d-c46f-4465-ae06-d51dbd470953')
-    def test_update_account_metadata_with_delete_matadata(self):
+    @decorators.idempotent_id('9f60348d-c46f-4465-ae06-d51dbd470953')
+    def test_update_account_metadata_with_delete_metadata(self):
         # delete metadata from account
         metadata = {'test-account-meta1': 'Meta1'}
         self.account_client.create_account_metadata(metadata)
@@ -300,8 +313,8 @@
         resp, _ = self.account_client.list_account_metadata()
         self.assertNotIn('x-account-meta-test-account-meta1', resp)
 
-    @test.idempotent_id('64fd53f3-adbd-4639-af54-436e4982dbfb')
-    def test_update_account_metadata_with_create_matadata_key(self):
+    @decorators.idempotent_id('64fd53f3-adbd-4639-af54-436e4982dbfb')
+    def test_update_account_metadata_with_create_metadata_key(self):
         # if the value of metadata is not set, the metadata is not
         # registered at a server
         metadata = {'test-account-meta1': ''}
@@ -311,8 +324,8 @@
         resp, _ = self.account_client.list_account_metadata()
         self.assertNotIn('x-account-meta-test-account-meta1', resp)
 
-    @test.idempotent_id('d4d884d3-4696-4b85-bc98-4f57c4dd2bf1')
-    def test_update_account_metadata_with_delete_matadata_key(self):
+    @decorators.idempotent_id('d4d884d3-4696-4b85-bc98-4f57c4dd2bf1')
+    def test_update_account_metadata_with_delete_metadata_key(self):
         # Although the value of metadata is not set, the feature of
         # deleting metadata is valid
         metadata_1 = {'test-account-meta1': 'Meta1'}
@@ -324,7 +337,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 ffdd1de..d4e5ec5 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -14,9 +14,9 @@
 #    under the License.
 
 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.common.utils import data_utils
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -26,17 +26,6 @@
     credentials = [['operator', CONF.object_storage.operator_role],
                    ['operator_alt', CONF.object_storage.operator_role]]
 
-    @classmethod
-    def setup_credentials(cls):
-        super(ObjectTestACLs, cls).setup_credentials()
-        cls.os = cls.os_roles_operator
-        cls.os_operator = cls.os_roles_operator_alt
-
-    @classmethod
-    def resource_setup(cls):
-        super(ObjectTestACLs, cls).resource_setup()
-        cls.test_auth_data = cls.os_operator.auth_provider.auth_data
-
     def setUp(self):
         super(ObjectTestACLs, self).setUp()
         self.container_name = self.create_container()
@@ -45,49 +34,54 @@
         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
-        tenant_name = self.os_operator.credentials.tenant_name
-        username = self.os_operator.credentials.username
+        tenant_name = self.os_roles_operator_alt.credentials.tenant_name
+        username = self.os_roles_operator_alt.credentials.username
         cont_headers = {'X-Container-Read': tenant_name + ':' + username}
-        resp_meta, body = self.container_client.update_container_metadata(
-            self.container_name, metadata=cont_headers,
-            metadata_prefix='')
+        resp_meta, body = self.os_roles_operator.container_client.\
+            update_container_metadata(
+                self.container_name, metadata=cont_headers,
+                metadata_prefix='')
         self.assertHeaders(resp_meta, 'Container', 'POST')
         # create object
         object_name = data_utils.rand_name(name='Object')
-        resp, _ = self.object_client.create_object(self.container_name,
-                                                   object_name, 'data')
+        resp, _ = self.os_roles_operator.object_client.create_object(
+            self.container_name, object_name, 'data')
         self.assertHeaders(resp, 'Object', 'PUT')
-        # Trying to read the object with rights
-        self.object_client.auth_provider.set_alt_auth_data(
+        # set alternative authentication data; cannot simply use the
+        # other object client.
+        self.os_roles_operator.object_client.auth_provider.set_alt_auth_data(
             request_part='headers',
-            auth_data=self.test_auth_data
-        )
-        resp, _ = self.object_client.get_object(
+            auth_data=self.os_roles_operator_alt.object_client.auth_provider.
+            auth_data)
+        resp, _ = self.os_roles_operator.object_client.get_object(
             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
-        tenant_name = self.os_operator.credentials.tenant_name
-        username = self.os_operator.credentials.username
+        tenant_name = self.os_roles_operator_alt.credentials.tenant_name
+        username = self.os_roles_operator_alt.credentials.username
         cont_headers = {'X-Container-Write': tenant_name + ':' + username}
-        resp_meta, body = self.container_client.update_container_metadata(
-            self.container_name, metadata=cont_headers,
-            metadata_prefix='')
+        resp_meta, body = self.os_roles_operator.container_client.\
+            update_container_metadata(self.container_name,
+                                      metadata=cont_headers,
+                                      metadata_prefix='')
         self.assertHeaders(resp_meta, 'Container', 'POST')
-        # Trying to write the object with rights
-        self.object_client.auth_provider.set_alt_auth_data(
+        # set alternative authentication data; cannot simply use the
+        # other object client.
+        self.os_roles_operator.object_client.auth_provider.set_alt_auth_data(
             request_part='headers',
-            auth_data=self.test_auth_data
-        )
+            auth_data=self.os_roles_operator_alt.object_client.auth_provider.
+            auth_data)
+        # Trying to write the object with rights
         object_name = data_utils.rand_name(name='Object')
-        resp, _ = self.object_client.create_object(
+        resp, _ = self.os_roles_operator.object_client.create_object(
             self.container_name,
             object_name, 'data', headers={})
         self.assertHeaders(resp, 'Object', 'PUT')
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index 0055bf9..c0f7b3a 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -13,8 +13,9 @@
 #    under the License.
 
 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 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..7ff337e 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.api.object_storage import base
-from tempest.common.utils import data_utils
+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
 
@@ -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 9ce1b18..a82d2cc 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -15,6 +15,7 @@
 
 from tempest.api.object_storage import base
 from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -24,14 +25,14 @@
         super(ContainerTest, self).tearDown()
 
     @test.attr(type='smoke')
-    @test.idempotent_id('92139d73-7819-4db1-85f8-3f2f22a8d91f')
+    @decorators.idempotent_id('92139d73-7819-4db1-85f8-3f2f22a8d91f')
     def test_create_container(self):
         container_name = data_utils.rand_name(name='TestContainer')
         resp, body = self.container_client.create_container(container_name)
         self.containers.append(container_name)
         self.assertHeaders(resp, 'Container', 'PUT')
 
-    @test.idempotent_id('49f866ed-d6af-4395-93e7-4187eb56d322')
+    @decorators.idempotent_id('49f866ed-d6af-4395-93e7-4187eb56d322')
     def test_create_container_overwrite(self):
         # overwrite container with the same name
         container_name = data_utils.rand_name(name='TestContainer')
@@ -41,7 +42,7 @@
         resp, _ = self.container_client.create_container(container_name)
         self.assertHeaders(resp, 'Container', 'PUT')
 
-    @test.idempotent_id('c2ac4d59-d0f5-40d5-ba19-0635056d48cd')
+    @decorators.idempotent_id('c2ac4d59-d0f5-40d5-ba19-0635056d48cd')
     def test_create_container_with_metadata_key(self):
         # create container with the blank value of metadata
         container_name = data_utils.rand_name(name='TestContainer')
@@ -58,7 +59,7 @@
         # in the server
         self.assertNotIn('x-container-meta-test-container-meta', resp)
 
-    @test.idempotent_id('e1e8df32-7b22-44e1-aa08-ccfd8d446b58')
+    @decorators.idempotent_id('e1e8df32-7b22-44e1-aa08-ccfd8d446b58')
     def test_create_container_with_metadata_value(self):
         # create container with metadata value
         container_name = data_utils.rand_name(name='TestContainer')
@@ -77,7 +78,7 @@
         self.assertEqual(resp['x-container-meta-test-container-meta'],
                          metadata['test_container_meta'])
 
-    @test.idempotent_id('24d16451-1c0c-4e4f-b59c-9840a3aba40e')
+    @decorators.idempotent_id('24d16451-1c0c-4e4f-b59c-9840a3aba40e')
     def test_create_container_with_remove_metadata_key(self):
         # create container with the blank value of remove metadata
         container_name = data_utils.rand_name(name='TestContainer')
@@ -97,7 +98,7 @@
             container_name)
         self.assertNotIn('x-container-meta-test-container-meta', resp)
 
-    @test.idempotent_id('8a21ebad-a5c7-4e29-b428-384edc8cd156')
+    @decorators.idempotent_id('8a21ebad-a5c7-4e29-b428-384edc8cd156')
     def test_create_container_with_remove_metadata_value(self):
         # create container with remove metadata
         container_name = data_utils.rand_name(name='TestContainer')
@@ -115,7 +116,7 @@
             container_name)
         self.assertNotIn('x-container-meta-test-container-meta', resp)
 
-    @test.idempotent_id('95d3a249-b702-4082-a2c4-14bb860cf06a')
+    @decorators.idempotent_id('95d3a249-b702-4082-a2c4-14bb860cf06a')
     def test_delete_container(self):
         # create a container
         container_name = self.create_container()
@@ -124,7 +125,7 @@
         self.assertHeaders(resp, 'Container', 'DELETE')
 
     @test.attr(type='smoke')
-    @test.idempotent_id('312ff6bd-5290-497f-bda1-7c5fec6697ab')
+    @decorators.idempotent_id('312ff6bd-5290-497f-bda1-7c5fec6697ab')
     def test_list_container_contents(self):
         # get container contents list
         container_name = self.create_container()
@@ -133,9 +134,9 @@
         resp, object_list = self.container_client.list_container_contents(
             container_name)
         self.assertHeaders(resp, 'Container', 'GET')
-        self.assertEqual(object_name, object_list.strip('\n'))
+        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()
@@ -143,9 +144,9 @@
         resp, object_list = self.container_client.list_container_contents(
             container_name)
         self.assertHeaders(resp, 'Container', 'GET')
-        self.assertEqual('', object_list.strip('\n'))
+        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()
@@ -157,22 +158,22 @@
             container_name,
             params=params)
         self.assertHeaders(resp, 'Container', 'GET')
-        self.assertEqual(object_name.split('/')[0], object_list.strip('/\n'))
+        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.strip('\n'))
+        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()
@@ -226,9 +227,9 @@
             container_name,
             params=params)
         self.assertHeaders(resp, 'Container', 'GET')
-        self.assertEqual(object_name, object_list.strip('\n'))
+        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()
@@ -239,13 +240,14 @@
             container_name,
             params=params)
         self.assertHeaders(resp, 'Container', 'GET')
-        self.assertEqual(object_name, object_list.strip('\n'))
+        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'}
@@ -253,9 +255,9 @@
             container_name,
             params=params)
         self.assertHeaders(resp, 'Container', 'GET')
-        self.assertEqual(object_name, object_list.strip('\n'))
+        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()
@@ -267,10 +269,10 @@
             container_name,
             params=params)
         self.assertHeaders(resp, 'Container', 'GET')
-        self.assertEqual(object_name, object_list.strip('\n'))
+        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 f63c518..be066ba 100644
--- a/tempest/api/object_storage/test_container_services_negative.py
+++ b/tempest/api/object_storage/test_container_services_negative.py
@@ -18,6 +18,7 @@
 from tempest.api.object_storage import base
 from tempest import config
 from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.lib import exceptions
 from tempest import test
 
@@ -36,7 +37,7 @@
             cls.constraints = body['swift']
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('30686921-4bed-4764-a038-40d741ed4e78')
+    @decorators.idempotent_id('30686921-4bed-4764-a038-40d741ed4e78')
     @testtools.skipUnless(
         CONF.object_storage_feature_enabled.discoverability,
         'Discoverability function is disabled')
@@ -52,7 +53,7 @@
                       ' longer than ' + str(max_length), str(ex))
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('41e645bf-2e68-4f84-bf7b-c71aa5cd76ce')
+    @decorators.idempotent_id('41e645bf-2e68-4f84-bf7b-c71aa5cd76ce')
     @testtools.skipUnless(
         CONF.object_storage_feature_enabled.discoverability,
         'Discoverability function is disabled')
@@ -69,7 +70,7 @@
         self.assertIn('Metadata name too long', str(ex))
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('81e36922-326b-4b7c-8155-3bbceecd7a82')
+    @decorators.idempotent_id('81e36922-326b-4b7c-8155-3bbceecd7a82')
     @testtools.skipUnless(
         CONF.object_storage_feature_enabled.discoverability,
         'Discoverability function is disabled')
@@ -86,7 +87,7 @@
         self.assertIn('Metadata value longer than ' + str(max_length), str(ex))
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('ac666539-d566-4f02-8ceb-58e968dfb732')
+    @decorators.idempotent_id('ac666539-d566-4f02-8ceb-58e968dfb732')
     @testtools.skipUnless(
         CONF.object_storage_feature_enabled.discoverability,
         'Discoverability function is disabled')
@@ -106,7 +107,7 @@
                       str(ex))
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('1a95ab2e-b712-4a98-8a4d-8ce21b7557d6')
+    @decorators.idempotent_id('1a95ab2e-b712-4a98-8a4d-8ce21b7557d6')
     def test_get_metadata_headers_with_invalid_container_name(self):
         # Attempts to retrieve metadata headers with an invalid
         # container name.
@@ -115,7 +116,7 @@
                           'invalid_container_name')
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('125a24fa-90a7-4cfc-b604-44e49d788390')
+    @decorators.idempotent_id('125a24fa-90a7-4cfc-b604-44e49d788390')
     def test_update_metadata_with_nonexistent_container_name(self):
         # Attempts to update metadata using a nonexistent container name.
         metadata = {'animal': 'penguin'}
@@ -125,7 +126,7 @@
                           'nonexistent_container_name', metadata)
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('65387dbf-a0e2-4aac-9ddc-16eb3f1f69ba')
+    @decorators.idempotent_id('65387dbf-a0e2-4aac-9ddc-16eb3f1f69ba')
     def test_delete_with_nonexistent_container_name(self):
         # Attempts to delete metadata using a nonexistent container name.
         metadata = {'animal': 'penguin'}
@@ -135,7 +136,7 @@
                           'nonexistent_container_name', metadata)
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('14331d21-1e81-420a-beea-19cb5e5207f5')
+    @decorators.idempotent_id('14331d21-1e81-420a-beea-19cb5e5207f5')
     def test_list_all_container_objects_with_nonexistent_container(self):
         # Attempts to get a listing of all objects on a container
         # that doesn't exist.
@@ -145,7 +146,7 @@
                           'nonexistent_container_name', params)
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('86b2ab08-92d5-493d-acd2-85f0c848819e')
+    @decorators.idempotent_id('86b2ab08-92d5-493d-acd2-85f0c848819e')
     def test_list_all_container_objects_on_deleted_container(self):
         # Attempts to get a listing of all objects on a container
         # that was deleted.
@@ -159,7 +160,7 @@
                           container_name, params)
 
     @test.attr(type=["negative"])
-    @test.idempotent_id('42da116e-1e8c-4c96-9e06-2f13884ed2b1')
+    @decorators.idempotent_id('42da116e-1e8c-4c96-9e06-2f13884ed2b1')
     def test_delete_non_empty_container(self):
         # create a container and an object within it
         # attempt to delete a container that isn't empty.
@@ -173,5 +174,5 @@
         ex = self.assertRaises(exceptions.Conflict,
                                self.container_client.delete_container,
                                container_name)
-        self.assertIn('An object with that identifier already exists',
-                      str(ex))
+        self.assertIn('There was a conflict when trying to complete your '
+                      'request.', str(ex))
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 47ef0d3..9e01c26 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -14,7 +14,8 @@
 
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
-from tempest.common.utils import data_utils
+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
 
@@ -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'}
@@ -96,7 +97,7 @@
         # Check only the format of common headers with custom matcher
         self.assertThat(resp, custom_matchers.AreAllWellFormatted())
 
-        self.assertIn(self.object_name, body)
+        self.assertIn(self.object_name, body.decode())
 
         # clean up before exiting
         self.container_client.update_container_metadata(self.container_name,
@@ -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',
@@ -126,11 +127,11 @@
         resp, body = self.account_client.request("GET",
                                                  self.container_name,
                                                  headers={})
-        self.assertIn(self.object_name, body)
+        self.assertIn(self.object_name, body.decode())
         css = '<link rel="stylesheet" type="text/css" href="listings.css" />'
-        self.assertIn(css, body)
+        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 e10b900..1c45a98 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -18,10 +18,9 @@
 from six.moves.urllib import parse as urlparse
 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 import test
 
@@ -96,7 +95,7 @@
                 cont_client[0].put(str(cont[0]), body=None, headers=headers)
             # create object in container
             object_name = data_utils.rand_name(name='TestSyncObject')
-            data = object_name[::-1]  # data_utils.arbitrary_string()
+            data = object_name[::-1].encode()  # Raw data, we need bytes
             resp, _ = obj_client[0].create_object(cont[0], object_name, data)
             self.objects.append(object_name)
 
@@ -127,11 +126,11 @@
         for obj_client, cont in obj_clients:
             for obj_name in object_lists[0]:
                 resp, object_content = obj_client.get_object(cont, obj_name)
-                self.assertEqual(object_content, obj_name[::-1])
+                self.assertEqual(object_content, obj_name[::-1].encode())
 
     @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 8dbfd06..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,10 +37,11 @@
         # 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", {})
+        body = body.decode()
 
         self.assertTrue(body.startswith(self.xml_start) and
                         body.endswith(self.xml_end))
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 102ec2f..c100629 100644
--- a/tempest/api/object_storage/test_object_formpost.py
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -19,7 +19,8 @@
 from six.moves.urllib import parse as urlparse
 
 from tempest.api.object_storage import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -72,7 +73,9 @@
                                             max_file_count,
                                             expires)
 
-        signature = hmac.new(self.key, hmac_body, hashlib.sha1).hexdigest()
+        signature = hmac.new(
+            self.key.encode(), hmac_body.encode(), hashlib.sha1
+        ).hexdigest()
 
         fields = {'redirect': redirect,
                   'max_file_size': str(max_file_size),
@@ -102,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()
@@ -119,4 +122,4 @@
         resp, body = self.object_client.get("%s/%s%s" % (
             self.container_name, self.object_name, "testfile"))
         self.assertHeaders(resp, "Object", "GET")
-        self.assertEqual(body, "hello world")
+        self.assertEqual(body.decode(), "hello world")
diff --git a/tempest/api/object_storage/test_object_formpost_negative.py b/tempest/api/object_storage/test_object_formpost_negative.py
index 8ff5d82..c4e6a3a 100644
--- a/tempest/api/object_storage/test_object_formpost_negative.py
+++ b/tempest/api/object_storage/test_object_formpost_negative.py
@@ -19,7 +19,8 @@
 from six.moves.urllib import parse as urlparse
 
 from tempest.api.object_storage import base
-from tempest.common.utils import data_utils
+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
 
@@ -73,7 +74,9 @@
                                             max_file_count,
                                             expires)
 
-        signature = hmac.new(self.key, hmac_body, hashlib.sha1).hexdigest()
+        signature = hmac.new(
+            self.key.encode(), hmac_body.encode(), hashlib.sha1
+        ).hexdigest()
 
         fields = {'redirect': redirect,
                   'max_file_size': str(max_file_size),
@@ -103,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):
@@ -120,8 +123,9 @@
             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')
+    @test.attr(type=['negative'])
     def test_post_object_using_form_invalid_signature(self):
         self.key = "Wrong"
         body, content_type = self.get_multipart_form()
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 8736f9a..d463827 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -19,12 +19,11 @@
 import time
 import zlib
 
-import six
-
 from tempest.api.object_storage import base
 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 import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -77,16 +76,16 @@
                 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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
         # create another object
         object_name = data_utils.rand_name(name='TestObject')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
         self.assertHeaders(resp, 'Object', 'PUT')
@@ -96,11 +95,11 @@
                                                 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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         metadata = {}
         metadata['content-disposition'] = 'inline'
         resp, _ = self.object_client.create_object(
@@ -118,13 +117,13 @@
         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')
 
         # put compressed string
-        data_before = 'x' * 2000
+        data_before = b'x' * 2000
         data = zlib.compress(data_before)
         metadata = {}
         metadata['content-encoding'] = 'deflate'
@@ -145,11 +144,11 @@
             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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         md5 = hashlib.md5(data).hexdigest()
         metadata = {'Etag': md5}
         resp, _ = self.object_client.create_object(
@@ -164,12 +163,12 @@
                                                 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
 
         object_name = data_utils.rand_name(name='TestObject')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
 
         status, _ = self.object_client.create_object_continue(
             self.container_name, object_name, data)
@@ -181,11 +180,11 @@
                                                 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')
-        data = data_utils.arbitrary_string(1024)
+        data = data_utils.random_bytes(1024)
         status, _, resp_headers = self.object_client.put_object_with_chunk(
             container=self.container_name,
             name=object_name,
@@ -198,11 +197,11 @@
                                                 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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         metadata_1 = {'X-Object-Meta-test-meta': 'Meta'}
         self.object_client.create_object(self.container_name,
                                          object_name_base,
@@ -224,11 +223,11 @@
         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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         metadata = {'X-Object-Meta-test-meta': 'Meta'}
         resp, _ = self.object_client.create_object(
             self.container_name,
@@ -243,11 +242,11 @@
         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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         metadata = {'X-Object-Meta-test-meta': ''}
         resp, _ = self.object_client.create_object(
             self.container_name,
@@ -262,11 +261,11 @@
         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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         metadata_add = {'X-Object-Meta-test-meta': 'Meta'}
         self.object_client.create_object(self.container_name,
                                          object_name,
@@ -285,11 +284,11 @@
         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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         metadata_add = {'X-Object-Meta-test-meta': 'Meta'}
         self.object_client.create_object(self.container_name,
                                          object_name,
@@ -308,11 +307,11 @@
         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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
         # delete object
@@ -321,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)
@@ -340,11 +339,11 @@
         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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         create_metadata = {'X-Object-Meta-test-meta1': 'Meta1'}
         self.object_client.create_object(self.container_name,
                                          object_name,
@@ -364,11 +363,11 @@
             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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         create_metadata = {'X-Object-Meta-test-meta1': 'Meta1'}
         self.object_client.create_object(self.container_name,
                                          object_name,
@@ -391,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
 
@@ -418,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)
@@ -437,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')
@@ -462,11 +461,11 @@
         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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         metadata = {'X-Object-Meta-test-meta': 'Meta'}
         self.object_client.create_object(self.container_name,
                                          object_name,
@@ -480,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)
@@ -491,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
 
@@ -532,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)
 
@@ -545,11 +544,11 @@
 
         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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         metadata = {'X-Object-Meta-test-meta': 'Meta'}
         self.object_client.create_object(self.container_name,
                                          object_name,
@@ -564,11 +563,11 @@
         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')
-        data = data_utils.arbitrary_string(100)
+        data = data_utils.random_bytes(100)
         self.object_client.create_object(self.container_name,
                                          object_name,
                                          data,
@@ -582,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,13 +622,13 @@
         self.assertEqual(resp['x-object-manifest'],
                          '%s/%s' % (self.container_name, object_name))
 
-        self.assertEqual(''.join(data_segments), body)
+        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')
-        data = data_utils.arbitrary_string(10)
+        data = data_utils.random_bytes(10)
         create_md5 = hashlib.md5(data).hexdigest()
         create_metadata = {'Etag': create_md5}
         self.object_client.create_object(self.container_name,
@@ -645,11 +644,11 @@
         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')
-        data = data_utils.arbitrary_string()
+        data = data_utils.random_bytes()
         time_now = time.time()
         self.object_client.create_object(self.container_name,
                                          object_name,
@@ -665,11 +664,11 @@
         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')
-        data = data_utils.arbitrary_string(10)
+        data = data_utils.random_bytes()
         create_md5 = hashlib.md5(data).hexdigest()
         create_metadata = {'Etag': create_md5}
         self.object_client.create_object(self.container_name,
@@ -677,7 +676,7 @@
                                          data,
                                          metadata=create_metadata)
 
-        list_data = data_utils.arbitrary_string(15)
+        list_data = data_utils.random_bytes()
         list_md5 = hashlib.md5(list_data).hexdigest()
         list_metadata = {'If-None-Match': list_md5}
         resp, body = self.object_client.get_object(
@@ -687,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)
@@ -702,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)
@@ -715,19 +714,17 @@
         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')
-        src_data = data_utils.arbitrary_string(size=len(src_object_name) * 2,
-                                               base_text=src_object_name)
+        src_data = data_utils.random_bytes(size=len(src_object_name) * 2)
         resp, _ = self.object_client.create_object(self.container_name,
                                                    src_object_name,
                                                    src_data)
         # create destination object
         dst_object_name = data_utils.rand_name(name='DstObject')
-        dst_data = data_utils.arbitrary_string(size=len(dst_object_name) * 3,
-                                               base_text=dst_object_name)
+        dst_data = data_utils.random_bytes(size=len(dst_object_name) * 3)
         resp, _ = self.object_client.create_object(self.container_name,
                                                    dst_object_name,
                                                    dst_data)
@@ -741,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
 
@@ -762,18 +759,16 @@
                                                           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')
-        src_data = data_utils.arbitrary_string(size=len(src_object_name) * 2,
-                                               base_text=src_object_name)
+        src_data = data_utils.random_bytes(size=len(src_object_name) * 2)
         resp, _ = self.object_client.create_object(self.container_name,
                                                    src_object_name, src_data)
         # create destination object
         dst_object_name = data_utils.rand_name(name='DstObject')
-        dst_data = data_utils.arbitrary_string(size=len(dst_object_name) * 3,
-                                               base_text=dst_object_name)
+        dst_data = data_utils.random_bytes(size=len(dst_object_name) * 3)
         resp, _ = self.object_client.create_object(self.container_name,
                                                    dst_object_name, dst_data)
         # copy source object to destination
@@ -788,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')
@@ -801,8 +796,7 @@
         self.containers.append(dst_container_name)
         # create object in source container
         object_name = data_utils.rand_name(name='Object')
-        data = data_utils.arbitrary_string(size=len(object_name) * 2,
-                                           base_text=object_name)
+        data = data_utils.random_bytes(size=len(object_name) * 2)
         resp, _ = self.object_client.create_object(src_container_name,
                                                    object_name, data)
         # set object metadata
@@ -828,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'}
@@ -849,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,14 +859,14 @@
         expected = {'x-object-meta-test': '',
                     'x-object-meta-src': 'src_value',
                     'x-copied-from': self.container_name + "/" + src_obj_name}
-        for key, value in six.iteritems(expected):
+        for key, value in expected.items():
             self.assertIn(key, resp)
             self.assertEqual(value, resp[key])
 
         # 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,14 +882,14 @@
         expected = {'x-object-meta-test': 'value',
                     'x-object-meta-src': 'src_value',
                     'x-copied-from': self.container_name + "/" + src_obj_name}
-        for key, value in six.iteritems(expected):
+        for key, value in expected.items():
             self.assertIn(key, resp)
             self.assertEqual(value, resp[key])
 
         # 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')
@@ -935,9 +929,9 @@
         # downloading the object
         resp, body = self.object_client.get_object(
             self.container_name, object_name)
-        self.assertEqual(''.join(data_segments), body)
+        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
@@ -960,7 +954,7 @@
 
         # local copy is different, download
         local_data = "something different"
-        md5 = hashlib.md5(local_data).hexdigest()
+        md5 = hashlib.md5(local_data.encode()).hexdigest()
         headers = {'If-None-Match': md5}
         resp, body = self.object_client.get(url, headers=headers)
         self.assertHeaders(resp, 'Object', 'GET')
@@ -991,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
@@ -1004,8 +998,7 @@
 
         # create object
         object_name = data_utils.rand_name(name='Object')
-        data = data_utils.arbitrary_string(size=len(object_name),
-                                           base_text=object_name)
+        data = data_utils.random_bytes(size=len(object_name))
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
         self.assertHeaders(resp, 'Object', 'PUT')
@@ -1029,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
@@ -1041,8 +1034,7 @@
 
         # create object
         object_name = data_utils.rand_name(name='Object')
-        data = data_utils.arbitrary_string(size=len(object_name) * 1,
-                                           base_text=object_name)
+        data = data_utils.random_bytes(size=len(object_name))
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
         self.assertHeaders(resp, 'Object', 'PUT')
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index e00bbab..085ad13 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -18,8 +18,9 @@
 
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
-from tempest.common.utils import data_utils
+from tempest.lib.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
@@ -56,7 +57,7 @@
         object_name_base_1 = object_name + '_01'
         object_name_base_2 = object_name + '_02'
         data_size = MIN_SEGMENT_SIZE
-        self.content = data_utils.arbitrary_string(data_size)
+        self.content = data_utils.random_bytes(data_size)
         self._create_object(self.container_name,
                             object_name_base_1,
                             self.content)
@@ -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 7287a2d..912deab 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -19,7 +19,8 @@
 from six.moves.urllib import parse as urlparse
 
 from tempest.api.object_storage import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -75,7 +76,9 @@
             container, object_name)
 
         hmac_body = '%s\n%s\n%s' % (method, expires, path)
-        sig = hmac.new(key, hmac_body, hashlib.sha1).hexdigest()
+        sig = hmac.new(
+            key.encode(), hmac_body.encode(), hashlib.sha1
+        ).hexdigest()
 
         url = "%s/%s?temp_url_sig=%s&temp_url_expires=%s" % (container,
                                                              object_name,
@@ -83,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()
@@ -102,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-'
@@ -126,12 +129,10 @@
         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.arbitrary_string(
-            size=len(self.object_name),
-            base_text=data_utils.rand_name(name="random"))
+        new_data = data_utils.random_bytes(size=len(self.object_name))
 
         expires = self._get_expiry_date()
         url = self._get_temp_url(self.container_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 577f3bd..9c1393f 100644
--- a/tempest/api/object_storage/test_object_temp_url_negative.py
+++ b/tempest/api/object_storage/test_object_temp_url_negative.py
@@ -19,7 +19,8 @@
 from six.moves.urllib import parse as urlparse
 
 from tempest.api.object_storage import base
-from tempest.common.utils import data_utils
+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
 
@@ -80,7 +81,9 @@
             container, object_name)
 
         hmac_body = '%s\n%s\n%s' % (method, expires, path)
-        sig = hmac.new(key, hmac_body, hashlib.sha1).hexdigest()
+        sig = hmac.new(
+            key.encode(), hmac_body.encode(), hashlib.sha1
+        ).hexdigest()
 
         url = "%s/%s?temp_url_sig=%s&temp_url_expires=%s" % (container,
                                                              object_name,
@@ -89,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 3f6623b..dc0d179 100644
--- a/tempest/api/object_storage/test_object_version.py
+++ b/tempest/api/object_storage/test_object_version.py
@@ -16,9 +16,9 @@
 import testtools
 
 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.common.utils import data_utils
+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')
@@ -69,22 +69,24 @@
                              vers_container_name)
         object_name = data_utils.rand_name(name='TestObject')
         # create object
+        data_1 = data_utils.random_bytes()
         resp, _ = self.object_client.create_object(base_container_name,
-                                                   object_name, '1')
+                                                   object_name, data_1)
         # create 2nd version of object
+        data_2 = data_utils.random_bytes()
         resp, _ = self.object_client.create_object(base_container_name,
-                                                   object_name, '2')
+                                                   object_name, data_2)
         resp, body = self.object_client.get_object(base_container_name,
                                                    object_name)
-        self.assertEqual(body, '2')
+        self.assertEqual(body, data_2)
         # delete object version 2
         resp, _ = self.object_client.delete_object(base_container_name,
                                                    object_name)
-        self.assertContainer(base_container_name, '1', '1',
+        self.assertContainer(base_container_name, '1', '1024',
                              vers_container_name)
         resp, body = self.object_client.get_object(base_container_name,
                                                    object_name)
-        self.assertEqual(body, '1')
+        self.assertEqual(body, data_1)
         # delete object version 1
         resp, _ = self.object_client.delete_object(base_container_name,
                                                    object_name)
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index 3701b55..8d3d344 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -14,8 +14,8 @@
 
 import yaml
 
-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
 import tempest.test
 
@@ -47,13 +47,8 @@
         cls.servers_client = cls.os.servers_client
         cls.keypairs_client = cls.os.keypairs_client
         cls.networks_client = cls.os.networks_client
-        cls.volumes_client = cls.os.volumes_client
         cls.images_v2_client = cls.os.image_client_v2
-
-        if CONF.volume_feature_enabled.api_v2:
-            cls.volumes_client = cls.os.volumes_v2_client
-        else:
-            cls.volumes_client = cls.os.volumes_client
+        cls.volumes_client = cls.os.volumes_v2_client
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/api/orchestration/stacks/test_environment.py b/tempest/api/orchestration/stacks/test_environment.py
index f2ffbd7..c8a9aa7 100644
--- a/tempest/api/orchestration/stacks/test_environment.py
+++ b/tempest/api/orchestration/stacks/test_environment.py
@@ -11,13 +11,13 @@
 #    under the License.
 
 from tempest.api.orchestration import base
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+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..9c9d4f9 100644
--- a/tempest/api/orchestration/stacks/test_limits.py
+++ b/tempest/api/orchestration/stacks/test_limits.py
@@ -11,17 +11,17 @@
 #    under the License.
 
 from tempest.api.orchestration 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
 
 
 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 6d27502..6faca71 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -14,8 +14,9 @@
 from oslo_log import log as logging
 
 from tempest.api.orchestration 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
 
@@ -28,8 +29,6 @@
 
     @classmethod
     def skip_checks(cls):
-        msg = "Skipped until Bug: 1547261 is resolved."
-        raise cls.skipException(msg)
         super(NeutronResourcesTestJSON, cls).skip_checks()
         if not CONF.service_available.neutron:
             raise cls.skipException("Neutron support is required")
@@ -44,6 +43,7 @@
         super(NeutronResourcesTestJSON, cls).setup_clients()
         cls.subnets_client = cls.os.subnets_client
         cls.ports_client = cls.os.ports_client
+        cls.routers_client = cls.os.routers_client
 
     @classmethod
     def resource_setup(cls):
@@ -84,18 +84,21 @@
                 # to heat.
                 body = cls.client.show_resource(cls.stack_identifier,
                                                 'Server')
-                server_id = body['physical_resource_id']
-                LOG.debug('Console output for %s', server_id)
-                output = cls.servers_client.get_console_output(
-                    server_id)['output']
-                LOG.debug(output)
-            raise
+                server_id = body.get('physical_resource_id')
+                if server_id:
+                    LOG.debug('Console output for %s', server_id)
+                    output = cls.servers_client.get_console_output(
+                        server_id)['output']
+                    LOG.debug(output)
+                else:
+                    LOG.debug('Server resource is %s', body)
+            raise  # original exception
 
         cls.test_resources = {}
         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'][
@@ -113,7 +116,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."""
@@ -125,7 +128,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."""
@@ -143,7 +146,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."""
@@ -156,7 +159,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."""
@@ -179,7 +182,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..6b9c88b 100644
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ b/tempest/api/orchestration/stacks/test_non_empty_stack.py
@@ -11,9 +11,9 @@
 #    under the License.
 
 from tempest.api.orchestration import base
-from tempest.common.utils import data_utils
 from tempest import config
-from tempest import test
+from tempest.lib.common.utils import data_utils
+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..a51648f 100644
--- a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
+++ b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
@@ -11,8 +11,8 @@
 #    under the License.
 
 from tempest.api.orchestration import base
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+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..dae0bab 100644
--- a/tempest/api/orchestration/stacks/test_soft_conf.py
+++ b/tempest/api/orchestration/stacks/test_soft_conf.py
@@ -11,7 +11,8 @@
 #    under the License.
 
 from tempest.api.orchestration import base
-from tempest.common.utils import data_utils
+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
 
@@ -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..0be135b 100644
--- a/tempest/api/orchestration/stacks/test_stacks.py
+++ b/tempest/api/orchestration/stacks/test_stacks.py
@@ -11,7 +11,8 @@
 #    under the License.
 
 from tempest.api.orchestration import base
-from tempest.common.utils import data_utils
+from tempest.lib.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 c0f1c4b..97fdac4 100644
--- a/tempest/api/orchestration/stacks/test_swift_resources.py
+++ b/tempest/api/orchestration/stacks/test_swift_resources.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
 #
 # Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -14,8 +13,9 @@
 # under the License.
 
 from tempest.api.orchestration 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 import test
 
 
@@ -60,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')
@@ -75,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'}
@@ -85,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')
@@ -103,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..4ff951d 100644
--- a/tempest/api/orchestration/stacks/test_templates.py
+++ b/tempest/api/orchestration/stacks/test_templates.py
@@ -11,8 +11,8 @@
 #    under the License.
 
 from tempest.api.orchestration import base
-from tempest.common.utils import data_utils
-from tempest import test
+from tempest.lib.common.utils import data_utils
+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..7ddf7af 100644
--- a/tempest/api/orchestration/stacks/test_volumes.py
+++ b/tempest/api/orchestration/stacks/test_volumes.py
@@ -11,8 +11,9 @@
 #    under the License.
 
 from tempest.api.orchestration 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
 
@@ -34,18 +35,10 @@
         self.assertEqual('available', volume.get('status'))
         self.assertEqual(CONF.volume.volume_size, volume.get('size'))
 
-        # Some volume properties have been renamed with Cinder v2
-        if CONF.volume_feature_enabled.api_v2:
-            description_field = 'description'
-            name_field = 'name'
-        else:
-            description_field = 'display_description'
-            name_field = 'display_name'
-
         self.assertEqual(template['resources']['volume']['properties'][
-            'description'], volume.get(description_field))
+            'description'], volume.get('description'))
         self.assertEqual(template['resources']['volume']['properties'][
-            'name'], volume.get(name_field))
+            'name'], volume.get('name'))
 
     def _outputs_verify(self, stack_identifier, template):
         self.assertEqual('available',
@@ -58,7 +51,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 +85,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/v2/test_backends_capabilities.py b/tempest/api/volume/admin/test_backends_capabilities.py
similarity index 81%
rename from tempest/api/volume/admin/v2/test_backends_capabilities.py
rename to tempest/api/volume/admin/test_backends_capabilities.py
index fc9066c..607fc43 100644
--- a/tempest/api/volume/admin/v2/test_backends_capabilities.py
+++ b/tempest/api/volume/admin/test_backends_capabilities.py
@@ -16,10 +16,10 @@
 import operator
 
 from tempest.api.volume import base
-from tempest import test
+from tempest.lib import decorators
 
 
-class BackendsCapabilitiesAdminV2TestsJSON(base.BaseVolumeAdminTest):
+class BackendsCapabilitiesAdminTestsJSON(base.BaseVolumeAdminTest):
 
     CAPABILITIES = ('namespace',
                     'vendor_name',
@@ -34,14 +34,14 @@
 
     @classmethod
     def resource_setup(cls):
-        super(BackendsCapabilitiesAdminV2TestsJSON, cls).resource_setup()
+        super(BackendsCapabilitiesAdminTestsJSON, cls).resource_setup()
         # Get host list, formation: host@backend-name
         cls.hosts = [
             pool['name'] for pool in
             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
@@ -72,8 +72,8 @@
         ]
 
         # Returns a tuple of VOLUME_STATS values
-        expected_list = map(operator.itemgetter(*VOLUME_STATS),
-                            cinder_pools)
-        observed_list = map(operator.itemgetter(*VOLUME_STATS),
-                            capabilities)
+        expected_list = list(map(operator.itemgetter(*VOLUME_STATS),
+                             cinder_pools))
+        observed_list = list(map(operator.itemgetter(*VOLUME_STATS),
+                             capabilities))
         self.assertEqual(expected_list, observed_list)
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 5703313..2db8010 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -12,41 +12,39 @@
 
 import six
 from tempest.api.volume import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 CONF = config.CONF
 
 
-class VolumeMultiBackendV2Test(base.BaseVolumeAdminTest):
+class VolumeMultiBackendTest(base.BaseVolumeAdminTest):
 
     @classmethod
     def skip_checks(cls):
-        super(VolumeMultiBackendV2Test, cls).skip_checks()
+        super(VolumeMultiBackendTest, cls).skip_checks()
 
         if not CONF.volume_feature_enabled.multi_backend:
             raise cls.skipException("Cinder multi-backend feature disabled")
 
     @classmethod
     def resource_setup(cls):
-        super(VolumeMultiBackendV2Test, cls).resource_setup()
+        super(VolumeMultiBackendTest, cls).resource_setup()
 
         # read backend name from a list .
-        cls.backend_names = set(CONF.volume.backend_names)
+        backend_names = set(CONF.volume.backend_names)
 
-        cls.name_field = cls.special_fields['name_field']
-        cls.volume_type_id_list = []
         cls.volume_id_list_with_prefix = []
         cls.volume_id_list_without_prefix = []
 
         # Volume/Type creation (uses volume_backend_name)
         # It is not allowed to create the same backend name twice
-        if len(cls.backend_names) < 2:
+        if len(backend_names) < 2:
             raise cls.skipException("Requires at least two different "
                                     "backend names")
-        for backend_name in cls.backend_names:
+        for backend_name in backend_names:
             # Volume/Type creation (uses backend_name)
             cls._create_type_and_volume(backend_name, False)
             # Volume/Type creation (uses capabilities:volume_backend_name)
@@ -63,10 +61,10 @@
             extra_specs = {spec_key_with_prefix: backend_name_key}
         else:
             extra_specs = {spec_key_without_prefix: backend_name_key}
-        cls.type = cls.create_volume_type(name=type_name,
-                                          extra_specs=extra_specs)
+        cls.create_volume_type(name=type_name,
+                               extra_specs=extra_specs)
 
-        params = {cls.name_field: vol_name, 'volume_type': type_name,
+        params = {'name': vol_name, 'volume_type': type_name,
                   'size': CONF.volume.volume_size}
         cls.volume = cls.admin_volume_client.create_volume(
             **params)['volume']
@@ -75,8 +73,8 @@
         else:
             cls.volume_id_list_without_prefix.append(
                 cls.volume['id'])
-        waiters.wait_for_volume_status(cls.admin_volume_client,
-                                       cls.volume['id'], 'available')
+        waiters.wait_for_volume_resource_status(cls.admin_volume_client,
+                                                cls.volume['id'], 'available')
 
     @classmethod
     def resource_cleanup(cls):
@@ -91,26 +89,26 @@
             cls.admin_volume_client.delete_volume(volume_id)
             cls.admin_volume_client.wait_for_resource_deletion(volume_id)
 
-        super(VolumeMultiBackendV2Test, cls).resource_cleanup()
+        super(VolumeMultiBackendTest, 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)
@@ -141,7 +139,3 @@
         msg = ("volumes %s were created in the same backend" % ", "
                .join(volume_hosts))
         six.assertCountEqual(self, volume_hosts, set(volume_hosts), msg)
-
-
-class VolumeMultiBackendV1Test(VolumeMultiBackendV2Test):
-    _api_version = 1
diff --git a/tempest/api/volume/admin/test_qos.py b/tempest/api/volume/admin/test_qos.py
index 9275d2b..e31c0ef 100644
--- a/tempest/api/volume/admin/test_qos.py
+++ b/tempest/api/volume/admin/test_qos.py
@@ -13,21 +13,21 @@
 #    under the License.
 
 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.common.utils import data_utils as utils
+from tempest.lib import decorators
 
 
-class QosSpecsV2TestJSON(base.BaseVolumeAdminTest):
+class QosSpecsTestJSON(base.BaseVolumeAdminTest):
     """Test the Cinder QoS-specs.
 
     Tests for  create, list, delete, show, associate,
-    disassociate, set/unset key V2 APIs.
+    disassociate, set/unset key APIs.
     """
 
     @classmethod
     def resource_setup(cls):
-        super(QosSpecsV2TestJSON, cls).resource_setup()
+        super(QosSpecsTestJSON, cls).resource_setup()
         # Create admin qos client
         # Create a test shared qos-specs for tests
         cls.qos_name = utils.rand_name(cls.__name__ + '-QoS')
@@ -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 :
 
@@ -157,7 +157,3 @@
         operation = 'disassociate-all'
         waiters.wait_for_qos_operations(self.admin_volume_qos_client,
                                         self.created_qos['id'], operation)
-
-
-class QosSpecsV1TestJSON(QosSpecsV2TestJSON):
-    _api_version = 1
diff --git a/tempest/api/volume/admin/test_snapshot_manage.py b/tempest/api/volume/admin/test_snapshot_manage.py
new file mode 100644
index 0000000..a2d5fb1
--- /dev/null
+++ b/tempest/api/volume/admin/test_snapshot_manage.py
@@ -0,0 +1,73 @@
+# Copyright 2016 Red Hat, Inc.
+# 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 testtools
+
+from tempest.api.volume import base
+from tempest.common import waiters
+from tempest import config
+from tempest.lib import decorators
+
+CONF = config.CONF
+
+
+class SnapshotManageAdminTest(base.BaseVolumeAdminTest):
+    """Unmanage & manage snapshots
+
+     This feature provides the ability to import/export volume snapshot
+     from one Cinder to another and to import snapshots that have not been
+     managed by Cinder from a storage back end to Cinder
+    """
+
+    @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):
+        # Create a volume
+        volume = self.create_volume()
+
+        # Create a snapshot
+        snapshot = self.create_snapshot(volume_id=volume['id'])
+
+        # Unmanage the snapshot
+        # Unmanage snapshot function works almost the same as delete snapshot,
+        # but it does not delete the snapshot data
+        self.admin_snapshots_client.unmanage_snapshot(snapshot['id'])
+        self.admin_snapshots_client.wait_for_resource_deletion(snapshot['id'])
+
+        # Fetch snapshot ids
+        snapshot_list = [
+            snap['id'] for snap in
+            self.snapshots_client.list_snapshots()['snapshots']
+        ]
+
+        # Verify snapshot does not exist in snapshot list
+        self.assertNotIn(snapshot['id'], snapshot_list)
+
+        # Manage the snapshot
+        snapshot_ref = '_snapshot-%s' % snapshot['id']
+        new_snapshot = self.admin_snapshot_manage_client.manage_snapshot(
+            volume_id=volume['id'],
+            ref={'source-name': snapshot_ref})['snapshot']
+        self.addCleanup(self.delete_snapshot, new_snapshot['id'],
+                        self.admin_snapshots_client)
+
+        # Wait for the snapshot to be available after manage operation
+        waiters.wait_for_volume_resource_status(self.admin_snapshots_client,
+                                                new_snapshot['id'],
+                                                'available')
+
+        # Verify the managed snapshot has the expected parent volume
+        self.assertEqual(new_snapshot['volume_id'], volume['id'])
diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py
index 29a161b..471f39a 100644
--- a/tempest/api/volume/admin/test_snapshots_actions.py
+++ b/tempest/api/volume/admin/test_snapshots_actions.py
@@ -15,21 +15,21 @@
 
 from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
 
-class SnapshotsActionsV2Test(base.BaseVolumeAdminTest):
+class SnapshotsActionsTest(base.BaseVolumeAdminTest):
     @classmethod
     def skip_checks(cls):
-        super(SnapshotsActionsV2Test, cls).skip_checks()
+        super(SnapshotsActionsTest, cls).skip_checks()
         if not CONF.volume_feature_enabled.snapshot:
             raise cls.skipException("Cinder snapshot feature disabled")
 
     @classmethod
     def resource_setup(cls):
-        super(SnapshotsActionsV2Test, cls).resource_setup()
+        super(SnapshotsActionsTest, cls).resource_setup()
 
         # Create a test shared volume for tests
         cls.volume = cls.create_volume()
@@ -43,7 +43,7 @@
         snapshot_id = self.snapshot['id']
         self.admin_snapshots_client.reset_snapshot_status(snapshot_id,
                                                           status)
-        super(SnapshotsActionsV2Test, self).tearDown()
+        super(SnapshotsActionsTest, self).tearDown()
 
     def _create_reset_and_force_delete_temp_snapshot(self, status=None):
         # Create snapshot, reset snapshot status,
@@ -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,26 +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')
-
-
-class SnapshotsActionsV1Test(SnapshotsActionsV2Test):
-    _api_version = 1
diff --git a/tempest/api/volume/admin/v3/test_user_messages.py b/tempest/api/volume/admin/test_user_messages.py
similarity index 88%
rename from tempest/api/volume/admin/v3/test_user_messages.py
rename to tempest/api/volume/admin/test_user_messages.py
index 257a434..20c3538 100755
--- a/tempest/api/volume/admin/v3/test_user_messages.py
+++ b/tempest/api/volume/admin/test_user_messages.py
@@ -13,10 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.volume.v3 import base
-from tempest.common.utils import data_utils
+from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 CONF = config.CONF
 
@@ -33,7 +33,8 @@
     'links']
 
 
-class UserMessagesTest(base.VolumesV3AdminTest):
+class UserMessagesTest(base.BaseVolumeAdminTest):
+    _api_version = 3
     min_microversion = '3.3'
     max_microversion = 'latest'
 
@@ -60,7 +61,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 +71,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 +81,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/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index f6de9a6..04d6cf9 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -14,17 +14,13 @@
 #    under the License.
 
 from tempest.api.volume import base
-from tempest import test
+from tempest.lib import decorators
 
 
-class VolumeHostsAdminV2TestsJSON(base.BaseVolumeAdminTest):
+class VolumeHostsAdminTestsJSON(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,"
                                 "response of list hosts is: % s" % hosts)
-
-
-class VolumeHostsAdminV1TestsJSON(VolumeHostsAdminV2TestsJSON):
-    _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_manage.py b/tempest/api/volume/admin/test_volume_manage.py
new file mode 100644
index 0000000..a039085
--- /dev/null
+++ b/tempest/api/volume/admin/test_volume_manage.py
@@ -0,0 +1,81 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# 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.api.volume import base
+from tempest.common import waiters
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+
+CONF = config.CONF
+
+
+class VolumeManageAdminTest(base.BaseVolumeAdminTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(VolumeManageAdminTest, cls).skip_checks()
+
+        if not CONF.volume_feature_enabled.manage_volume:
+            raise cls.skipException("Manage volume tests are disabled")
+
+        if len(CONF.volume.manage_volume_ref) != 2:
+            raise cls.skipException("Manage volume ref is not correctly "
+                                    "configured")
+
+    @decorators.idempotent_id('70076c71-0ce1-4208-a8ff-36a66e65cc1e')
+    def test_unmanage_manage_volume(self):
+        # Create original volume
+        org_vol_id = self.create_volume()['id']
+        org_vol_info = self.admin_volume_client.show_volume(
+            org_vol_id)['volume']
+
+        # Unmanage the original volume
+        self.admin_volume_client.unmanage_volume(org_vol_id)
+        self.admin_volume_client.wait_for_resource_deletion(org_vol_id)
+
+        # Verify the original volume does not exist in volume list
+        params = {'all_tenants': 1}
+        all_tenants_volumes = self.admin_volume_client.list_volumes(
+            detail=True, params=params)['volumes']
+        self.assertNotIn(org_vol_id, [v['id'] for v in all_tenants_volumes])
+
+        # Manage volume
+        new_vol_name = data_utils.rand_name(
+            self.__class__.__name__ + '-volume')
+        new_vol_ref = {
+            'name': new_vol_name,
+            'host': org_vol_info['os-vol-host-attr:host'],
+            'ref': {CONF.volume.manage_volume_ref[0]:
+                    CONF.volume.manage_volume_ref[1] % org_vol_id},
+            'volume_type': org_vol_info['volume_type'],
+            'availability_zone': org_vol_info['availability_zone']}
+        new_vol_id = self.admin_volume_manage_client.manage_volume(
+            **new_vol_ref)['volume']['id']
+        self.addCleanup(self.delete_volume,
+                        self.admin_volume_client, new_vol_id)
+        waiters.wait_for_volume_resource_status(self.admin_volume_client,
+                                                new_vol_id, 'available')
+
+        # Compare the managed volume with the original
+        new_vol_info = self.admin_volume_client.show_volume(
+            new_vol_id)['volume']
+        self.assertNotIn(new_vol_id, [org_vol_id])
+        self.assertEqual(new_vol_info['name'], new_vol_name)
+        for key in ['size',
+                    'volume_type',
+                    'availability_zone',
+                    'os-vol-host-attr:host']:
+            self.assertEqual(new_vol_info[key], org_vol_info[key])
diff --git a/tempest/api/volume/admin/test_volume_pools.py b/tempest/api/volume/admin/test_volume_pools.py
new file mode 100644
index 0000000..60a3bda
--- /dev/null
+++ b/tempest/api/volume/admin/test_volume_pools.py
@@ -0,0 +1,39 @@
+# 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.
+
+from tempest.api.volume import base
+from tempest import config
+from tempest.lib import decorators
+
+CONF = config.CONF
+
+
+class VolumePoolsAdminTestsJSON(base.BaseVolumeAdminTest):
+    def _assert_pools(self, with_detail=False):
+        cinder_pools = self.admin_volume_client.show_pools(
+            detail=with_detail)['pools']
+        self.assertIn('name', cinder_pools[0])
+        if with_detail:
+            self.assertIn(CONF.volume.vendor_name,
+                          [pool['capabilities']['vendor_name']
+                           for pool in cinder_pools])
+
+    @decorators.idempotent_id('0248a46c-e226-4933-be10-ad6fca8227e7')
+    def test_get_pools_without_details(self):
+        self._assert_pools()
+
+    @decorators.idempotent_id('d4bb61f7-762d-4437-b8a4-5785759a0ced')
+    def test_get_pools_with_details(self):
+        self._assert_pools(with_detail=True)
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index b47a5f0..58ca92f 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -12,42 +12,47 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import six
 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.common.utils import data_utils
+from tempest.lib import decorators
 
 QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes', 'backups']
 QUOTA_USAGE_KEYS = ['reserved', 'limit', 'in_use']
 
 
-class BaseVolumeQuotasAdminV2TestJSON(base.BaseVolumeAdminTest):
+class BaseVolumeQuotasAdminTestJSON(base.BaseVolumeAdminTest):
     force_tenant_isolation = True
 
     credentials = ['primary', 'alt', 'admin']
 
     @classmethod
     def setup_credentials(cls):
-        super(BaseVolumeQuotasAdminV2TestJSON, cls).setup_credentials()
+        super(BaseVolumeQuotasAdminTestJSON, cls).setup_credentials()
         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')
+    @classmethod
+    def setup_clients(cls):
+        super(BaseVolumeQuotasAdminTestJSON, cls).setup_clients()
+        cls.transfer_client = cls.os.volume_transfers_v2_client
+        cls.alt_transfer_client = cls.os_alt.volume_transfers_v2_client
+
+    @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(
@@ -63,7 +68,7 @@
             **new_quota_set)['quota_set']
 
         cleanup_quota_set = dict(
-            (k, v) for k, v in six.iteritems(default_quota_set)
+            (k, v) for k, v in default_quota_set.items()
             if k in QUOTA_KEYS)
         self.addCleanup(self.admin_quotas_client.update_quota_set,
                         self.demo_tenant_id, **cleanup_quota_set)
@@ -72,7 +77,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,
@@ -82,7 +87,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']
@@ -101,7 +106,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')
@@ -115,14 +120,14 @@
         volume_default = quota_set_default['volumes']
 
         self.admin_quotas_client.update_quota_set(
-            project_id, volumes=(int(volume_default) + 5))
+            project_id, volumes=(volume_default + 5))
 
         self.admin_quotas_client.delete_quota_set(project_id)
         quota_set_new = (self.admin_quotas_client.show_quota_set(project_id)
                          ['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()
@@ -137,17 +142,17 @@
             self.alt_client.tenant_id, params={'usage': True})['quota_set']
 
         # Creates a volume transfer
-        transfer = self.volumes_client.create_volume_transfer(
+        transfer = self.transfer_client.create_volume_transfer(
             volume_id=volume['id'])['transfer']
         transfer_id = transfer['id']
         auth_key = transfer['auth_key']
 
         # Accepts a volume transfer
-        self.alt_client.accept_volume_transfer(
+        self.alt_transfer_client.accept_volume_transfer(
             transfer_id, auth_key=auth_key)['transfer']
 
         # Verify volume transferred is available
-        waiters.wait_for_volume_status(
+        waiters.wait_for_volume_resource_status(
             self.alt_client, volume['id'], 'available')
 
         # List of tenants quota usage post transfer
@@ -170,7 +175,3 @@
         self.assertEqual(primary_quota['gigabytes']['in_use'] -
                          volume['size'],
                          new_primary_quota['gigabytes']['in_use'])
-
-
-class VolumeQuotasAdminV1TestJSON(BaseVolumeQuotasAdminV2TestJSON):
-    _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py
index c19b1c4..10cf890 100644
--- a/tempest/api/volume/admin/test_volume_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_quotas_negative.py
@@ -15,23 +15,24 @@
 
 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
 
 
-class BaseVolumeQuotasNegativeV2TestJSON(base.BaseVolumeAdminTest):
+class BaseVolumeQuotasNegativeTestJSON(base.BaseVolumeAdminTest):
     force_tenant_isolation = True
 
     @classmethod
     def setup_credentials(cls):
-        super(BaseVolumeQuotasNegativeV2TestJSON, cls).setup_credentials()
+        super(BaseVolumeQuotasNegativeTestJSON, cls).setup_credentials()
         cls.demo_tenant_id = cls.os.credentials.tenant_id
 
     @classmethod
     def resource_setup(cls):
-        super(BaseVolumeQuotasNegativeV2TestJSON, cls).resource_setup()
+        super(BaseVolumeQuotasNegativeTestJSON, cls).resource_setup()
         cls.shared_quota_set = {'gigabytes': 2 * CONF.volume.volume_size,
                                 'volumes': 1}
 
@@ -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
@@ -69,7 +70,3 @@
         self.assertRaises(lib_exc.OverLimit,
                           self.volumes_client.create_volume,
                           size=CONF.volume.volume_size)
-
-
-class VolumeQuotasNegativeV1TestJSON(BaseVolumeQuotasNegativeV2TestJSON):
-    _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_retype_with_migration.py b/tempest/api/volume/admin/test_volume_retype_with_migration.py
new file mode 100644
index 0000000..94d5299
--- /dev/null
+++ b/tempest/api/volume/admin/test_volume_retype_with_migration.py
@@ -0,0 +1,109 @@
+#    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 oslo_log import log as logging
+
+from tempest.api.volume import base
+from tempest.common import waiters
+from tempest import config
+from tempest.lib import decorators
+
+CONF = config.CONF
+
+LOG = logging.getLogger(__name__)
+
+
+class VolumeRetypeWithMigrationTest(base.BaseVolumeAdminTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(VolumeRetypeWithMigrationTest, cls).skip_checks()
+
+        if not CONF.volume_feature_enabled.multi_backend:
+            raise cls.skipException("Cinder multi-backend feature disabled.")
+
+        if len(set(CONF.volume.backend_names)) < 2:
+            raise cls.skipException("Requires at least two different "
+                                    "backend names")
+
+    @classmethod
+    def resource_setup(cls):
+        super(VolumeRetypeWithMigrationTest, cls).resource_setup()
+        # read backend name from a list.
+        backend_src = CONF.volume.backend_names[0]
+        backend_dst = CONF.volume.backend_names[1]
+
+        extra_specs_src = {"volume_backend_name": backend_src}
+        extra_specs_dst = {"volume_backend_name": backend_dst}
+
+        src_vol_type = cls.create_volume_type(extra_specs=extra_specs_src)
+        cls.dst_vol_type = cls.create_volume_type(extra_specs=extra_specs_dst)
+
+        cls.src_vol = cls.create_volume(volume_type=src_vol_type['name'])
+
+    @classmethod
+    def resource_cleanup(cls):
+        # When retyping a volume, Cinder creates an internal volume in the
+        # target backend. The volume in the source backend is deleted after
+        # the migration, so we need to wait for Cinder delete this volume
+        # before deleting the types we've created.
+
+        # This list should return 2 volumes until the copy and cleanup
+        # process is finished.
+        fetched_list = cls.admin_volume_client.list_volumes(
+            params={'all_tenants': True,
+                    'display_name': cls.src_vol['name']})['volumes']
+
+        for fetched_vol in fetched_list:
+            if fetched_vol['id'] != cls.src_vol['id']:
+                # This is the Cinder internal volume
+                LOG.debug('Waiting for internal volume %s deletion',
+                          fetched_vol['id'])
+                cls.admin_volume_client.wait_for_resource_deletion(
+                    fetched_vol['id'])
+                break
+
+        super(VolumeRetypeWithMigrationTest, cls).resource_cleanup()
+
+    @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',
+                               'os-vol-tenant-attr:tenant_id')
+        keys_with_change = ('volume_type', 'os-vol-host-attr:host')
+
+        volume_source = self.admin_volume_client.show_volume(
+            self.src_vol['id'])['volume']
+
+        # TODO(erlon): change this to volumes_client client after Bug
+        # #1657806 is fixed
+        self.admin_volume_client.retype_volume(
+            self.src_vol['id'],
+            new_type=self.dst_vol_type['name'],
+            migration_policy='on-demand')
+
+        waiters.wait_for_volume_retype(self.volumes_client, self.src_vol['id'],
+                                       self.dst_vol_type['name'])
+        volume_dest = self.admin_volume_client.show_volume(
+            self.src_vol['id'])['volume']
+
+        # Check the volume information after the migration.
+        self.assertEqual('success',
+                         volume_dest['os-vol-mig-status-attr:migstat'])
+        self.assertEqual('success', volume_dest['migration_status'])
+
+        for key in keys_with_no_change:
+            self.assertEqual(volume_source[key], volume_dest[key])
+
+        for key in keys_with_change:
+            self.assertNotEqual(volume_source[key], volume_dest[key])
diff --git a/tempest/api/volume/admin/test_volume_services.py b/tempest/api/volume/admin/test_volume_services.py
index 165874b..4aab9c1 100644
--- a/tempest/api/volume/admin/test_volume_services.py
+++ b/tempest/api/volume/admin/test_volume_services.py
@@ -13,20 +13,14 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 from tempest.api.volume import base
-from tempest import config
-from tempest import test
-
-
-CONF = config.CONF
+from tempest.lib import decorators
 
 
 def _get_host(host):
-    if CONF.volume_feature_enabled.volume_services:
-        host = host.split('@')[0]
-    return host
+    return host.split('@')[0]
 
 
-class VolumesServicesV2TestJSON(base.BaseVolumeAdminTest):
+class VolumesServicesTestJSON(base.BaseVolumeAdminTest):
     """Tests Volume Services API.
 
     volume service list requires admin privileges.
@@ -34,7 +28,7 @@
 
     @classmethod
     def resource_setup(cls):
-        super(VolumesServicesV2TestJSON, cls).resource_setup()
+        super(VolumesServicesTestJSON, cls).resource_setup()
         cls.services = (cls.admin_volume_services_client.list_services()
                         ['services'])
         # NOTE: Cinder service-list API returns the list contains
@@ -43,13 +37,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 +51,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 +67,21 @@
         # on order.
         self.assertEqual(sorted(s1), sorted(s2))
 
-    @test.idempotent_id('ffa6167c-4497-4944-a464-226bbdb53908')
+    @decorators.idempotent_id('67ec6902-f91d-4dec-91fa-338523208bbc')
+    def test_get_service_by_volume_host_name(self):
+        volume_id = self.create_volume()['id']
+        volume = self.admin_volume_client.show_volume(volume_id)['volume']
+        hostname = _get_host(volume['os-vol-host-attr:host'])
+
+        services = (self.admin_volume_services_client.list_services(
+            host=hostname, binary='cinder-volume')['services'])
+
+        self.assertNotEqual(0, len(services),
+                            'cinder-volume not found on host %s' % hostname)
+        self.assertEqual(hostname, _get_host(services[0]['host']))
+        self.assertEqual('cinder-volume', services[0]['binary'])
+
+    @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(
@@ -82,7 +90,3 @@
         self.assertNotEqual(0, len(services))
         self.assertEqual(self.host_name, _get_host(services[0]['host']))
         self.assertEqual(self.binary_name, services[0]['binary'])
-
-
-class VolumesServicesV1TestJSON(VolumesServicesV2TestJSON):
-    _api_version = 1
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..e5c78cb 100644
--- a/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py
@@ -15,29 +15,30 @@
 
 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
 
 
-class VolumeSnapshotQuotasNegativeV2TestJSON(base.BaseVolumeAdminTest):
+class VolumeSnapshotQuotasNegativeTestJSON(base.BaseVolumeAdminTest):
     force_tenant_isolation = True
 
     @classmethod
     def skip_checks(cls):
-        super(VolumeSnapshotQuotasNegativeV2TestJSON, cls).skip_checks()
+        super(VolumeSnapshotQuotasNegativeTestJSON, cls).skip_checks()
         if not CONF.volume_feature_enabled.snapshot:
             raise cls.skipException('Cinder volume snapshots are disabled')
 
     @classmethod
     def setup_credentials(cls):
-        super(VolumeSnapshotQuotasNegativeV2TestJSON, cls).setup_credentials()
+        super(VolumeSnapshotQuotasNegativeTestJSON, cls).setup_credentials()
         cls.demo_tenant_id = cls.os.credentials.tenant_id
 
     @classmethod
     def resource_setup(cls):
-        super(VolumeSnapshotQuotasNegativeV2TestJSON, cls).resource_setup()
+        super(VolumeSnapshotQuotasNegativeTestJSON, cls).resource_setup()
         cls.default_volume_size = CONF.volume.volume_size
         cls.shared_quota_set = {'gigabytes': 3 * cls.default_volume_size,
                                 'volumes': 1, 'snapshots': 1}
@@ -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,
@@ -74,7 +75,3 @@
         self.assertRaises(lib_exc.OverLimit,
                           self.snapshots_client.create_snapshot,
                           volume_id=self.volume['id'])
-
-
-class VolumeSnapshotNegativeV1TestJSON(VolumeSnapshotQuotasNegativeV2TestJSON):
-    _api_version = 1
diff --git a/tempest/api/volume/admin/v2/test_volume_type_access.py b/tempest/api/volume/admin/test_volume_type_access.py
similarity index 92%
rename from tempest/api/volume/admin/v2/test_volume_type_access.py
rename to tempest/api/volume/admin/test_volume_type_access.py
index 80dbf12..297ab6e 100644
--- a/tempest/api/volume/admin/v2/test_volume_type_access.py
+++ b/tempest/api/volume/admin/test_volume_type_access.py
@@ -17,22 +17,22 @@
 
 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
 
 
-class VolumeTypesAccessV2Test(base.BaseVolumeAdminTest):
+class VolumeTypesAccessTest(base.BaseVolumeAdminTest):
 
     credentials = ['primary', 'alt', 'admin']
 
     @classmethod
     def setup_clients(cls):
-        super(VolumeTypesAccessV2Test, cls).setup_clients()
+        super(VolumeTypesAccessTest, 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/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 6b2acc6..ac717f8 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -14,58 +14,57 @@
 #    under the License.
 
 from tempest.api.volume import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 CONF = config.CONF
 
 
-class VolumeTypesV2Test(base.BaseVolumeAdminTest):
+class VolumeTypesTest(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()
         vol_name = data_utils.rand_name(self.__class__.__name__ + '-volume')
-        self.name_field = self.special_fields['name_field']
         proto = CONF.volume.storage_protocol
         vendor = CONF.volume.vendor_name
         extra_specs = {"storage_protocol": proto,
                        "vendor_name": vendor}
         # Create two volume_types
-        for i in range(2):
+        for _ in range(2):
             vol_type = self.create_volume_type(
                 extra_specs=extra_specs)
             volume_types.append(vol_type)
-        params = {self.name_field: vol_name,
+        params = {'name': vol_name,
                   'volume_type': volume_types[0]['id'],
                   'size': CONF.volume.volume_size}
 
         # Create volume
         volume = self.create_volume(**params)
         self.assertEqual(volume_types[0]['name'], volume["volume_type"])
-        self.assertEqual(volume[self.name_field], vol_name,
+        self.assertEqual(volume['name'], vol_name,
                          "The created volume name is not equal "
                          "to the requested name")
         self.assertIsNotNone(volume['id'],
                              "Field volume id is empty or not found.")
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'available')
 
         # Update volume with new volume_type
         self.volumes_client.retype_volume(volume['id'],
                                           new_type=volume_types[1]['id'])
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'available')
 
         # Get volume details and Verify
         fetched_volume = self.volumes_client.show_volume(
@@ -74,25 +73,27 @@
                          fetched_volume['volume_type'],
                          'The fetched Volume type is different '
                          'from updated volume type')
-        self.assertEqual(vol_name, fetched_volume[self.name_field],
+        self.assertEqual(vol_name, fetched_volume['name'],
                          'The fetched Volume is different '
                          'from the created Volume')
         self.assertEqual(volume['id'], fetched_volume['id'],
                          '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.
-        body = {}
         name = data_utils.rand_name(self.__class__.__name__ + '-volume-type')
         description = data_utils.rand_name("volume-type-description")
         proto = CONF.volume.storage_protocol
         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 "
@@ -113,48 +114,66 @@
         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')
-    def test_volume_type_encryption_create_get_delete(self):
-        # Create/get/delete encryption type.
-        provider = "LuksEncryptor"
-        control_location = "front-end"
-        body = self.create_volume_type()
+    @decorators.idempotent_id('7830abd0-ff99-4793-a265-405684a54d46')
+    def test_volume_type_encryption_create_get_update_delete(self):
+        # Create/get/update/delete encryption type.
+        create_kwargs = {'provider': 'LuksEncryptor',
+                         'control_location': 'front-end'}
+        volume_type_id = self.create_volume_type()['id']
+
         # Create encryption type
         encryption_type = \
             self.admin_encryption_types_client.create_encryption_type(
-                body['id'], provider=provider,
-                control_location=control_location)['encryption']
+                volume_type_id, **create_kwargs)['encryption']
         self.assertIn('volume_type_id', encryption_type)
-        self.assertEqual(provider, encryption_type['provider'],
-                         "The created encryption_type provider is not equal "
-                         "to the requested provider")
-        self.assertEqual(control_location, encryption_type['control_location'],
-                         "The created encryption_type control_location is not "
-                         "equal to the requested control_location")
+        for key in create_kwargs:
+            self.assertEqual(create_kwargs[key], encryption_type[key],
+                             'The created encryption_type %s is different '
+                             'from the requested encryption_type' % key)
 
         # Get encryption type
+        encrypt_type_id = encryption_type['volume_type_id']
         fetched_encryption_type = (
             self.admin_encryption_types_client.show_encryption_type(
-                encryption_type['volume_type_id']))
-        self.assertEqual(provider,
-                         fetched_encryption_type['provider'],
-                         'The fetched encryption_type provider is different '
-                         'from the created encryption_type')
-        self.assertEqual(control_location,
-                         fetched_encryption_type['control_location'],
-                         'The fetched encryption_type control_location is '
-                         'different from the created encryption_type')
+                encrypt_type_id))
+        for key in create_kwargs:
+            self.assertEqual(create_kwargs[key], fetched_encryption_type[key],
+                             'The fetched encryption_type %s is different '
+                             'from the created encryption_type' % key)
+
+        # Update encryption type
+        update_kwargs = {'key_size': 128,
+                         'provider': 'SomeProvider',
+                         'cipher': 'aes-xts-plain64',
+                         'control_location': 'back-end'}
+        self.admin_encryption_types_client.update_encryption_type(
+            encrypt_type_id, **update_kwargs)
+        updated_encryption_type = (
+            self.admin_encryption_types_client.show_encryption_type(
+                encrypt_type_id))
+        for key in update_kwargs:
+            self.assertEqual(update_kwargs[key], updated_encryption_type[key],
+                             'The fetched encryption_type %s is different '
+                             'from the updated encryption_type' % key)
 
         # Delete encryption type
-        type_id = encryption_type['volume_type_id']
-        self.admin_encryption_types_client.delete_encryption_type(type_id)
-        self.admin_encryption_types_client.wait_for_resource_deletion(type_id)
+        self.admin_encryption_types_client.delete_encryption_type(
+            encrypt_type_id)
+        self.admin_encryption_types_client.wait_for_resource_deletion(
+            encrypt_type_id)
         deleted_encryption_type = (
-            self.admin_encryption_types_client.show_encryption_type(type_id))
+            self.admin_encryption_types_client.show_encryption_type(
+                encrypt_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()
@@ -175,7 +194,3 @@
         self.assertEqual(name, updated_vol_type['name'])
         self.assertEqual(description, updated_vol_type['description'])
         self.assertEqual(is_public, updated_vol_type['is_public'])
-
-
-class VolumeTypesV1Test(VolumeTypesV2Test):
-    _api_version = 1
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..b5a2fb7 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs.py
@@ -14,18 +14,18 @@
 #    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):
+class VolumeTypesExtraSpecsTest(base.BaseVolumeAdminTest):
 
     @classmethod
     def resource_setup(cls):
-        super(VolumeTypesExtraSpecsV2Test, cls).resource_setup()
+        super(VolumeTypesExtraSpecsTest, 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"
@@ -77,7 +77,3 @@
             lib_exc.NotFound,
             self.admin_volume_types_client.show_volume_type_extra_specs,
             self.volume_type['id'], spec_key)
-
-
-class VolumeTypesExtraSpecsV1Test(VolumeTypesExtraSpecsV2Test):
-    _api_version = 1
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..4efc44b 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
@@ -14,20 +14,22 @@
 #    under the License.
 
 from tempest.api.volume import base
-from tempest.common.utils import data_utils
+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 ExtraSpecsNegativeV2Test(base.BaseVolumeAdminTest):
+class ExtraSpecsNegativeTest(base.BaseVolumeAdminTest):
 
     @classmethod
     def resource_setup(cls):
-        super(ExtraSpecsNegativeV2Test, cls).resource_setup()
-        cls.extra_specs = {"spec1": "val1"}
-        cls.volume_type = cls.create_volume_type(extra_specs=cls.extra_specs)
+        super(ExtraSpecsNegativeTest, cls).resource_setup()
+        extra_specs = {"spec1": "val1"}
+        cls.volume_type = cls.create_volume_type(extra_specs=extra_specs)
 
-    @test.idempotent_id('08961d20-5cbb-4910-ac0f-89ad6dbb2da1')
+    @test.attr(type=['negative'])
+    @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 +37,8 @@
             self.admin_volume_types_client.update_volume_type_extra_specs,
             self.volume_type['id'], "spec1", None)
 
-    @test.idempotent_id('25e5a0ee-89b3-4c53-8310-236f76c75365')
+    @test.attr(type=['negative'])
+    @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 +48,8 @@
             self.volume_type['id'], data_utils.rand_uuid(),
             extra_spec)
 
-    @test.idempotent_id('9bf7a657-b011-4aec-866d-81c496fbe5c8')
+    @test.attr(type=['negative'])
+    @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 +58,8 @@
             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')
+    @test.attr(type=['negative'])
+    @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 +70,8 @@
             self.volume_type['id'], list(extra_spec)[0],
             extra_spec)
 
-    @test.idempotent_id('49d5472c-a53d-4eab-a4d3-450c4db1c545')
+    @test.attr(type=['negative'])
+    @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 +81,8 @@
             self.admin_volume_types_client.create_volume_type_extra_specs,
             data_utils.rand_uuid(), extra_specs)
 
-    @test.idempotent_id('c821bdc8-43a4-4bf4-86c8-82f3858d5f7d')
+    @test.attr(type=['negative'])
+    @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 +90,8 @@
             self.admin_volume_types_client.create_volume_type_extra_specs,
             self.volume_type['id'], None)
 
-    @test.idempotent_id('bc772c71-1ed4-4716-b945-8b5ed0f15e87')
+    @test.attr(type=['negative'])
+    @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 +99,8 @@
             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')
+    @test.attr(type=['negative'])
+    @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 +109,8 @@
             self.admin_volume_types_client.delete_volume_type_extra_specs,
             data_utils.rand_uuid(), "spec1")
 
-    @test.idempotent_id('dee5cf0c-cdd6-4353-b70c-e847050d71fb')
+    @test.attr(type=['negative'])
+    @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 +118,8 @@
             self.admin_volume_types_client.list_volume_types_extra_specs,
             data_utils.rand_uuid())
 
-    @test.idempotent_id('9f402cbd-1838-4eb4-9554-126a6b1908c9')
+    @test.attr(type=['negative'])
+    @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 +127,8 @@
             self.admin_volume_types_client.show_volume_type_extra_specs,
             data_utils.rand_uuid(), "spec1")
 
-    @test.idempotent_id('c881797d-12ff-4f1a-b09d-9f6212159753')
+    @test.attr(type=['negative'])
+    @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.
@@ -124,7 +136,3 @@
             lib_exc.NotFound,
             self.admin_volume_types_client.show_volume_type_extra_specs,
             self.volume_type['id'], data_utils.rand_uuid())
-
-
-class ExtraSpecsNegativeV1Test(ExtraSpecsNegativeV2Test):
-    _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py
index 857e7d2..bac2ea3 100644
--- a/tempest/api/volume/admin/test_volume_types_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_negative.py
@@ -15,42 +15,51 @@
 
 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):
+class VolumeTypesNegativeTest(base.BaseVolumeAdminTest):
 
-    @test.idempotent_id('b48c98f2-e662-4885-9b71-032256906314')
+    @test.attr(type=['negative'])
+    @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']
-        params = {self.name_field: data_utils.rand_uuid(),
+        params = {'name': data_utils.rand_uuid(),
                   'volume_type': data_utils.rand_uuid()}
         self.assertRaises(lib_exc.NotFound,
                           self.volumes_client.create_volume, **params)
 
-    @test.idempotent_id('878b4e57-faa2-4659-b0d1-ce740a06ae81')
+    @test.attr(type=['negative'])
+    @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')
+    @test.attr(type=['negative'])
+    @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')
+    @test.attr(type=['negative'])
+    @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())
 
-
-class VolumeTypesNegativeV1Test(VolumeTypesNegativeV2Test):
-    _api_version = 1
+    @test.attr(type=['negative'])
+    @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}
+        volume_type = self.create_volume_type(**params)
+        self.assertRaises(lib_exc.NotFound,
+                          self.create_volume, volume_type=volume_type['id'])
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index a63cbf0..7f291e9 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -14,10 +14,10 @@
 #    under the License.
 
 from tempest.api.volume import base
-from tempest import test
+from tempest.lib import decorators
 
 
-class VolumesActionsV2Test(base.BaseVolumeAdminTest):
+class VolumesActionsTest(base.BaseVolumeAdminTest):
 
     def _create_reset_and_force_delete_temp_volume(self, status=None):
         # Create volume, reset volume status, and force delete temp volume
@@ -28,32 +28,35 @@
         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()
-        for status in ['error', 'available']:
+        self.addCleanup(self.admin_volume_client.reset_volume_status,
+                        volume['id'], status='available')
+        for status in ['error', 'available', 'maintenance']:
             self.admin_volume_client.reset_volume_status(
                 volume['id'], status=status)
             volume_get = self.admin_volume_client.show_volume(
                 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')
 
-
-class VolumesActionsV1Test(VolumesActionsV2Test):
-    _api_version = 1
+    @decorators.idempotent_id('b957cabd-1486-4e21-90cf-a9ed3c39dfb2')
+    def test_volume_force_delete_when_volume_is_maintenance(self):
+        # test force delete when status of volume is maintenance
+        self._create_reset_and_force_delete_temp_volume('maintenance')
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index 61d4ba7..afc3281 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -17,19 +17,19 @@
 from oslo_serialization import jsonutils as json
 
 from tempest.api.volume import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest import test
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 
 CONF = config.CONF
 
 
-class VolumesBackupsAdminV2Test(base.BaseVolumeAdminTest):
+class VolumesBackupsAdminTest(base.BaseVolumeAdminTest):
 
     @classmethod
     def skip_checks(cls):
-        super(VolumesBackupsAdminV2Test, cls).skip_checks()
+        super(VolumesBackupsAdminTest, cls).skip_checks()
         if not CONF.volume_feature_enabled.backup:
             raise cls.skipException("Cinder backup feature disabled")
 
@@ -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.
 
@@ -94,8 +94,9 @@
         self.addCleanup(self._delete_backup, new_id)
         self.assertIn("id", import_backup)
         self.assertEqual(new_id, import_backup['id'])
-        waiters.wait_for_backup_status(self.admin_backups_client,
-                                       import_backup['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.admin_backups_client,
+                                                import_backup['id'],
+                                                'available')
 
         # Verify Import Backup
         backups = self.admin_backups_client.list_backups(
@@ -108,16 +109,18 @@
         self.addCleanup(self.admin_volume_client.delete_volume,
                         restore['volume_id'])
         self.assertEqual(backup['id'], restore['backup_id'])
-        waiters.wait_for_volume_status(self.admin_volume_client,
-                                       restore['volume_id'], 'available')
+        waiters.wait_for_volume_resource_status(self.admin_volume_client,
+                                                restore['volume_id'],
+                                                'available')
 
         # Verify if restored volume is there in volume list
         volumes = self.admin_volume_client.list_volumes()['volumes']
         self.assertIn(restore['volume_id'], [v['id'] for v in volumes])
-        waiters.wait_for_backup_status(self.admin_backups_client,
-                                       import_backup['id'], 'available')
+        waiters.wait_for_volume_resource_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()
@@ -131,9 +134,5 @@
         # Reset backup status to error
         self.admin_backups_client.reset_backup_status(backup_id=backup['id'],
                                                       status="error")
-        waiters.wait_for_backup_status(self.admin_backups_client,
-                                       backup['id'], 'error')
-
-
-class VolumesBackupsAdminV1Test(VolumesBackupsAdminV2Test):
-    _api_version = 1
+        waiters.wait_for_volume_resource_status(self.admin_backups_client,
+                                                backup['id'], 'error')
diff --git a/tempest/api/volume/admin/v2/test_volumes_list.py b/tempest/api/volume/admin/test_volumes_list.py
similarity index 86%
rename from tempest/api/volume/admin/v2/test_volumes_list.py
rename to tempest/api/volume/admin/test_volumes_list.py
index cdd9df9..9d98b7a 100644
--- a/tempest/api/volume/admin/v2/test_volumes_list.py
+++ b/tempest/api/volume/admin/test_volumes_list.py
@@ -18,35 +18,35 @@
 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
 
 
-class VolumesListAdminV2TestJSON(base.BaseVolumeAdminTest):
+class VolumesListAdminTestJSON(base.BaseVolumeAdminTest):
 
     @classmethod
     def resource_setup(cls):
-        super(VolumesListAdminV2TestJSON, cls).resource_setup()
+        super(VolumesListAdminTestJSON, cls).resource_setup()
         # Create 3 test volumes
         # NOTE(zhufl): When using pre-provisioned credentials, the project
         # may have volumes other than those created below.
         cls.volume_list = cls.volumes_client.list_volumes()['volumes']
-        for i in range(3):
+        for _ in range(3):
             volume = cls.create_volume()
             # Fetch volume details
             volume_details = cls.volumes_client.show_volume(
                 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
         adm_vol = self.admin_volume_client.create_volume(
             size=CONF.volume.volume_size)['volume']
-        waiters.wait_for_volume_status(self.admin_volume_client,
-                                       adm_vol['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.admin_volume_client,
+                                                adm_vol['id'], 'available')
         self.addCleanup(self.admin_volume_client.delete_volume, adm_vol['id'])
         params = {'all_tenants': 1,
                   'project_id': self.volumes_client.tenant_id}
diff --git a/tempest/api/volume/admin/v2/test_volume_pools.py b/tempest/api/volume/admin/v2/test_volume_pools.py
deleted file mode 100644
index 8544a6a..0000000
--- a/tempest/api/volume/admin/v2/test_volume_pools.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# 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.
-
-from tempest.api.volume import base
-from tempest import test
-
-
-class VolumePoolsAdminV2TestsJSON(base.BaseVolumeAdminTest):
-
-    @classmethod
-    def resource_setup(cls):
-        super(VolumePoolsAdminV2TestsJSON, cls).resource_setup()
-        # Create a test shared volume for tests
-        cls.volume = cls.create_volume()
-
-    def _assert_host_volume_in_pools(self, with_detail=False):
-        volume_info = self.admin_volume_client.show_volume(
-            self.volume['id'])['volume']
-        cinder_pools = self.admin_volume_client.show_pools(
-            detail=with_detail)['pools']
-        self.assertIn(volume_info['os-vol-host-attr:host'],
-                      [pool['name'] for pool in cinder_pools])
-
-    @test.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')
-    def test_get_pools_with_details(self):
-        self._assert_host_volume_in_pools(with_detail=True)
diff --git a/tempest/api/volume/admin/v3/__init__.py b/tempest/api/volume/admin/v3/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api/volume/admin/v3/__init__.py
+++ /dev/null
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 90dc7f4..a19af5d 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -13,10 +13,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.api.volume import api_microversion_fixture
 from tempest.common import compute
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib.common import api_version_utils
+from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions
 import tempest.test
@@ -24,7 +26,8 @@
 CONF = config.CONF
 
 
-class BaseVolumeTest(tempest.test.BaseTestCase):
+class BaseVolumeTest(api_version_utils.BaseMicroversionTest,
+                     tempest.test.BaseTestCase):
     """Base test case class for all Cinder API tests."""
 
     _api_version = 2
@@ -37,11 +40,7 @@
         if not CONF.service_available.cinder:
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
-        if cls._api_version == 1:
-            if not CONF.volume_feature_enabled.api_v1:
-                msg = "Volume API v1 is disabled"
-                raise cls.skipException(msg)
-        elif cls._api_version == 2:
+        if cls._api_version == 2:
             if not CONF.volume_feature_enabled.api_v2:
                 msg = "Volume API v2 is disabled"
                 raise cls.skipException(msg)
@@ -53,6 +52,10 @@
             msg = ("Invalid Cinder API version (%s)" % cls._api_version)
             raise exceptions.InvalidConfiguration(msg)
 
+        api_version_utils.check_skip_with_microversion(
+            cls.min_microversion, cls.max_microversion,
+            CONF.volume.min_microversion, CONF.volume.max_microversion)
+
     @classmethod
     def setup_credentials(cls):
         cls.set_network_resources()
@@ -65,27 +68,28 @@
         cls.compute_networks_client = cls.os.compute_networks_client
         cls.compute_images_client = cls.os.compute_images_client
 
-        if cls._api_version == 1:
-            cls.snapshots_client = cls.os.snapshots_client
-            cls.volumes_client = cls.os.volumes_client
-            cls.backups_client = cls.os.backups_client
-            cls.volume_services_client = cls.os.volume_services_client
-            cls.volumes_extension_client = cls.os.volumes_extension_client
-            cls.availability_zone_client = (
-                cls.os.volume_availability_zone_client)
-            cls.volume_limits_client = cls.os.volume_limits_client
-        else:
-            cls.snapshots_client = cls.os.snapshots_v2_client
-            cls.volumes_client = cls.os.volumes_v2_client
-            cls.backups_client = cls.os.backups_v2_client
-            cls.volumes_extension_client = cls.os.volumes_v2_extension_client
-            cls.availability_zone_client = (
-                cls.os.volume_v2_availability_zone_client)
-            cls.volume_limits_client = cls.os.volume_v2_limits_client
+        cls.snapshots_client = cls.os.snapshots_v2_client
+        cls.volumes_client = cls.os.volumes_v2_client
+        cls.backups_client = cls.os.backups_v2_client
+        cls.volumes_extension_client = cls.os.volumes_v2_extension_client
+        cls.availability_zone_client = (
+            cls.os.volume_v2_availability_zone_client)
+        cls.volume_limits_client = cls.os.volume_v2_limits_client
+        cls.messages_client = cls.os.volume_v3_messages_client
+        cls.versions_client = cls.os.volume_v3_versions_client
+
+    def setUp(self):
+        super(BaseVolumeTest, self).setUp()
+        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+            self.request_microversion))
 
     @classmethod
     def resource_setup(cls):
         super(BaseVolumeTest, cls).resource_setup()
+        cls.request_microversion = (
+            api_version_utils.select_request_microversion(
+                cls.min_microversion,
+                CONF.volume.min_microversion))
 
         cls.snapshots = []
         cls.volumes = []
@@ -94,15 +98,6 @@
         cls.build_interval = CONF.volume.build_interval
         cls.build_timeout = CONF.volume.build_timeout
 
-        if cls._api_version == 1:
-            # Special fields and resp code for cinder v1
-            cls.special_fields = {'name_field': 'display_name',
-                                  'descrip_field': 'display_description'}
-        else:
-            # Special fields and resp code for cinder v2
-            cls.special_fields = {'name_field': 'name',
-                                  'descrip_field': 'description'}
-
     @classmethod
     def resource_cleanup(cls):
         cls.clear_snapshots()
@@ -124,62 +119,72 @@
             min_disk = image.get('minDisk')
             kwargs['size'] = max(kwargs['size'], min_disk)
 
-        name_field = cls.special_fields['name_field']
-        if name_field not in kwargs:
+        if 'name' not in kwargs:
             name = data_utils.rand_name(cls.__name__ + '-Volume')
-            kwargs[name_field] = name
+            kwargs['name'] = name
 
         volume = cls.volumes_client.create_volume(**kwargs)['volume']
         cls.volumes.append(volume)
-        waiters.wait_for_volume_status(cls.volumes_client, volume['id'],
-                                       wait_until)
+        waiters.wait_for_volume_resource_status(cls.volumes_client,
+                                                volume['id'], wait_until)
         return volume
 
     @classmethod
     def create_snapshot(cls, volume_id=1, **kwargs):
         """Wrapper utility that returns a test snapshot."""
-        name_field = cls.special_fields['name_field']
-        if name_field not in kwargs:
+        if 'name' not in kwargs:
             name = data_utils.rand_name(cls.__name__ + '-Snapshot')
-            kwargs[name_field] = name
+            kwargs['name'] = name
 
         snapshot = cls.snapshots_client.create_snapshot(
             volume_id=volume_id, **kwargs)['snapshot']
-        cls.snapshots.append(snapshot)
-        waiters.wait_for_snapshot_status(cls.snapshots_client,
-                                         snapshot['id'], 'available')
+        cls.snapshots.append(snapshot['id'])
+        waiters.wait_for_volume_resource_status(cls.snapshots_client,
+                                                snapshot['id'], 'available')
         return snapshot
 
     def create_backup(self, volume_id, backup_client=None, **kwargs):
         """Wrapper utility that returns a test backup."""
         if backup_client is None:
             backup_client = self.backups_client
+        if 'name' not in kwargs:
+            name = data_utils.rand_name(self.__class__.__name__ + '-Backup')
+            kwargs['name'] = name
 
         backup = backup_client.create_backup(
             volume_id=volume_id, **kwargs)['backup']
         self.addCleanup(backup_client.delete_backup, backup['id'])
-        waiters.wait_for_backup_status(backup_client, backup['id'],
-                                       'available')
+        waiters.wait_for_volume_resource_status(backup_client, backup['id'],
+                                                'available')
         return backup
 
     # NOTE(afazekas): these create_* and clean_* could be defined
     # only in a single location in the source, and could be more general.
 
-    @classmethod
-    def delete_volume(cls, client, volume_id):
+    @staticmethod
+    def delete_volume(client, volume_id):
         """Delete volume by the given client"""
         client.delete_volume(volume_id)
         client.wait_for_resource_deletion(volume_id)
 
+    def delete_snapshot(self, snapshot_id, snapshots_client=None):
+        """Delete snapshot by the given client"""
+        if snapshots_client is None:
+            snapshots_client = self.snapshots_client
+        snapshots_client.delete_snapshot(snapshot_id)
+        snapshots_client.wait_for_resource_deletion(snapshot_id)
+        if snapshot_id in self.snapshots:
+            self.snapshots.remove(snapshot_id)
+
     def attach_volume(self, server_id, volume_id):
-        """Attachs a volume to a server"""
+        """Attach a volume to a server"""
         self.servers_client.attach_volume(
             server_id, volumeId=volume_id,
             device='/dev/%s' % CONF.compute.volume_device_name)
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume_id, 'in-use')
-        self.addCleanup(waiters.wait_for_volume_status, self.volumes_client,
-                        volume_id, 'available')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume_id, 'in-use')
+        self.addCleanup(waiters.wait_for_volume_resource_status,
+                        self.volumes_client, volume_id, 'available')
         self.addCleanup(self.servers_client.detach_volume, server_id,
                         volume_id)
 
@@ -201,12 +206,12 @@
     def clear_snapshots(cls):
         for snapshot in cls.snapshots:
             test_utils.call_and_ignore_notfound_exc(
-                cls.snapshots_client.delete_snapshot, snapshot['id'])
+                cls.snapshots_client.delete_snapshot, snapshot)
 
         for snapshot in cls.snapshots:
             test_utils.call_and_ignore_notfound_exc(
                 cls.snapshots_client.wait_for_resource_deletion,
-                snapshot['id'])
+                snapshot)
 
     def create_server(self, **kwargs):
         name = kwargs.pop(
@@ -237,36 +242,27 @@
     def setup_clients(cls):
         super(BaseVolumeAdminTest, cls).setup_clients()
 
-        if cls._api_version == 1:
-            cls.admin_volume_qos_client = cls.os_adm.volume_qos_client
-            cls.admin_volume_services_client = \
-                cls.os_adm.volume_services_client
-            cls.admin_volume_types_client = cls.os_adm.volume_types_client
-            cls.admin_volume_client = cls.os_adm.volumes_client
-            cls.admin_hosts_client = cls.os_adm.volume_hosts_client
-            cls.admin_snapshots_client = cls.os_adm.snapshots_client
-            cls.admin_backups_client = cls.os_adm.backups_client
-            cls.admin_encryption_types_client = \
-                cls.os_adm.encryption_types_client
-            cls.admin_quotas_client = cls.os_adm.volume_quotas_client
-            cls.admin_volume_limits_client = cls.os_adm.volume_limits_client
-        elif cls._api_version == 2:
-            cls.admin_volume_qos_client = cls.os_adm.volume_qos_v2_client
-            cls.admin_volume_services_client = \
-                cls.os_adm.volume_services_v2_client
-            cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
-            cls.admin_volume_client = cls.os_adm.volumes_v2_client
-            cls.admin_hosts_client = cls.os_adm.volume_hosts_v2_client
-            cls.admin_snapshots_client = cls.os_adm.snapshots_v2_client
-            cls.admin_backups_client = cls.os_adm.backups_v2_client
-            cls.admin_encryption_types_client = \
-                cls.os_adm.encryption_types_v2_client
-            cls.admin_quotas_client = cls.os_adm.volume_quotas_v2_client
-            cls.admin_volume_limits_client = cls.os_adm.volume_v2_limits_client
-            cls.admin_capabilities_client = \
-                cls.os_adm.volume_capabilities_v2_client
-            cls.admin_scheduler_stats_client = \
-                cls.os_adm.volume_scheduler_stats_v2_client
+        cls.admin_volume_qos_client = cls.os_adm.volume_qos_v2_client
+        cls.admin_volume_services_client = \
+            cls.os_adm.volume_services_v2_client
+        cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
+        cls.admin_volume_manage_client = cls.os_adm.volume_manage_v2_client
+        cls.admin_volume_client = cls.os_adm.volumes_v2_client
+        cls.admin_hosts_client = cls.os_adm.volume_hosts_v2_client
+        cls.admin_snapshot_manage_client = \
+            cls.os_adm.snapshot_manage_v2_client
+        cls.admin_snapshots_client = cls.os_adm.snapshots_v2_client
+        cls.admin_backups_client = cls.os_adm.backups_v2_client
+        cls.admin_encryption_types_client = \
+            cls.os_adm.encryption_types_v2_client
+        cls.admin_quotas_client = cls.os_adm.volume_quotas_v2_client
+        cls.admin_volume_limits_client = cls.os_adm.volume_v2_limits_client
+        cls.admin_capabilities_client = \
+            cls.os_adm.volume_capabilities_v2_client
+        cls.admin_scheduler_stats_client = \
+            cls.os_adm.volume_scheduler_stats_v2_client
+        cls.admin_messages_client = cls.os_adm.volume_v3_messages_client
+        cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/api/volume/test_availability_zone.py b/tempest/api/volume/test_availability_zone.py
index ae4b8f9..666efdf 100644
--- a/tempest/api/volume/test_availability_zone.py
+++ b/tempest/api/volume/test_availability_zone.py
@@ -14,24 +14,20 @@
 #    under the License.
 
 from tempest.api.volume import base
-from tempest import test
+from tempest.lib import decorators
 
 
-class AvailabilityZoneV2TestJSON(base.BaseVolumeTest):
-    """Tests Availability Zone V2 API List"""
+class AvailabilityZoneTestJSON(base.BaseVolumeTest):
+    """Tests Availability Zone API List"""
 
     @classmethod
     def setup_clients(cls):
-        super(AvailabilityZoneV2TestJSON, cls).setup_clients()
+        super(AvailabilityZoneTestJSON, 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()
                              ['availabilityZoneInfo'])
         self.assertGreater(len(availability_zone), 0)
-
-
-class AvailabilityZoneV1TestJSON(AvailabilityZoneV2TestJSON):
-    _api_version = 1
diff --git a/tempest/api/volume/test_extensions.py b/tempest/api/volume/test_extensions.py
index f044124..91bfa33 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
 
@@ -25,9 +25,9 @@
 LOG = logging.getLogger(__name__)
 
 
-class ExtensionsV2TestJSON(base.BaseVolumeTest):
+class ExtensionsTestJSON(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()
@@ -43,7 +43,3 @@
             self.assertIn(ext, map(lambda x: x['alias'], extensions))
         else:
             raise self.skipException('There are not any extensions configured')
-
-
-class ExtensionsV1TestJSON(ExtensionsV2TestJSON):
-    _api_version = 1
diff --git a/tempest/api/volume/v2/test_image_metadata.py b/tempest/api/volume/test_image_metadata.py
similarity index 83%
rename from tempest/api/volume/v2/test_image_metadata.py
rename to tempest/api/volume/test_image_metadata.py
index 1e7bb30..77baf18 100644
--- a/tempest/api/volume/v2/test_image_metadata.py
+++ b/tempest/api/volume/test_image_metadata.py
@@ -17,20 +17,28 @@
 
 from tempest.api.volume import base
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
 
 
-class VolumesV2ImageMetadata(base.BaseVolumeTest):
+class VolumesImageMetadata(base.BaseVolumeTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(VolumesImageMetadata, cls).skip_checks()
+        if not CONF.service_available.glance:
+            skip_msg = ("%s skipped as Glance is not available" % cls.__name__)
+            raise cls.skipException(skip_msg)
 
     @classmethod
     def resource_setup(cls):
-        super(VolumesV2ImageMetadata, cls).resource_setup()
+        super(VolumesImageMetadata, cls).resource_setup()
         # 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/test_snapshot_metadata.py b/tempest/api/volume/test_snapshot_metadata.py
index d0fa07e..164ed37 100644
--- a/tempest/api/volume/test_snapshot_metadata.py
+++ b/tempest/api/volume/test_snapshot_metadata.py
@@ -17,21 +17,21 @@
 
 from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 CONF = config.CONF
 
 
-class SnapshotV2MetadataTestJSON(base.BaseVolumeTest):
+class SnapshotMetadataTestJSON(base.BaseVolumeTest):
     @classmethod
     def skip_checks(cls):
-        super(SnapshotV2MetadataTestJSON, cls).skip_checks()
+        super(SnapshotMetadataTestJSON, cls).skip_checks()
         if not CONF.volume_feature_enabled.snapshot:
             raise cls.skipException("Cinder snapshot feature disabled")
 
     @classmethod
     def resource_setup(cls):
-        super(SnapshotV2MetadataTestJSON, cls).resource_setup()
+        super(SnapshotMetadataTestJSON, cls).resource_setup()
         # Create a volume
         cls.volume = cls.create_volume()
         # Create a snapshot
@@ -41,9 +41,9 @@
         # Update the metadata to {}
         self.snapshots_client.update_snapshot_metadata(
             self.snapshot['id'], metadata={})
-        super(SnapshotV2MetadataTestJSON, self).tearDown()
+        super(SnapshotMetadataTestJSON, 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",
@@ -102,7 +102,3 @@
         body = self.snapshots_client.show_snapshot_metadata(
             self.snapshot['id'])['metadata']
         self.assertThat(body.items(), matchers.ContainsAll(expect.items()))
-
-
-class SnapshotV1MetadataTestJSON(SnapshotV2MetadataTestJSON):
-    _api_version = 1
diff --git a/tempest/api/volume/test_versions.py b/tempest/api/volume/test_versions.py
new file mode 100644
index 0000000..76f2a99
--- /dev/null
+++ b/tempest/api/volume/test_versions.py
@@ -0,0 +1,30 @@
+# Copyright 2017 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.api.volume import base
+from tempest.lib import decorators
+from tempest import test
+
+
+class VersionsTest(base.BaseVolumeTest):
+
+    _api_version = 3
+
+    @decorators.idempotent_id('77838fc4-b49b-4c64-9533-166762517369')
+    @test.attr(type='smoke')
+    def test_list_versions(self):
+        # NOTE: The version data is checked on service client side
+        #       with JSON-Schema validation. It is enough to just call
+        #       the API here.
+        self.versions_client.list_versions()['versions']
diff --git a/tempest/api/volume/test_volume_absolute_limits.py b/tempest/api/volume/test_volume_absolute_limits.py
index 35e0d56..836e489 100644
--- a/tempest/api/volume/test_volume_absolute_limits.py
+++ b/tempest/api/volume/test_volume_absolute_limits.py
@@ -15,24 +15,24 @@
 
 from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 
 CONF = config.CONF
 
 
-class AbsoluteLimitsV2Tests(base.BaseVolumeTest):
+class AbsoluteLimitsTests(base.BaseVolumeTest):
 
     # avoid existing volumes of pre-defined tenant
     force_tenant_isolation = True
 
     @classmethod
     def resource_setup(cls):
-        super(AbsoluteLimitsV2Tests, cls).resource_setup()
+        super(AbsoluteLimitsTests, cls).resource_setup()
         # 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 = \
@@ -46,7 +46,3 @@
         self.assertEqual(absolute_limits['totalSnapshotsUsed'], 0)
         self.assertEqual(absolute_limits['totalBackupsUsed'], 0)
         self.assertEqual(absolute_limits['totalBackupGigabytesUsed'], 0)
-
-
-class AbsoluteLimitsV1Tests(AbsoluteLimitsV2Tests):
-    _api_version = 1
diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py
index c125bb8..b4d22fe 100644
--- a/tempest/api/volume/test_volume_metadata.py
+++ b/tempest/api/volume/test_volume_metadata.py
@@ -16,23 +16,23 @@
 from testtools import matchers
 
 from tempest.api.volume import base
-from tempest import test
+from tempest.lib import decorators
 
 
-class VolumesV2MetadataTest(base.BaseVolumeTest):
+class VolumesMetadataTest(base.BaseVolumeTest):
 
     @classmethod
     def resource_setup(cls):
-        super(VolumesV2MetadataTest, cls).resource_setup()
+        super(VolumesMetadataTest, cls).resource_setup()
         # Create a volume
         cls.volume = cls.create_volume()
 
     def tearDown(self):
         # Update the metadata to {}
         self.volumes_client.update_volume_metadata(self.volume['id'], {})
-        super(VolumesV2MetadataTest, self).tearDown()
+        super(VolumesMetadataTest, 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",
@@ -89,7 +89,3 @@
         body = self.volumes_client.show_volume_metadata(
             self.volume['id'])['metadata']
         self.assertThat(body.items(), matchers.ContainsAll(expect.items()))
-
-
-class VolumesV1MetadataTest(VolumesV2MetadataTest):
-    _api_version = 1
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index a8889e0..afcffc2 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -17,35 +17,37 @@
 
 from tempest.api.volume import base
 from tempest.common import waiters
-from tempest import test
+from tempest.lib import decorators
 
 
-class VolumesV2TransfersTest(base.BaseVolumeTest):
+class VolumesTransfersTest(base.BaseVolumeTest):
 
     credentials = ['primary', 'alt', 'admin']
 
     @classmethod
     def setup_clients(cls):
-        super(VolumesV2TransfersTest, cls).setup_clients()
+        super(VolumesTransfersTest, cls).setup_clients()
 
-        cls.client = cls.volumes_client
-        cls.alt_client = cls.os_alt.volumes_client
-        cls.alt_tenant_id = cls.alt_client.tenant_id
-        cls.adm_client = cls.os_adm.volumes_client
+        cls.client = cls.os.volume_transfers_v2_client
+        cls.alt_client = cls.os_alt.volume_transfers_v2_client
+        cls.alt_volumes_client = cls.os_alt.volumes_v2_client
+        cls.adm_volumes_client = cls.os_adm.volumes_v2_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()
-        self.addCleanup(self.delete_volume, self.adm_client, volume['id'])
+        self.addCleanup(self.delete_volume,
+                        self.adm_volumes_client,
+                        volume['id'])
 
         # Create a volume transfer
         transfer = self.client.create_volume_transfer(
             volume_id=volume['id'])['transfer']
         transfer_id = transfer['id']
         auth_key = transfer['auth_key']
-        waiters.wait_for_volume_status(self.client,
-                                       volume['id'], 'awaiting-transfer')
+        waiters.wait_for_volume_resource_status(
+            self.volumes_client, volume['id'], 'awaiting-transfer')
 
         # Get a volume transfer
         body = self.client.show_volume_transfer(transfer_id)['transfer']
@@ -59,21 +61,23 @@
         # Accept a volume transfer by alt_tenant
         body = self.alt_client.accept_volume_transfer(
             transfer_id, auth_key=auth_key)['transfer']
-        waiters.wait_for_volume_status(self.alt_client,
-                                       volume['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.alt_volumes_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()
-        self.addCleanup(self.delete_volume, self.adm_client, volume['id'])
+        self.addCleanup(self.delete_volume,
+                        self.adm_volumes_client,
+                        volume['id'])
 
         # Create a volume transfer
         body = self.client.create_volume_transfer(
             volume_id=volume['id'])['transfer']
         transfer_id = body['id']
-        waiters.wait_for_volume_status(self.client,
-                                       volume['id'], 'awaiting-transfer')
+        waiters.wait_for_volume_resource_status(
+            self.volumes_client, volume['id'], 'awaiting-transfer')
 
         # List all volume transfers (looking for the one we created)
         body = self.client.list_volume_transfers()['transfers']
@@ -85,8 +89,5 @@
 
         # Delete a volume transfer
         self.client.delete_volume_transfer(transfer_id)
-        waiters.wait_for_volume_status(self.client, volume['id'], 'available')
-
-
-class VolumesV1TransfersTest(VolumesV2TransfersTest):
-    _api_version = 1
+        waiters.wait_for_volume_resource_status(
+            self.volumes_client, volume['id'], 'available')
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index d8d6b9a..a2a3d27 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -14,22 +14,22 @@
 #    under the License.
 
 from tempest.api.volume import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 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 import test
 
 CONF = config.CONF
 
 
-class VolumesV2ActionsTest(base.BaseVolumeTest):
+class VolumesActionsTest(base.BaseVolumeTest):
 
     @classmethod
     def setup_clients(cls):
-        super(VolumesV2ActionsTest, cls).setup_clients()
-        cls.client = cls.volumes_client
+        super(VolumesActionsTest, cls).setup_clients()
         if CONF.service_available.glance:
             # Check if glance v1 is available to determine which client to use.
             if CONF.image_feature_enabled.api_v1:
@@ -43,35 +43,35 @@
 
     @classmethod
     def resource_setup(cls):
-        super(VolumesV2ActionsTest, cls).resource_setup()
+        super(VolumesActionsTest, cls).resource_setup()
 
         # 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):
         # Create a server
         server = self.create_server(wait_until='ACTIVE')
         # Volume is attached and detached successfully from an instance
-        self.client.attach_volume(self.volume['id'],
-                                  instance_uuid=server['id'],
-                                  mountpoint='/dev/%s' %
-                                             CONF.compute.volume_device_name)
-        waiters.wait_for_volume_status(self.client,
-                                       self.volume['id'], 'in-use')
-        self.client.detach_volume(self.volume['id'])
-        waiters.wait_for_volume_status(self.client,
-                                       self.volume['id'], 'available')
+        self.volumes_client.attach_volume(self.volume['id'],
+                                          instance_uuid=server['id'],
+                                          mountpoint='/dev/%s' %
+                                          CONF.compute.volume_device_name)
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                self.volume['id'], 'in-use')
+        self.volumes_client.detach_volume(self.volume['id'])
+        waiters.wait_for_volume_resource_status(self.volumes_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]:
-            self.client.set_bootable_volume(self.volume['id'],
-                                            bootable=bool_bootable)
-            fetched_volume = self.client.show_volume(
+            self.volumes_client.set_bootable_volume(self.volume['id'],
+                                                    bootable=bool_bootable)
+            fetched_volume = self.volumes_client.show_volume(
                 self.volume['id'])['volume']
             # Get Volume information
             # NOTE(masayukig): 'bootable' is "true" or "false" in the current
@@ -80,23 +80,24 @@
             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
         server = self.create_server(wait_until='ACTIVE')
         # Verify that a volume's attachment information is retrieved
-        self.client.attach_volume(self.volume['id'],
-                                  instance_uuid=server['id'],
-                                  mountpoint='/dev/%s' %
-                                             CONF.compute.volume_device_name)
-        waiters.wait_for_volume_status(self.client,
-                                       self.volume['id'], 'in-use')
-        self.addCleanup(waiters.wait_for_volume_status, self.client,
-                        self.volume['id'],
-                        'available')
-        self.addCleanup(self.client.detach_volume, self.volume['id'])
-        volume = self.client.show_volume(self.volume['id'])['volume']
+        self.volumes_client.attach_volume(self.volume['id'],
+                                          instance_uuid=server['id'],
+                                          mountpoint='/dev/%s' %
+                                          CONF.compute.volume_device_name)
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                self.volume['id'],
+                                                'in-use')
+        self.addCleanup(waiters.wait_for_volume_resource_status,
+                        self.volumes_client,
+                        self.volume['id'], 'available')
+        self.addCleanup(self.volumes_client.detach_volume, self.volume['id'])
+        volume = self.volumes_client.show_volume(self.volume['id'])['volume']
         self.assertIn('attachments', volume)
         attachment = volume['attachments'][0]
 
@@ -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,
@@ -115,7 +116,7 @@
         # there is no way to delete it from Cinder, so we delete it from Glance
         # using the Glance image_client and from Cinder via tearDownClass.
         image_name = data_utils.rand_name(self.__class__.__name__ + '-Image')
-        body = self.client.upload_volume(
+        body = self.volumes_client.upload_volume(
             self.volume['id'], image_name=image_name,
             disk_format=CONF.volume.disk_format)['os-volume_upload_image']
         image_id = body["image_id"]
@@ -123,37 +124,33 @@
                         self.image_client.delete_image,
                         image_id)
         waiters.wait_for_image_status(self.image_client, image_id, 'active')
-        waiters.wait_for_volume_status(self.client,
-                                       self.volume['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.volumes_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'])
+        body = self.volumes_client.reserve_volume(self.volume['id'])
         # To get the volume info
-        body = self.client.show_volume(self.volume['id'])['volume']
+        body = self.volumes_client.show_volume(self.volume['id'])['volume']
         self.assertIn('attaching', body['status'])
         # Unmark volume as reserved.
-        body = self.client.unreserve_volume(self.volume['id'])
+        body = self.volumes_client.unreserve_volume(self.volume['id'])
         # To get the volume info
-        body = self.client.show_volume(self.volume['id'])['volume']
+        body = self.volumes_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
-            self.client.update_volume_readonly(self.volume['id'],
-                                               readonly=readonly)
+            self.volumes_client.update_volume_readonly(self.volume['id'],
+                                                       readonly=readonly)
             # Get Volume information
-            fetched_volume = self.client.show_volume(
+            fetched_volume = self.volumes_client.show_volume(
                 self.volume['id'])['volume']
             # NOTE(masayukig): 'readonly' is "True" or "False" in the current
             # cinder implementation. So we need to cast boolean values to str
             # to compare here.
             self.assertEqual(str(readonly),
                              fetched_volume['metadata']['readonly'])
-
-
-class VolumesV1ActionsTest(VolumesV2ActionsTest):
-    _api_version = 1
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 70b3c58..5ad209c 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -13,20 +13,24 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+from testtools import matchers
+
 from tempest.api.volume import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
 
 
-class VolumesBackupsV2Test(base.BaseVolumeTest):
+class VolumesBackupsTest(base.BaseVolumeTest):
 
     @classmethod
     def skip_checks(cls):
-        super(VolumesBackupsV2Test, cls).skip_checks()
+        super(VolumesBackupsTest, cls).skip_checks()
         if not CONF.volume_feature_enabled.backup:
             raise cls.skipException("Cinder backup feature disabled")
 
@@ -39,33 +43,42 @@
         self.addCleanup(self.volumes_client.delete_volume,
                         restored_volume['volume_id'])
         self.assertEqual(backup_id, restored_volume['backup_id'])
-        waiters.wait_for_backup_status(self.backups_client,
-                                       backup_id, 'available')
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       restored_volume['volume_id'],
-                                       'available')
+        waiters.wait_for_volume_resource_status(self.backups_client,
+                                                backup_id, 'available')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                restored_volume['volume_id'],
+                                                'available')
         return restored_volume
 
-    @test.idempotent_id('a66eb488-8ee1-47d4-8e9f-575a095728c6')
+    @testtools.skipIf(CONF.volume.storage_protocol == 'ceph',
+                      'ceph does not support arbitrary container names')
+    @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()
+        # Create a volume with metadata
+        metadata = {"vol-meta1": "value1",
+                    "vol-meta2": "value2",
+                    "vol-meta3": "value3"}
+        volume = self.create_volume(metadata=metadata)
         self.addCleanup(self.volumes_client.delete_volume,
                         volume['id'])
+
+        # Create a backup
         backup_name = data_utils.rand_name(
             self.__class__.__name__ + '-Backup')
         description = data_utils.rand_name("volume-backup-description")
         backup = self.create_backup(volume_id=volume['id'],
                                     name=backup_name,
-                                    description=description)
+                                    description=description,
+                                    container='container')
         self.assertEqual(backup_name, backup['name'])
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'available')
 
         # Get a given backup
         backup = self.backups_client.show_backup(backup['id'])['backup']
         self.assertEqual(backup_name, backup['name'])
         self.assertEqual(description, backup['description'])
+        self.assertEqual('container', backup['container'])
 
         # Get all backups with detail
         backups = self.backups_client.list_backups(
@@ -73,9 +86,17 @@
         self.assertIn((backup['name'], backup['id']),
                       [(m['name'], m['id']) for m in backups])
 
-        self.restore_backup(backup['id'])
+        restored_volume = self.restore_backup(backup['id'])
 
-    @test.idempotent_id('07af8f6d-80af-44c9-a5dc-c8427b1b62e6')
+        restored_volume_metadata = self.volumes_client.show_volume(
+            restored_volume['volume_id'])['volume']['metadata']
+
+        # Verify the backups has been restored successfully
+        # with the metadata of the source volume.
+        self.assertThat(restored_volume_metadata.items(),
+                        matchers.ContainsAll(metadata.items()))
+
+    @decorators.idempotent_id('07af8f6d-80af-44c9-a5dc-c8427b1b62e6')
     @test.services('compute')
     def test_backup_create_attached_volume(self):
         """Test backup create using force flag.
@@ -89,14 +110,7 @@
                         volume['id'])
         server = self.create_server(wait_until='ACTIVE')
         # Attach volume to instance
-        self.servers_client.attach_volume(server['id'],
-                                          volumeId=volume['id'])
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume['id'], 'in-use')
-        self.addCleanup(waiters.wait_for_volume_status, self.volumes_client,
-                        volume['id'], 'available')
-        self.addCleanup(self.servers_client.detach_volume, server['id'],
-                        volume['id'])
+        self.attach_volume(server['id'], volume['id'])
         # Create backup using force flag
         backup_name = data_utils.rand_name(
             self.__class__.__name__ + '-Backup')
@@ -104,7 +118,9 @@
                                     name=backup_name, force=True)
         self.assertEqual(backup_name, backup['name'])
 
-    @test.idempotent_id('2a8ba340-dff2-4511-9db7-646f07156b15')
+    @testtools.skipUnless(CONF.service_available.glance,
+                          "Glance is not available")
+    @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
@@ -125,7 +141,3 @@
             restored_volume_id)['volume']
 
         self.assertEqual('true', restored_volume_info['bootable'])
-
-
-class VolumesBackupsV1Test(VolumesBackupsV2Test):
-    _api_version = 1
diff --git a/tempest/api/volume/test_volumes_clone.py b/tempest/api/volume/test_volumes_clone.py
index 2cedb4e..a6bbb0a 100644
--- a/tempest/api/volume/test_volumes_clone.py
+++ b/tempest/api/volume/test_volumes_clone.py
@@ -13,23 +13,25 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 from tempest.api.volume import base
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 
 CONF = config.CONF
 
 
-class VolumesV2CloneTest(base.BaseVolumeTest):
+class VolumesCloneTest(base.BaseVolumeTest):
 
     @classmethod
     def skip_checks(cls):
-        super(VolumesV2CloneTest, cls).skip_checks()
+        super(VolumesCloneTest, cls).skip_checks()
         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.
@@ -43,9 +45,11 @@
         volume = self.volumes_client.show_volume(dst_vol['id'])['volume']
         # Should allow
         self.assertEqual(volume['source_volid'], src_vol['id'])
-        self.assertEqual(int(volume['size']), src_size + 1)
+        self.assertEqual(volume['size'], src_size + 1)
 
-    @test.idempotent_id('cbbcd7c6-5a6c-481a-97ac-ca55ab715d16')
+    @testtools.skipUnless(CONF.service_available.glance,
+                          "Glance is not available")
+    @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
@@ -60,7 +64,3 @@
         self.assertEqual('true', cloned_vol_details['bootable'])
         self.assertEqual(src_vol['id'], cloned_vol_details['source_volid'])
         self.assertEqual(src_vol['size'], cloned_vol_details['size'])
-
-
-class VolumesV1CloneTest(VolumesV2CloneTest):
-    _api_version = 1
diff --git a/tempest/api/volume/test_volumes_clone_negative.py b/tempest/api/volume/test_volumes_clone_negative.py
index 5c54e1e..9169c19 100644
--- a/tempest/api/volume/test_volumes_clone_negative.py
+++ b/tempest/api/volume/test_volumes_clone_negative.py
@@ -15,22 +15,23 @@
 
 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
 
 
-class VolumesV2CloneNegativeTest(base.BaseVolumeTest):
+class VolumesCloneNegativeTest(base.BaseVolumeTest):
 
     @classmethod
     def skip_checks(cls):
-        super(VolumesV2CloneNegativeTest, cls).skip_checks()
+        super(VolumesCloneNegativeTest, cls).skip_checks()
         if not CONF.volume_feature_enabled.clone:
             raise cls.skipException("Cinder volume clones are disabled")
 
-    @test.idempotent_id('9adae371-a257-43a5-459a-dc7c88e66e0e')
+    @test.attr(type=['negative'])
+    @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.
@@ -42,7 +43,3 @@
                           self.volumes_client.create_volume,
                           size=src_size - 1,
                           source_volid=src_vol['id'])
-
-
-class VolumesV1CloneNegativeTest(VolumesV2CloneNegativeTest):
-    _api_version = 1
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index c3d6dbb..84ecb22 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -15,23 +15,19 @@
 
 from tempest.api.volume import base
 from tempest.common import waiters
-from tempest import test
+from tempest.lib import decorators
 
 
-class VolumesV2ExtendTest(base.BaseVolumeTest):
+class VolumesExtendTest(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()
-        extend_size = int(self.volume['size']) + 1
-        self.volumes_client.extend_volume(self.volume['id'],
+        volume = self.create_volume()
+        extend_size = volume['size'] + 1
+        self.volumes_client.extend_volume(volume['id'],
                                           new_size=extend_size)
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       self.volume['id'], 'available')
-        volume = self.volumes_client.show_volume(self.volume['id'])['volume']
-        self.assertEqual(int(volume['size']), extend_size)
-
-
-class VolumesV1ExtendTest(VolumesV2ExtendTest):
-    _api_version = 1
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'available')
+        volume = self.volumes_client.show_volume(volume['id'])['volume']
+        self.assertEqual(volume['size'], extend_size)
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 65e461c..65027bf 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -17,33 +17,31 @@
 from testtools import matchers
 
 from tempest.api.volume import base
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
 
 
-class VolumesV2GetTest(base.BaseVolumeTest):
+class VolumesGetTest(base.BaseVolumeTest):
 
     def _volume_create_get_update_delete(self, **kwargs):
-        name_field = self.special_fields['name_field']
-        descrip_field = self.special_fields['descrip_field']
-
         # Create a volume, Get it's details and Delete the volume
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
         metadata = {'Type': 'Test'}
         # Create a volume
-        kwargs[name_field] = v_name
+        kwargs['name'] = v_name
         kwargs['metadata'] = metadata
         volume = self.volumes_client.create_volume(**kwargs)['volume']
         self.assertIn('id', volume)
         self.addCleanup(self.delete_volume, self.volumes_client, volume['id'])
-        waiters.wait_for_volume_status(self.volumes_client, volume['id'],
-                                       'available')
-        self.assertIn(name_field, volume)
-        self.assertEqual(volume[name_field], v_name,
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'available')
+        self.assertIn('name', volume)
+        self.assertEqual(volume['name'], v_name,
                          "The created volume name is not equal "
                          "to the requested name")
 
@@ -51,7 +49,7 @@
         fetched_volume = self.volumes_client.show_volume(
             volume['id'])['volume']
         self.assertEqual(v_name,
-                         fetched_volume[name_field],
+                         fetched_volume['name'],
                          'The fetched Volume name is different '
                          'from the created Volume')
         self.assertEqual(volume['id'],
@@ -70,25 +68,25 @@
 
         # Update Volume
         # Test volume update when display_name is same with original value
-        params = {name_field: v_name}
+        params = {'name': v_name}
         self.volumes_client.update_volume(volume['id'], **params)
         # Test volume update when display_name is new
         new_v_name = data_utils.rand_name(
             self.__class__.__name__ + '-new-Volume')
         new_desc = 'This is the new description of volume'
-        params = {name_field: new_v_name,
-                  descrip_field: new_desc}
+        params = {'name': new_v_name,
+                  'description': new_desc}
         update_volume = self.volumes_client.update_volume(
             volume['id'], **params)['volume']
         # Assert response body for update_volume method
-        self.assertEqual(new_v_name, update_volume[name_field])
-        self.assertEqual(new_desc, update_volume[descrip_field])
+        self.assertEqual(new_v_name, update_volume['name'])
+        self.assertEqual(new_desc, update_volume['description'])
         # Assert response body for show_volume method
         updated_volume = self.volumes_client.show_volume(
             volume['id'])['volume']
         self.assertEqual(volume['id'], updated_volume['id'])
-        self.assertEqual(new_v_name, updated_volume[name_field])
-        self.assertEqual(new_desc, updated_volume[descrip_field])
+        self.assertEqual(new_v_name, updated_volume['name'])
+        self.assertEqual(new_desc, updated_volume['description'])
         self.assertThat(updated_volume['metadata'].items(),
                         matchers.ContainsAll(metadata.items()),
                         'The fetched Volume metadata misses data '
@@ -98,18 +96,18 @@
         # contains specific characters,
         # then test volume update if display_name is duplicated
         new_v_desc = data_utils.rand_name('@#$%^* description')
-        params = {descrip_field: new_v_desc,
+        params = {'description': new_v_desc,
                   'availability_zone': volume['availability_zone'],
                   'size': CONF.volume.volume_size}
         new_volume = self.volumes_client.create_volume(**params)['volume']
         self.assertIn('id', new_volume)
         self.addCleanup(self.delete_volume, self.volumes_client,
                         new_volume['id'])
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       new_volume['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                new_volume['id'], 'available')
 
-        params = {name_field: volume[name_field],
-                  descrip_field: volume[descrip_field]}
+        params = {'name': volume['name'],
+                  'description': volume['description']}
         self.volumes_client.update_volume(new_volume['id'], **params)
 
         if 'imageRef' in kwargs:
@@ -118,12 +116,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,14 +131,10 @@
         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):
         origin = self.create_volume()
         self._volume_create_get_update_delete(source_volid=origin['id'],
                                               size=CONF.volume.volume_size)
-
-
-class VolumesV1GetTest(VolumesV2GetTest):
-    _api_version = 1
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 030ea6c..b6b5ab4 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -13,16 +13,20 @@
 #    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 operator
 
+import operator
+import random
+
+from six.moves.urllib import parse
 from testtools import matchers
 
 from tempest.api.volume import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest import test
 
 
-class VolumesV2ListTestJSON(base.BaseVolumeTest):
+class VolumesListTestJSON(base.BaseVolumeTest):
     # NOTE: This test creates a number of 1G volumes. To run successfully,
     # ensure that the backing file for the volume group that Nova uses
     # has space for at least 3 1G volumes!
@@ -56,15 +60,20 @@
 
     @classmethod
     def resource_setup(cls):
-        super(VolumesV2ListTestJSON, cls).resource_setup()
+        super(VolumesListTestJSON, cls).resource_setup()
         cls.name = cls.VOLUME_FIELDS[1]
+
+        existing_volumes = cls.volumes_client.list_volumes()['volumes']
+        cls.volume_id_list = [vol['id'] for vol in existing_volumes]
+
         # Create 3 test volumes
         cls.volume_list = []
         cls.metadata = {'Type': 'work'}
-        for i in range(3):
+        for _ in range(3):
             volume = cls.create_volume(metadata=cls.metadata)
             volume = cls.volumes_client.show_volume(volume['id'])['volume']
             cls.volume_list.append(volume)
+            cls.volume_id_list.append(volume['id'])
 
     def _list_by_param_value_and_assert(self, params, with_detail=False):
         """list or list_details with given params and validates result"""
@@ -77,11 +86,7 @@
                 params=params)['volumes']
 
         # Validating params of fetched volumes
-        # In v2, only list detail view includes items in params.
-        # In v1, list view and list detail view are same. So the
-        # following check should be run when 'with_detail' is True
-        # or v1 tests.
-        if with_detail or self._api_version == 1:
+        if with_detail:
             for volume in fetched_vol_list:
                 for key in params:
                     msg = "Failed to list volumes %s by %s" % \
@@ -95,7 +100,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 +108,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 +125,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 +135,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 +144,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 +153,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 +167,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 +176,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 +187,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 +198,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 +218,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)]
@@ -221,7 +226,159 @@
                   'status': 'available'}
         self._list_by_param_value_and_assert(params, with_detail=True)
 
+    @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,
+                                               status='available',
+                                               sort_dir='asc',
+                                               sort_key='id'):
+            params = {'limit': limit,
+                      'status': status,
+                      'sort_dir': sort_dir,
+                      'sort_key': sort_key
+                      }
+            fetched_volume = self.volumes_client.list_volumes(
+                detail=True, params=params)['volumes']
+            self.assertEqual(limit, len(fetched_volume),
+                             "The count of volumes is %s, expected:%s " %
+                             (len(fetched_volume), limit))
+            self.assertEqual(status, fetched_volume[0]['status'])
+            self.assertEqual(status, fetched_volume[1]['status'])
+            val0 = fetched_volume[0][sort_key]
+            val1 = fetched_volume[1][sort_key]
+            if sort_dir == 'asc':
+                self.assertLess(val0, val1,
+                                "list is not in asc order with sort_key: %s."
+                                " %s" % (sort_key, fetched_volume))
+            elif sort_dir == 'desc':
+                self.assertGreater(val0, val1,
+                                   "list is not in desc order with sort_key: "
+                                   "%s. %s" % (sort_key, fetched_volume))
 
-class VolumesV1ListTestJSON(VolumesV2ListTestJSON):
-    _api_version = 1
-    VOLUME_FIELDS = ('id', 'display_name')
+        _list_details_with_multiple_params()
+        _list_details_with_multiple_params(sort_dir='desc')
+
+    def _test_pagination(self, resource, ids=None, limit=1, **kwargs):
+        """Check list pagination functionality for a resource.
+
+        This method requests the list of resources and follows pagination
+        links.
+
+        If an iterable is supplied in ids it will check that all ids are
+        retrieved and that only those are listed, that we will get a next
+        link for an empty page if the number of items is divisible by used
+        limit (this is expected behavior).
+
+        We can specify number of items per request using limit argument.
+        """
+
+        # Get list method for the type of resource from the client
+        client = getattr(self, resource + '_client')
+        method = getattr(client, 'list_' + resource)
+
+        # Include limit in params for list request
+        params = kwargs.pop('params', {})
+        params['limit'] = limit
+
+        # Store remaining items we are expecting from list
+        if ids is not None:
+            remaining = list(ids)
+        else:
+            remaining = None
+
+        # Mark that the current iteration is not from a 'next' link
+        next = None
+
+        while True:
+            # Get a list page
+            response = method(params=params, **kwargs)
+
+            # If we have to check ids
+            if remaining is not None:
+                # Confirm we receive expected number of elements
+                num_expected = min(len(remaining), limit)
+                self.assertEqual(num_expected, len(response[resource]),
+                                 'Requested %(#expect)d but got %(#received)d '
+                                 % {'#expect': num_expected,
+                                    '#received': len(response[resource])})
+
+                # For each received element
+                for element in response[resource]:
+                    element_id = element['id']
+                    # Check it's one of expected ids
+                    self.assertIn(element_id,
+                                  ids,
+                                  'Id %(id)s is not in expected ids %(ids)s' %
+                                  {'id': element_id, 'ids': ids})
+                    # If not in remaining, we have received it twice
+                    self.assertIn(element_id,
+                                  remaining,
+                                  'Id %s was received twice' % element_id)
+                    # We no longer expect it
+                    remaining.remove(element_id)
+
+            # If the current iteration is from a 'next' link, check that the
+            # absolute url is the same as the one used for this request
+            if next:
+                self.assertEqual(next, response.response['content-location'])
+
+            # Get next from response
+            next = None
+            for link in response.get(resource + '_links', ()):
+                if link['rel'] == 'next':
+                    next = link['href']
+                    break
+
+            # Check if we have next and we shouldn't or the other way around
+            if remaining is not None:
+                if remaining or (num_expected and len(ids) % limit == 0):
+                    self.assertIsNotNone(next, 'Missing link to next page')
+                else:
+                    self.assertIsNone(next, 'Unexpected link to next page')
+
+            # If we can follow to the next page, get params from url to make
+            # request in the form of a relative URL
+            if next:
+                params = parse.urlparse(next).query
+
+            # If cannot follow make sure it's because we have finished
+            else:
+                self.assertEqual([], remaining or [],
+                                 'No more pages reported, but still '
+                                 'missing ids %s' % remaining)
+                break
+
+    @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)
+
+    @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)
+
+    @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'
+        # parameter
+        random_volume = random.choice(self.volume_id_list)
+
+        params = {'marker': random_volume}
+
+        # Running volume list using marker parameter
+        vol_with_marker = self.volumes_client.list_volumes(
+            detail=True, params=params)['volumes']
+
+        # Fetching the index of the random volume from volume_id_list
+        index_marker = self.volume_id_list.index(random_volume)
+
+        # The expected list with marker parameter
+        verify_volume_list = self.volume_id_list[:index_marker]
+
+        failed_msg = "Failed to list volume details by marker"
+
+        # Validating the expected list is the same like the observed list
+        self.assertEqual(verify_volume_list,
+                         map(lambda x: x['id'],
+                             vol_with_marker[::-1]), failed_msg)
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index c45ace6..609a031 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -14,167 +14,134 @@
 #    under the License.
 
 from tempest.api.volume import base
-from tempest.common.utils import data_utils
+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 VolumesV2NegativeTest(base.BaseVolumeTest):
+class VolumesNegativeTest(base.BaseVolumeTest):
 
     @classmethod
     def resource_setup(cls):
-        super(VolumesV2NegativeTest, cls).resource_setup()
-
-        cls.name_field = cls.special_fields['name_field']
+        super(VolumesNegativeTest, cls).resource_setup()
 
         # Create a test shared instance and volume for attach/detach tests
         cls.volume = cls.create_volume()
         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'}
+        # Should not be able to create volume with invalid size in request
         self.assertRaises(lib_exc.BadRequest,
-                          self.volumes_client.create_volume,
-                          size='#$%', display_name=v_name, metadata=metadata)
+                          self.volumes_client.create_volume, size='#$%')
 
     @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'}
         self.assertRaises(lib_exc.BadRequest,
-                          self.volumes_client.create_volume,
-                          size='', display_name=v_name, metadata=metadata)
+                          self.volumes_client.create_volume, size='')
 
     @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'}
         self.assertRaises(lib_exc.BadRequest,
-                          self.volumes_client.create_volume,
-                          size='0', display_name=v_name, metadata=metadata)
+                          self.volumes_client.create_volume, size='0')
 
     @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'}
         self.assertRaises(lib_exc.BadRequest,
-                          self.volumes_client.create_volume,
-                          size='-1', display_name=v_name, metadata=metadata)
+                          self.volumes_client.create_volume, size='-1')
 
     @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'}
         self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
-                          size='1', volume_type=data_utils.rand_uuid(),
-                          display_name=v_name, metadata=metadata)
+                          size='1', volume_type=data_utils.rand_uuid())
 
     @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'}
         self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
-                          size='1', snapshot_id=data_utils.rand_uuid(),
-                          display_name=v_name, metadata=metadata)
+                          size='1', snapshot_id=data_utils.rand_uuid())
 
     @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'}
         self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
-                          size='1', source_volid=data_utils.rand_uuid(),
-                          display_name=v_name, metadata=metadata)
+                          size='1', source_volid=data_utils.rand_uuid())
 
     @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'}
         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())
 
     @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'}
         self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
-                          volume_id='#$%%&^&^', display_name=v_name,
-                          metadata=metadata)
+                          volume_id=data_utils.rand_name('invalid'))
 
     @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'}
         self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
-                          volume_id='', display_name=v_name,
-                          metadata=metadata)
+                          volume_id='')
 
     @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')
@@ -186,14 +153,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
@@ -202,7 +169,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'
@@ -211,7 +178,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
@@ -220,37 +187,37 @@
                           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
+        extend_size = self.volume['size'] + 1
         self.assertRaises(lib_exc.NotFound, self.volumes_client.extend_volume,
                           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
+        extend_size = self.volume['size'] + 1
         self.assertRaises(lib_exc.NotFound, self.volumes_client.extend_volume,
                           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'])
@@ -262,26 +229,26 @@
         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}
+        params = {'name': v_name}
         fetched_volume = self.volumes_client.list_volumes(
             params=params)['volumes']
         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}
+        params = {'name': v_name}
         fetched_volume = \
             self.volumes_client.list_volumes(
                 detail=True, params=params)['volumes']
         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(
@@ -289,14 +256,10 @@
         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 = \
             self.volumes_client.list_volumes(detail=True,
                                              params=params)['volumes']
         self.assertEqual(0, len(fetched_volume))
-
-
-class VolumesV1NegativeTest(VolumesV2NegativeTest):
-    _api_version = 1
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 6f85891..8ffc99d 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -10,36 +10,31 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from testtools import matchers
+
 from tempest.api.volume 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 import test
 
 CONF = config.CONF
 
 
-class VolumesV2SnapshotTestJSON(base.BaseVolumeTest):
+class VolumesSnapshotTestJSON(base.BaseVolumeTest):
 
     @classmethod
     def skip_checks(cls):
-        super(VolumesV2SnapshotTestJSON, cls).skip_checks()
+        super(VolumesSnapshotTestJSON, cls).skip_checks()
         if not CONF.volume_feature_enabled.snapshot:
             raise cls.skipException("Cinder volume snapshots are disabled")
 
     @classmethod
     def resource_setup(cls):
-        super(VolumesV2SnapshotTestJSON, cls).resource_setup()
+        super(VolumesSnapshotTestJSON, cls).resource_setup()
         cls.volume_origin = cls.create_volume()
-        cls.name_field = cls.special_fields['name_field']
-        cls.descrip_field = cls.special_fields['descrip_field']
 
-    def cleanup_snapshot(self, snapshot):
-        # Delete the snapshot
-        self.snapshots_client.delete_snapshot(snapshot['id'])
-        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
@@ -51,9 +46,9 @@
         snapshot = self.create_snapshot(self.volume_origin['id'],
                                         force=True)
         # Delete the snapshot
-        self.cleanup_snapshot(snapshot)
+        self.delete_snapshot(snapshot['id'])
 
-    @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
@@ -67,11 +62,11 @@
 
         # Delete the snapshots. Some snapshot implementations can take
         # different paths according to order they are deleted.
-        self.cleanup_snapshot(snapshot1)
-        self.cleanup_snapshot(snapshot3)
-        self.cleanup_snapshot(snapshot2)
+        self.delete_snapshot(snapshot1['id'])
+        self.delete_snapshot(snapshot3['id'])
+        self.delete_snapshot(snapshot2['id'])
 
-    @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):
 
@@ -88,14 +83,18 @@
 
         # Delete the snapshots. Some snapshot implementations can take
         # different paths according to order they are deleted.
-        self.cleanup_snapshot(snapshot3)
-        self.cleanup_snapshot(snapshot1)
-        self.cleanup_snapshot(snapshot2)
+        self.delete_snapshot(snapshot3['id'])
+        self.delete_snapshot(snapshot1['id'])
+        self.delete_snapshot(snapshot2['id'])
 
-    @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'])
+        # Create a snapshot with metadata
+        metadata = {"snap-meta1": "value1",
+                    "snap-meta2": "value2",
+                    "snap-meta3": "value3"}
+        snapshot = self.create_snapshot(self.volume_origin['id'],
+                                        metadata=metadata)
 
         # Get the snap and check for some of its details
         snap_get = self.snapshots_client.show_snapshot(
@@ -103,36 +102,42 @@
         self.assertEqual(self.volume_origin['id'],
                          snap_get['volume_id'],
                          "Referred volume origin mismatch")
+        self.assertEqual(self.volume_origin['size'], snap_get['size'])
+
+        # Verify snapshot metadata
+        self.assertThat(snap_get['metadata'].items(),
+                        matchers.ContainsAll(metadata.items()))
 
         # Compare also with the output from the list action
-        tracking_data = (snapshot['id'], snapshot[self.name_field])
+        tracking_data = (snapshot['id'], snapshot['name'])
         snaps_list = self.snapshots_client.list_snapshots()['snapshots']
-        snaps_data = [(f['id'], f[self.name_field]) for f in snaps_list]
+        snaps_data = [(f['id'], f['name']) for f in snaps_list]
         self.assertIn(tracking_data, snaps_data)
 
         # Updates snapshot with new values
         new_s_name = data_utils.rand_name(
             self.__class__.__name__ + '-new-snap')
         new_desc = 'This is the new description of snapshot.'
-        params = {self.name_field: new_s_name,
-                  self.descrip_field: new_desc}
+        params = {'name': new_s_name,
+                  'description': new_desc}
         update_snapshot = self.snapshots_client.update_snapshot(
             snapshot['id'], **params)['snapshot']
         # Assert response body for update_snapshot method
-        self.assertEqual(new_s_name, update_snapshot[self.name_field])
-        self.assertEqual(new_desc, update_snapshot[self.descrip_field])
+        self.assertEqual(new_s_name, update_snapshot['name'])
+        self.assertEqual(new_desc, update_snapshot['description'])
         # Assert response body for show_snapshot method
         updated_snapshot = self.snapshots_client.show_snapshot(
             snapshot['id'])['snapshot']
-        self.assertEqual(new_s_name, updated_snapshot[self.name_field])
-        self.assertEqual(new_desc, updated_snapshot[self.descrip_field])
+        self.assertEqual(new_s_name, updated_snapshot['name'])
+        self.assertEqual(new_desc, updated_snapshot['description'])
 
         # Delete the snapshot
-        self.cleanup_snapshot(snapshot)
+        self.delete_snapshot(snapshot['id'])
 
-    @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
+        # Creates a volume from a snapshot passing a size
+        # different from the source
         src_size = CONF.volume.volume_size
 
         src_vol = self.create_volume(size=src_size)
@@ -152,8 +157,4 @@
         volume = self.volumes_client.show_volume(dst_vol['id'])['volume']
         # Should allow
         self.assertEqual(volume['snapshot_id'], src_snap['id'])
-        self.assertEqual(int(volume['size']), src_size + 1)
-
-
-class VolumesV1SnapshotTestJSON(VolumesV2SnapshotTestJSON):
-    _api_version = 1
+        self.assertEqual(volume['size'], src_size + 1)
diff --git a/tempest/api/volume/test_volumes_snapshots_list.py b/tempest/api/volume/test_volumes_snapshots_list.py
index 4416bef..507df1f 100644
--- a/tempest/api/volume/test_volumes_snapshots_list.py
+++ b/tempest/api/volume/test_volumes_snapshots_list.py
@@ -13,27 +13,29 @@
 from tempest.api.volume import base
 from tempest import config
 from tempest.lib import decorators
-from tempest import test
 
 CONF = config.CONF
 
 
-class VolumesV2SnapshotListTestJSON(base.BaseVolumeTest):
+class VolumesSnapshotListTestJSON(base.BaseVolumeTest):
 
     @classmethod
     def skip_checks(cls):
-        super(VolumesV2SnapshotListTestJSON, cls).skip_checks()
+        super(VolumesSnapshotListTestJSON, cls).skip_checks()
         if not CONF.volume_feature_enabled.snapshot:
             raise cls.skipException("Cinder volume snapshots are disabled")
 
     @classmethod
     def resource_setup(cls):
-        super(VolumesV2SnapshotListTestJSON, cls).resource_setup()
-        cls.volume_origin = cls.create_volume()
-        cls.name_field = cls.special_fields['name_field']
+        super(VolumesSnapshotListTestJSON, cls).resource_setup()
+        cls.snapshot_id_list = []
+        volume_origin = cls.create_volume()
+
         # Create snapshots with params
-        for _ in range(2):
-            cls.snapshot = cls.create_snapshot(cls.volume_origin['id'])
+        for _ in range(3):
+            snapshot = cls.create_snapshot(volume_origin['id'])
+            cls.snapshot_id_list.append(snapshot['id'])
+        cls.snapshot = snapshot
 
     def _list_by_param_values_and_assert(self, with_detail=False, **params):
         """list or list_details with given params and validates result."""
@@ -56,11 +58,11 @@
         # 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
-        params = {self.name_field: self.snapshot[self.name_field]}
+        params = {'name': self.snapshot['name']}
         self._list_by_param_values_and_assert(**params)
 
         # Verify list snapshots by status filter
@@ -69,29 +71,29 @@
 
         # Verify list snapshots by status and display name filter
         params = {'status': 'available',
-                  self.name_field: self.snapshot[self.name_field]}
+                  'name': self.snapshot['name']}
         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
-        params = {self.name_field: self.snapshot[self.name_field]}
+        params = {'name': self.snapshot['name']}
         self._list_by_param_values_and_assert(with_detail=True, **params)
         # Verify list snapshot details by status filter
         params = {'status': 'available'}
         self._list_by_param_values_and_assert(with_detail=True, **params)
         # Verify list snapshot details by status and display name filter
         params = {'status': 'available',
-                  self.name_field: self.snapshot[self.name_field]}
+                  'name': self.snapshot['name']}
         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
@@ -99,18 +101,60 @@
         self._list_snapshots_by_param_limit(limit=100000,
                                             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)
 
-    def cleanup_snapshot(self, snapshot):
-        # Delete the snapshot
-        self.snapshots_client.delete_snapshot(snapshot['id'])
-        self.snapshots_client.wait_for_resource_deletion(snapshot['id'])
-        self.snapshots.remove(snapshot)
+    def _list_snapshots_param_sort(self, sort_key, sort_dir):
+        """list snapshots by sort param"""
+        snap_list = self.snapshots_client.list_snapshots(
+            sort_key=sort_key, sort_dir=sort_dir)['snapshots']
+        self.assertNotEmpty(snap_list)
+        if sort_key is 'display_name':
+            sort_key = 'name'
+        # Note: On Cinder API, 'display_name' works as a sort key
+        # on a request, a volume name appears as 'name' on the response.
+        # So Tempest needs to change the key name here for this inconsistent
+        # API behavior.
+        sorted_list = [snapshot[sort_key] for snapshot in snap_list]
+        msg = 'The list of snapshots was not sorted correctly.'
+        self.assertEqual(sorted(sorted_list, reverse=(sort_dir == 'desc')),
+                         sorted_list, msg)
 
+    @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')
 
-class VolumesV1SnapshotLimitTestJSON(VolumesV2SnapshotListTestJSON):
-    _api_version = 1
+    @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')
+
+    @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')
+
+    @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')
+
+    @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')
+
+    @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')
+
+    @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 = [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.
+        self.assertEqual(self.snapshot_id_list[:1], fetched_list_id)
diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py
index 1f5bb0d..2e30d04 100644
--- a/tempest/api/volume/test_volumes_snapshots_negative.py
+++ b/tempest/api/volume/test_volumes_snapshots_negative.py
@@ -11,24 +11,25 @@
 #    under the License.
 
 from tempest.api.volume 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
 
 
-class VolumesV2SnapshotNegativeTestJSON(base.BaseVolumeTest):
+class VolumesSnapshotNegativeTestJSON(base.BaseVolumeTest):
 
     @classmethod
     def skip_checks(cls):
-        super(VolumesV2SnapshotNegativeTestJSON, cls).skip_checks()
+        super(VolumesSnapshotNegativeTestJSON, cls).skip_checks()
         if not CONF.volume_feature_enabled.snapshot:
             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,8 @@
                           self.snapshots_client.create_snapshot,
                           volume_id=None, display_name=s_name)
 
-    @test.idempotent_id('677863d1-34f9-456d-b6ac-9924f667a7f4')
+    @test.attr(type=['negative'])
+    @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
@@ -60,6 +62,23 @@
                           size=src_size - 1,
                           snapshot_id=src_snap['id'])
 
+    @test.attr(type=['negative'])
+    @decorators.idempotent_id('8fd92339-e22f-4591-86b4-1e2215372a40')
+    def test_list_snapshot_invalid_param_limit(self):
+        self.assertRaises(lib_exc.BadRequest,
+                          self.snapshots_client.list_snapshots,
+                          limit='invalid')
 
-class VolumesV1SnapshotNegativeTestJSON(VolumesV2SnapshotNegativeTestJSON):
-    _api_version = 1
+    @test.attr(type=['negative'])
+    @decorators.idempotent_id('27b5f37f-bf69-4e8c-986e-c44f3d6819b8')
+    def test_list_snapshots_invalid_param_sort(self):
+        self.assertRaises(lib_exc.BadRequest,
+                          self.snapshots_client.list_snapshots,
+                          sort_key='invalid')
+
+    @test.attr(type=['negative'])
+    @decorators.idempotent_id('b68deeda-ca79-4a32-81af-5c51179e553a')
+    def test_list_snapshots_invalid_param_marker(self):
+        self.assertRaises(lib_exc.NotFound,
+                          self.snapshots_client.list_snapshots,
+                          marker=data_utils.rand_uuid())
diff --git a/tempest/api/volume/v2/__init__.py b/tempest/api/volume/v2/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api/volume/v2/__init__.py
+++ /dev/null
diff --git a/tempest/api/volume/v2/test_volumes_list.py b/tempest/api/volume/v2/test_volumes_list.py
deleted file mode 100644
index fb8c65d..0000000
--- a/tempest/api/volume/v2/test_volumes_list.py
+++ /dev/null
@@ -1,204 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# Copyright 2013 IBM Corp.
-# 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 random
-from six.moves.urllib import parse
-
-from tempest.api.volume import base
-from tempest.lib import decorators
-from tempest import test
-
-
-class VolumesV2ListTestJSON(base.BaseVolumeTest):
-    """volumes v2 specific tests.
-
-    This test creates a number of 1G volumes. To run successfully,
-    ensure that the backing file for the volume group that Nova uses
-    has space for at least 3 1G volumes!
-    If you are running a Devstack environment, ensure that the
-    VOLUME_BACKING_FILE_SIZE is at least 4G in your localrc
-    """
-
-    @classmethod
-    def resource_setup(cls):
-        super(VolumesV2ListTestJSON, cls).resource_setup()
-
-        # Create 3 test volumes
-        cls.metadata = {'Type': 'work'}
-        # NOTE(zhufl): When using pre-provisioned credentials, the project
-        # may have volumes other than those created below.
-        existing_volumes = cls.volumes_client.list_volumes()['volumes']
-        cls.volume_id_list = [vol['id'] for vol in existing_volumes]
-        for i in range(3):
-            volume = cls.create_volume(metadata=cls.metadata)
-            cls.volume_id_list.append(volume['id'])
-
-    @test.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,
-                                               status='available',
-                                               sort_dir='asc',
-                                               sort_key='id'):
-            params = {'limit': limit,
-                      'status': status,
-                      'sort_dir': sort_dir,
-                      'sort_key': sort_key
-                      }
-            fetched_volume = self.volumes_client.list_volumes(
-                detail=True, params=params)['volumes']
-            self.assertEqual(limit, len(fetched_volume),
-                             "The count of volumes is %s, expected:%s " %
-                             (len(fetched_volume), limit))
-            self.assertEqual(status, fetched_volume[0]['status'])
-            self.assertEqual(status, fetched_volume[1]['status'])
-            val0 = fetched_volume[0][sort_key]
-            val1 = fetched_volume[1][sort_key]
-            if sort_dir == 'asc':
-                self.assertLess(val0, val1,
-                                "list is not in asc order with sort_key: %s."
-                                " %s" % (sort_key, fetched_volume))
-            elif sort_dir == 'desc':
-                self.assertGreater(val0, val1,
-                                   "list is not in desc order with sort_key: "
-                                   "%s. %s" % (sort_key, fetched_volume))
-
-        _list_details_with_multiple_params()
-        _list_details_with_multiple_params(sort_dir='desc')
-
-    def _test_pagination(self, resource, ids=None, limit=1, **kwargs):
-        """Check list pagination functionality for a resource.
-
-        This method requests the list of resources and follows pagination
-        links.
-
-        If an iterable is supplied in ids it will check that all ids are
-        retrieved and that only those are listed, that we will get a next
-        link for an empty page if the number of items is divisible by used
-        limit (this is expected behavior).
-
-        We can specify number of items per request using limit argument.
-        """
-
-        # Get list method for the type of resource from the client
-        client = getattr(self, resource + '_client')
-        method = getattr(client, 'list_' + resource)
-
-        # Include limit in params for list request
-        params = kwargs.pop('params', {})
-        params['limit'] = limit
-
-        # Store remaining items we are expecting from list
-        if ids is not None:
-            remaining = list(ids)
-        else:
-            remaining = None
-
-        # Mark that the current iteration is not from a 'next' link
-        next = None
-
-        while True:
-            # Get a list page
-            response = method(params=params, **kwargs)
-
-            # If we have to check ids
-            if remaining is not None:
-                # Confirm we receive expected number of elements
-                num_expected = min(len(remaining), limit)
-                self.assertEqual(num_expected, len(response[resource]),
-                                 'Requested %(#expect)d but got %(#received)d '
-                                 % {'#expect': num_expected,
-                                    '#received': len(response[resource])})
-
-                # For each received element
-                for element in response[resource]:
-                    element_id = element['id']
-                    # Check it's one of expected ids
-                    self.assertIn(element_id,
-                                  ids,
-                                  'Id %(id)s is not in expected ids %(ids)s' %
-                                  {'id': element_id, 'ids': ids})
-                    # If not in remaining, we have received it twice
-                    self.assertIn(element_id,
-                                  remaining,
-                                  'Id %s was received twice' % element_id)
-                    # We no longer expect it
-                    remaining.remove(element_id)
-
-            # If the current iteration is from a 'next' link, check that the
-            # absolute url is the same as the one used for this request
-            if next:
-                self.assertEqual(next, response.response['content-location'])
-
-            # Get next from response
-            next = None
-            for link in response.get(resource + '_links', ()):
-                if link['rel'] == 'next':
-                    next = link['href']
-                    break
-
-            # Check if we have next and we shouldn't or the other way around
-            if remaining is not None:
-                if remaining or (num_expected and len(ids) % limit == 0):
-                    self.assertIsNotNone(next, 'Missing link to next page')
-                else:
-                    self.assertIsNone(next, 'Unexpected link to next page')
-
-            # If we can follow to the next page, get params from url to make
-            # request in the form of a relative URL
-            if next:
-                params = parse.urlparse(next).query
-
-            # If cannot follow make sure it's because we have finished
-            else:
-                self.assertEqual([], remaining or [],
-                                 'No more pages reported, but still '
-                                 'missing ids %s' % remaining)
-                break
-
-    @test.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')
-    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.skip_because(bug='1572765')
-    def test_volume_list_with_detail_param_marker(self):
-        # Choosing a random volume from a list of volumes for 'marker'
-        # parameter
-        random_volume = random.choice(self.volume_id_list)
-
-        params = {'marker': random_volume}
-
-        # Running volume list using marker parameter
-        vol_with_marker = self.volumes_client.list_volumes(
-            detail=True, params=params)['volumes']
-
-        # Fetching the index of the random volume from volume_id_list
-        index_marker = self.volume_id_list.index(random_volume)
-
-        # The expected list with marker parameter
-        verify_volume_list = self.volume_id_list[:index_marker]
-
-        failed_msg = "Failed to list volume details by marker"
-
-        # Validating the expected list is the same like the observed list
-        self.assertEqual(verify_volume_list,
-                         map(lambda x: x['id'],
-                             vol_with_marker[::-1]), failed_msg)
diff --git a/tempest/api/volume/v3/__init__.py b/tempest/api/volume/v3/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api/volume/v3/__init__.py
+++ /dev/null
diff --git a/tempest/api/volume/v3/base.py b/tempest/api/volume/v3/base.py
deleted file mode 100644
index 31fc1eb..0000000
--- a/tempest/api/volume/v3/base.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# Copyright 2016 Andrew Kerr
-# 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.api.volume import api_microversion_fixture
-from tempest.api.volume import base
-from tempest import config
-from tempest.lib.common import api_version_utils
-
-CONF = config.CONF
-
-
-class VolumesV3Test(api_version_utils.BaseMicroversionTest,
-                    base.BaseVolumeTest):
-    """Base test case class for all v3 Cinder API tests."""
-
-    _api_version = 3
-
-    @classmethod
-    def skip_checks(cls):
-        super(VolumesV3Test, cls).skip_checks()
-        api_version_utils.check_skip_with_microversion(
-            cls.min_microversion, cls.max_microversion,
-            CONF.volume.min_microversion, CONF.volume.max_microversion)
-
-    @classmethod
-    def resource_setup(cls):
-        super(VolumesV3Test, cls).resource_setup()
-        cls.request_microversion = (
-            api_version_utils.select_request_microversion(
-                cls.min_microversion,
-                CONF.volume.min_microversion))
-
-    @classmethod
-    def setup_clients(cls):
-        super(VolumesV3Test, cls).setup_clients()
-        cls.messages_client = cls.os.volume_v3_messages_client
-
-    def setUp(self):
-        super(VolumesV3Test, self).setUp()
-        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
-            self.request_microversion))
-
-
-class VolumesV3AdminTest(VolumesV3Test,
-                         base.BaseVolumeAdminTest):
-    """Base test case class for all v3 Volume Admin API tests."""
-
-    credentials = ['primary', 'admin']
-
-    @classmethod
-    def setup_clients(cls):
-        super(VolumesV3AdminTest, cls).setup_clients()
-        cls.admin_messages_client = cls.os_adm.volume_v3_messages_client
-        cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
diff --git a/tempest/clients.py b/tempest/clients.py
index e3466e5..01abfd8 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -19,7 +19,6 @@
 from tempest.lib import auth
 from tempest.lib import exceptions as lib_exc
 from tempest.lib.services import clients
-from tempest.lib.services import identity
 from tempest.services import object_storage
 from tempest.services import orchestration
 
@@ -32,20 +31,11 @@
 
     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, service=None, scope='project'):
+    def __init__(self, credentials, scope='project'):
         """Initialization of Manager class.
 
         Setup all services clients and make them available for tests cases.
         :param credentials: type Credentials or TestResources
-        :param service: Service name
         :param scope: default scope for tokens produced by the auth provider
         """
         _, identity_uri = get_auth_provider_class(credentials)
@@ -128,9 +118,15 @@
             self.image_member_client_v2 = self.image_v2.ImageMembersClient()
             self.namespaces_client = self.image_v2.NamespacesClient()
             self.resource_types_client = self.image_v2.ResourceTypesClient()
+            self.namespace_objects_client = \
+                self.image_v2.NamespaceObjectsClient()
             self.schemas_client = self.image_v2.SchemasClient()
             self.namespace_properties_client = \
                 self.image_v2.NamespacePropertiesClient()
+            self.namespace_tags_client = \
+                self.image_v2.NamespaceTagsClient()
+            self.image_versions_client = \
+                self.image_v2.VersionsClient()
 
     def _set_compute_clients(self):
         self.agents_client = self.compute.AgentsClient()
@@ -163,6 +159,7 @@
         self.aggregates_client = self.compute.AggregatesClient()
         self.services_client = self.compute.ServicesClient()
         self.tenant_usages_client = self.compute.TenantUsagesClient()
+        self.baremetal_nodes_client = self.compute.BaremetalNodesClient()
         self.hosts_client = self.compute.HostsClient()
         self.hypervisor_client = self.compute.HypervisorClient()
         self.instance_usages_audit_log_client = (
@@ -230,21 +227,25 @@
         self.credentials_client = self.identity_v3.CredentialsClient(
             **params_v3)
         self.groups_client = self.identity_v3.GroupsClient(**params_v3)
+        self.identity_versions_v3_client = self.identity_v3.VersionsClient(
+            **params_v3)
+        self.oauth_consumers_client = self.identity_v3.OAUTHConsumerClient(
+            **params_v3)
 
         # Token clients do not use the catalog. They only need default_params.
         # They read auth_url, so they should only be set if the corresponding
         # API version is marked as enabled
         if CONF.identity_feature_enabled.api_v2:
             if CONF.identity.uri:
-                self.token_client = identity.v2.TokenClient(
-                    CONF.identity.uri, **self.default_params)
+                self.token_client = self.identity_v2.TokenClient(
+                    auth_url=CONF.identity.uri)
             else:
                 msg = 'Identity v2 API enabled, but no identity.uri set'
                 raise lib_exc.InvalidConfiguration(msg)
         if CONF.identity_feature_enabled.api_v3:
             if CONF.identity.uri_v3:
-                self.token_v3_client = identity.v3.V3TokenClient(
-                    CONF.identity.uri_v3, **self.default_params)
+                self.token_v3_client = self.identity_v3.V3TokenClient(
+                    auth_url=CONF.identity.uri_v3)
             else:
                 msg = 'Identity v3 API enabled, but no identity.uri_v3 set'
                 raise lib_exc.InvalidConfiguration(msg)
@@ -260,11 +261,14 @@
         self.encryption_types_client = self.volume_v1.EncryptionTypesClient()
         self.encryption_types_v2_client = \
             self.volume_v2.EncryptionTypesClient()
+        self.snapshot_manage_v2_client = self.volume_v2.SnapshotManageClient()
         self.snapshots_client = self.volume_v1.SnapshotsClient()
         self.snapshots_v2_client = self.volume_v2.SnapshotsClient()
+        self.volume_manage_v2_client = self.volume_v2.VolumeManageClient()
         self.volumes_client = self.volume_v1.VolumesClient()
         self.volumes_v2_client = self.volume_v2.VolumesClient()
         self.volume_v3_messages_client = self.volume_v3.MessagesClient()
+        self.volume_v3_versions_client = self.volume_v3.VersionsClient()
         self.volume_types_client = self.volume_v1.TypesClient()
         self.volume_types_v2_client = self.volume_v2.TypesClient()
         self.volume_hosts_client = self.volume_v1.HostsClient()
@@ -283,6 +287,8 @@
             self.volume_v2.CapabilitiesClient()
         self.volume_scheduler_stats_v2_client = \
             self.volume_v2.SchedulerStatsClient()
+        self.volume_transfers_v2_client = \
+            self.volume_v2.TransfersClient()
 
     def _set_object_storage_clients(self):
         # Mandatory parameters (always defined)
diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py
index 5fa8b74..b36bf5c 100644
--- a/tempest/cmd/run.py
+++ b/tempest/cmd/run.py
@@ -21,7 +21,7 @@
 
  * **--regex/-r**: This is a selection regex like what testr uses. It will run
                    any tests that match on re.match() with the regex
- * **--smoke**: Run all the tests tagged as smoke
+ * **--smoke/-s**: Run all the tests tagged as smoke
 
 There are also the **--blacklist-file** and **--whitelist-file** options that
 let you pass a filepath to tempest run with the file format being a line
@@ -52,7 +52,7 @@
 There are several options to control how the tests are executed. By default
 tempest will run in parallel with a worker for each CPU present on the machine.
 If you want to adjust the number of workers use the **--concurrency** option
-and if you want to run tests serially use **--serial**
+and if you want to run tests serially use **--serial/-t**
 
 Running with Workspaces
 -----------------------
@@ -78,16 +78,26 @@
 subunit-trace output filter. But, if you would prefer a subunit v2 stream be
 output to STDOUT use the **--subunit** flag
 
+Combining Runs
+==============
+
+There are certain situations in which you want to split a single run of tempest
+across 2 executions of tempest run. (for example to run part of the tests
+serially and others in parallel) To accomplish this but still treat the results
+as a single run you can leverage the **--combine** option which will append
+the current run's results with the previous runs.
 """
 
 import io
 import os
 import sys
+import tempfile
 import threading
 
 from cliff import command
 from os_testr import regex_builder
 from os_testr import subunit_trace
+import six
 from testrepository.commands import run_argv
 
 from tempest.cmd import init
@@ -109,6 +119,12 @@
             return
         else:
             os.environ["TESTR_PDB"] = ""
+        # NOTE(dims): most of our .testr.conf try to test for PYTHON
+        # environment variable and fall back to "python", under python3
+        # if it does not exist. we should set it to the python3 executable
+        # to deal with this situation better for now.
+        if six.PY3 and 'PYTHON' not in os.environ:
+            os.environ['PYTHON'] = sys.executable
 
     def _create_testrepository(self):
         if not os.path.isdir('.testrepository'):
@@ -158,6 +174,12 @@
         else:
             print("No .testr.conf file was found for local execution")
             sys.exit(2)
+        if parsed_args.combine:
+            temp_stream = tempfile.NamedTemporaryFile()
+            return_code = run_argv(['tempest', 'last', '--subunit'], sys.stdin,
+                                   temp_stream, sys.stderr)
+            if return_code > 0:
+                sys.exit(return_code)
 
         regex = self._build_regex(parsed_args)
         if parsed_args.list_tests:
@@ -166,6 +188,16 @@
         else:
             options = self._build_options(parsed_args)
             returncode = self._run(regex, options)
+            if returncode > 0:
+                sys.exit(returncode)
+
+        if parsed_args.combine:
+            return_code = run_argv(['tempest', 'last', '--subunit'], sys.stdin,
+                                   temp_stream, sys.stderr)
+            if return_code > 0:
+                sys.exit(return_code)
+            returncode = run_argv(['tempest', 'load', temp_stream.name],
+                                  sys.stdin, sys.stdout, sys.stderr)
         sys.exit(returncode)
 
     def get_description(self):
@@ -191,7 +223,7 @@
                             help='Configuration file to run tempest with')
         # test selection args
         regex = parser.add_mutually_exclusive_group()
-        regex.add_argument('--smoke', action='store_true',
+        regex.add_argument('--smoke', '-s', action='store_true',
                            help="Run the smoke tests only")
         regex.add_argument('--regex', '-r', default='',
                            help='A normal testr selection regex used to '
@@ -218,12 +250,16 @@
                               action='store_true',
                               help='Run tests in parallel (this is the'
                                    ' default)')
-        parallel.add_argument('--serial', dest='parallel',
+        parallel.add_argument('--serial', '-t', dest='parallel',
                               action='store_false',
                               help='Run tests serially')
         # output args
         parser.add_argument("--subunit", action='store_true',
                             help='Enable subunit v2 output')
+        parser.add_argument("--combine", action='store_true',
+                            help='Combine the output of this run with the '
+                                 "previous run's as a combined stream in the "
+                                 "testr repository after it finish")
 
         parser.set_defaults(parallel=True)
         return parser
diff --git a/tempest/cmd/subunit_describe_calls.py b/tempest/cmd/subunit_describe_calls.py
index 0f868a9..8ee3055 100644
--- a/tempest/cmd/subunit_describe_calls.py
+++ b/tempest/cmd/subunit_describe_calls.py
@@ -294,7 +294,8 @@
             outfile.write(json.dumps(url_parser.test_logs))
         return
 
-    for test_name, items in url_parser.test_logs.iteritems():
+    for test_name in url_parser.test_logs:
+        items = url_parser.test_logs[test_name]
         sys.stdout.write('{0}\n'.format(test_name))
         if not items:
             sys.stdout.write('\n')
diff --git a/tempest/cmd/workspace.py b/tempest/cmd/workspace.py
index 3c58648..d2dc00d 100644
--- a/tempest/cmd/workspace.py
+++ b/tempest/cmd/workspace.py
@@ -151,7 +151,7 @@
         if not os.path.isfile(self.path):
             return
         with open(self.path, 'r') as f:
-            self.workspaces = yaml.load(f) or {}
+            self.workspaces = yaml.safe_load(f) or {}
 
 
 class TempestWorkspace(command.Command):
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 4f2fe67..38daffe 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -13,6 +13,14 @@
 #    See the License for the specific language governing permissions and
 #    limitations under the License.
 
+import base64
+import socket
+import struct
+import textwrap
+
+import six
+from six.moves.urllib import parse as urlparse
+
 from oslo_log import log as logging
 from oslo_utils import excutils
 
@@ -22,6 +30,11 @@
 from tempest.lib.common import rest_client
 from tempest.lib.common.utils import data_utils
 
+if six.PY2:
+    ord_func = ord
+else:
+    ord_func = int
+
 CONF = config.CONF
 
 LOG = logging.getLogger(__name__)
@@ -30,8 +43,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 +56,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
     """
 
@@ -100,24 +126,36 @@
             if wait_until is None:
                 wait_until = 'ACTIVE'
 
+        if 'user_data' not in kwargs:
+            # If nothing overrides the default user data script then run
+            # a simple script on the host to print networking info. This is
+            # to aid in debugging ssh failures.
+            script = '''
+                     #!/bin/sh
+                     echo "Printing {user} user authorized keys"
+                     cat ~{user}/.ssh/authorized_keys || true
+                     '''.format(user=CONF.validation.image_ssh_user)
+            script_clean = textwrap.dedent(script).lstrip().encode('utf8')
+            script_b64 = base64.b64encode(script_clean)
+            kwargs['user_data'] = script_b64
+
     if volume_backed:
         volume_name = data_utils.rand_name(__name__ + '-volume')
         volumes_client = clients.volumes_v2_client
-        if CONF.volume_feature_enabled.api_v1:
-            volumes_client = clients.volumes_client
-        volume = volumes_client.create_volume(
-            display_name=volume_name,
-            imageRef=image_id,
-            size=CONF.volume.volume_size)
-        waiters.wait_for_volume_status(volumes_client,
-                                       volume['volume']['id'], 'available')
+        params = {'name': volume_name,
+                  'imageRef': image_id,
+                  'size': CONF.volume.volume_size}
+        volume = volumes_client.create_volume(**params)
+        waiters.wait_for_volume_resource_status(volumes_client,
+                                                volume['volume']['id'],
+                                                'available')
 
         bd_map_v2 = [{
             'uuid': volume['volume']['id'],
             '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
@@ -194,3 +232,87 @@
             servers_client.shelve_offload_server(server_id)
             waiters.wait_for_server_status(servers_client, server_id,
                                            'SHELVED_OFFLOADED')
+
+
+def create_websocket(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)
+
+
+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_func(header[1]) & 127 > 0:
+                return self._socket.recv(ord_func(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_func(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.encode('utf8'))
+        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(b'\r\n\r\n') < 0:
+            data = self._socket.recv(4096)
+            self.response += data
diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py
index bf8d30e..e6b46ed 100644
--- a/tempest/common/credentials_factory.py
+++ b/tempest/common/credentials_factory.py
@@ -233,7 +233,6 @@
 class AdminManager(clients.Manager):
     """Manager that uses admin credentials for its managed client objects"""
 
-    def __init__(self, service=None):
+    def __init__(self):
         super(AdminManager, self).__init__(
-            credentials=get_configured_admin_credentials(),
-            service=service)
+            credentials=get_configured_admin_credentials())
diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py
index 8410541..ed11b21 100644
--- a/tempest/common/custom_matchers.py
+++ b/tempest/common/custom_matchers.py
@@ -14,7 +14,6 @@
 
 import re
 
-import six
 from testtools import helpers
 
 
@@ -217,7 +216,7 @@
     """
 
     def match(self, actual):
-        for key, value in six.iteritems(actual):
+        for key, value in actual.items():
             if key in ('content-length', 'x-account-bytes-used',
                        'x-account-container-count', 'x-account-object-count',
                        'x-container-bytes-used', 'x-container-object-count')\
diff --git a/tempest/common/dynamic_creds.py b/tempest/common/dynamic_creds.py
index 632a876..88fe26c 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -293,12 +293,12 @@
         return resp_body['subnet']
 
     def _create_router(self, router_name, tenant_id):
-        external_net_id = dict(
-            network_id=self.public_network_id)
-        resp_body = self.routers_admin_client.create_router(
-            name=router_name,
-            external_gateway_info=external_net_id,
-            tenant_id=tenant_id)
+        kwargs = {'name': router_name,
+                  'tenant_id': tenant_id}
+        if self.public_network_id:
+            kwargs['external_gateway_info'] = dict(
+                network_id=self.public_network_id)
+        resp_body = self.routers_admin_client.create_router(**kwargs)
         return resp_body['router']
 
     def _add_router_interface(self, router_id, subnet_id):
diff --git a/tempest/common/fixed_network.py b/tempest/common/fixed_network.py
index f50edbd..4032c90 100644
--- a/tempest/common/fixed_network.py
+++ b/tempest/common/fixed_network.py
@@ -11,6 +11,7 @@
 #    under the License.
 
 import copy
+
 from oslo_log import log as logging
 
 from tempest import exceptions
diff --git a/tempest/common/image.py b/tempest/common/image.py
index 95a7d1a..3618f7e 100644
--- a/tempest/common/image.py
+++ b/tempest/common/image.py
@@ -15,8 +15,6 @@
 
 import copy
 
-import six
-
 
 def get_image_meta_from_headers(resp):
     meta = {'properties': {}}
@@ -55,13 +53,13 @@
     if copy_from is not None:
         headers['x-glance-api-copy-from'] = copy_from
 
-    for key, value in six.iteritems(fields_copy.pop('properties', {})):
+    for key, value in fields_copy.pop('properties', {}).items():
         headers['x-image-meta-property-%s' % key] = str(value)
 
-    for key, value in six.iteritems(fields_copy.pop('api', {})):
+    for key, value in fields_copy.pop('api', {}).items():
         headers['x-glance-api-property-%s' % key] = str(value)
 
-    for key, value in six.iteritems(fields_copy):
+    for key, value in fields_copy.items():
         headers['x-image-meta-%s' % key] = str(value)
 
     return headers
diff --git a/tempest/common/preprov_creds.py b/tempest/common/preprov_creds.py
index 0b0f692..a92d16a 100644
--- a/tempest/common/preprov_creds.py
+++ b/tempest/common/preprov_creds.py
@@ -33,7 +33,7 @@
 def read_accounts_yaml(path):
     try:
         with open(path, 'r') as yaml_file:
-            accounts = yaml.load(yaml_file)
+            accounts = yaml.safe_load(yaml_file)
     except IOError:
         raise lib_exc.InvalidConfiguration(
             'The path for the test accounts file: %s '
@@ -120,7 +120,7 @@
             if 'resources' in account:
                 resources = account.pop('resources')
             temp_hash = hashlib.md5()
-            account_for_hash = dict((k, v) for (k, v) in six.iteritems(account)
+            account_for_hash = dict((k, v) for (k, v) in account.items()
                                     if k in cls.HASH_CRED_FIELDS)
             temp_hash.update(six.text_type(account_for_hash).encode('utf-8'))
             temp_hash_key = temp_hash.hexdigest()
diff --git a/tempest/common/utils/__init__.py b/tempest/common/utils/__init__.py
index b6565d1..84e31d0 100644
--- a/tempest/common/utils/__init__.py
+++ b/tempest/common/utils/__init__.py
@@ -19,10 +19,6 @@
 
 CONF = config.CONF
 
-PING_IPV4_COMMAND = 'ping -c 3 '
-PING_IPV6_COMMAND = 'ping6 -c 3 '
-PING_PACKET_LOSS_REGEX = '(\d{1,3})\.?\d*\% packet loss'
-
 
 class DataUtils(object):
     def __getattr__(self, attr):
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 009812e..9319d2a 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -10,17 +10,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import netaddr
 import re
-import six
-import sys
 import time
 
 from oslo_log import log as logging
 
 from tempest import config
-from tempest.lib.common import ssh
-from tempest.lib.common.utils import test_utils
+from tempest.lib.common.utils.linux import remote_client
 import tempest.lib.exceptions
 
 CONF = config.CONF
@@ -28,39 +24,11 @@
 LOG = logging.getLogger(__name__)
 
 
-def debug_ssh(function):
-    """Decorator to generate extra debug info in case off SSH failure"""
-    def wrapper(self, *args, **kwargs):
-        try:
-            return function(self, *args, **kwargs)
-        except tempest.lib.exceptions.SSHTimeout:
-            try:
-                original_exception = sys.exc_info()
-                caller = test_utils.find_test_caller() or "not found"
-                if self.server:
-                    msg = 'Caller: %s. Timeout trying to ssh to server %s'
-                    LOG.debug(msg, caller, self.server)
-                    if self.log_console and self.servers_client:
-                        try:
-                            msg = 'Console log for server %s: %s'
-                            console_log = (
-                                self.servers_client.get_console_output(
-                                    self.server['id'])['output'])
-                            LOG.debug(msg, self.server['id'], console_log)
-                        except Exception:
-                            msg = 'Could not get console_log for server %s'
-                            LOG.debug(msg, self.server['id'])
-                # re-raise the original ssh timeout exception
-                six.reraise(*original_exception)
-            finally:
-                # Delete the traceback to avoid circular references
-                _, _, trace = original_exception
-                del trace
-    return wrapper
+class RemoteClient(remote_client.RemoteClient):
 
-
-class RemoteClient(object):
-
+    # TODO(oomichi): Make this class deprecated after migrating
+    #                necessary methods to tempest.lib and cleaning
+    #                unnecessary methods up from this class.
     def __init__(self, ip_address, username, password=None, pkey=None,
                  server=None, servers_client=None):
         """Executes commands in a VM over ssh
@@ -72,46 +40,18 @@
         :param server: server dict, used for debugging purposes
         :param servers_client: servers client, used for debugging purposes
         """
-        self.server = server
-        self.servers_client = servers_client
-        ssh_timeout = CONF.validation.ssh_timeout
-        connect_timeout = CONF.validation.connect_timeout
-        self.log_console = CONF.compute_feature_enabled.console_output
+        super(RemoteClient, self).__init__(
+            ip_address, username, password=password, pkey=pkey,
+            server=server, servers_client=servers_client,
+            ssh_timeout=CONF.validation.ssh_timeout,
+            connect_timeout=CONF.validation.connect_timeout,
+            console_output_enabled=CONF.compute_feature_enabled.console_output,
+            ssh_shell_prologue=CONF.validation.ssh_shell_prologue,
+            ping_count=CONF.validation.ping_count,
+            ping_size=CONF.validation.ping_size)
 
-        self.ssh_client = ssh.Client(ip_address, username, password,
-                                     ssh_timeout, pkey=pkey,
-                                     channel_timeout=connect_timeout)
-
-    @debug_ssh
-    def exec_command(self, cmd):
-        # Shell options below add more clearness on failures,
-        # path is extended for some non-cirros guest oses (centos7)
-        cmd = CONF.validation.ssh_shell_prologue + " " + cmd
-        LOG.debug("Remote command: %s", cmd)
-        return self.ssh_client.exec_command(cmd)
-
-    @debug_ssh
-    def validate_authentication(self):
-        """Validate ssh connection and authentication
-
-           This method raises an Exception when the validation fails.
-        """
-        self.ssh_client.test_connection_auth()
-
-    def get_hostname(self):
-        # Get host name using command "hostname"
-        actual_hostname = self.exec_command("hostname").rstrip()
-        return actual_hostname
-
-    def get_ram_size_in_mb(self):
-        output = self.exec_command('free -m | grep Mem')
-        if output:
-            return output.split()[1]
-
-    def get_number_of_vcpus(self):
-        output = self.exec_command('grep -c ^processor /proc/cpuinfo')
-        return int(output)
-
+    # Note that this method will not work on SLES11 guests, as they do
+    # not support the TYPE column on lsblk
     def get_disks(self):
         # Select root disk devices as shown by lsblk
         command = 'lsblk -lb --nodeps'
@@ -141,21 +81,6 @@
         cmd = 'sudo sh -c "echo \\"%s\\" >/dev/console"' % message
         return self.exec_command(cmd)
 
-    def ping_host(self, host, count=CONF.validation.ping_count,
-                  size=CONF.validation.ping_size, nic=None):
-        addr = netaddr.IPAddress(host)
-        cmd = 'ping6' if addr.version == 6 else 'ping'
-        if nic:
-            cmd = 'sudo {cmd} -I {nic}'.format(cmd=cmd, nic=nic)
-        cmd += ' -c{0} -w{0} -s{1} {2}'.format(count, size, host)
-        return self.exec_command(cmd)
-
-    def set_mac_address(self, nic, address):
-        self.set_nic_state(nic=nic, state="down")
-        cmd = "sudo ip link set dev {0} address {1}".format(nic, address)
-        self.exec_command(cmd)
-        self.set_nic_state(nic=nic, state="up")
-
     def get_mac_address(self, nic=""):
         show_nic = "show {nic} ".format(nic=nic) if nic else ""
         cmd = "ip addr %s| awk '/ether/ {print $2}'" % show_nic
@@ -171,26 +96,6 @@
         nic = self.exec_command(cmd)
         return nic.strip().strip(":").lower()
 
-    def get_ip_list(self):
-        cmd = "ip address"
-        return self.exec_command(cmd)
-
-    def assign_static_ip(self, nic, addr):
-        cmd = "sudo ip addr add {ip}/{mask} dev {nic}".format(
-            ip=addr, mask=CONF.network.project_network_mask_bits,
-            nic=nic
-        )
-        return self.exec_command(cmd)
-
-    def set_nic_state(self, nic, state="up"):
-        cmd = "sudo ip link set {nic} {state}".format(nic=nic, state=state)
-        return self.exec_command(cmd)
-
-    def get_pids(self, pr_name):
-        # Get pid(s) of a process/program
-        cmd = "ps -ef | grep %s | grep -v 'grep' | awk {'print $1'}" % pr_name
-        return self.exec_command(cmd).split('\n')
-
     def get_dns_servers(self):
         cmd = 'cat /etc/resolv.conf'
         resolve_file = self.exec_command(cmd).strip().split('\n')
@@ -199,10 +104,6 @@
                        if len(l) and l[0] == 'nameserver']
         return dns_servers
 
-    def send_signal(self, pid, signum):
-        cmd = 'sudo /bin/kill -{sig} {pid}'.format(pid=pid, sig=signum)
-        return self.exec_command(cmd)
-
     def _renew_lease_udhcpc(self, fixed_ip=None):
         """Renews DHCP lease via udhcpc client. """
         file_path = '/var/run/udhcpc.'
@@ -210,14 +111,15 @@
         pid = self.exec_command('cat {path}{nic}.pid'.
                                 format(path=file_path, nic=nic_name))
         pid = pid.strip()
-        self.send_signal(pid, 'USR1')
+        cmd = 'sudo /bin/kill -{sig} {pid}'.format(pid=pid, sig='USR1')
+        self.exec_command(cmd)
 
     def _renew_lease_dhclient(self, fixed_ip=None):
         """Renews DHCP lease via dhclient client. """
         cmd = "sudo /sbin/dhclient -r && sudo /sbin/dhclient"
         self.exec_command(cmd)
 
-    def renew_lease(self, fixed_ip=None):
+    def renew_lease(self, fixed_ip=None, dhcp_client='udhcpc'):
         """Wrapper method for renewing DHCP lease via given client
 
         Supporting:
@@ -226,7 +128,6 @@
         """
         # TODO(yfried): add support for dhcpcd
         supported_clients = ['udhcpc', 'dhclient']
-        dhcp_client = CONF.scenario.dhcp_client
         if dhcp_client not in supported_clients:
             raise tempest.lib.exceptions.InvalidConfiguration(
                 '%s DHCP client unsupported' % dhcp_client)
diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py
index 88697c4..b15796f 100644
--- a/tempest/common/validation_resources.py
+++ b/tempest/common/validation_resources.py
@@ -15,7 +15,7 @@
 
 from tempest import config
 
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
 from tempest.lib import exceptions as lib_exc
 
 CONF = config.CONF
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index fe648a0..9c83c99 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -10,7 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-
+import re
 import time
 
 from oslo_log import log as logging
@@ -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)
+            raise lib_exc.DeleteErrorException(resource_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):
@@ -166,67 +179,52 @@
     raise lib_exc.TimeoutException(message)
 
 
-def wait_for_volume_status(client, volume_id, status):
-    """Waits for a Volume to reach a given status."""
-    body = client.show_volume(volume_id)['volume']
-    volume_status = body['status']
+def wait_for_volume_resource_status(client, resource_id, status):
+    """Waits for a volume resource to reach a given status.
+
+    This function is a common function for volume, snapshot and backup
+    resources. The function extracts the name of the desired resource from
+    the client class name of the resource.
+    """
+    resource_name = re.findall(r'(Volume|Snapshot|Backup)',
+                               client.__class__.__name__)[0].lower()
+    show_resource = getattr(client, 'show_' + resource_name)
+    resource_status = show_resource(resource_id)[resource_name]['status']
     start = int(time.time())
 
-    while volume_status != status:
+    while resource_status != status:
+        time.sleep(client.build_interval)
+        resource_status = show_resource(resource_id)[
+            '{}'.format(resource_name)]['status']
+        if resource_status == 'error' and resource_status != status:
+            raise exceptions.VolumeResourceBuildErrorException(
+                resource_name=resource_name, resource_id=resource_id)
+        if resource_name == 'volume' and resource_status == 'error_restoring':
+            raise exceptions.VolumeRestoreErrorException(volume_id=resource_id)
+
+        if int(time.time()) - start >= client.build_timeout:
+            message = ('%s %s failed to reach %s status (current %s) '
+                       'within the required time (%s s).' %
+                       (resource_name, resource_id, status, resource_status,
+                        client.build_timeout))
+            raise lib_exc.TimeoutException(message)
+
+
+def wait_for_volume_retype(client, volume_id, new_volume_type):
+    """Waits for a Volume to have a new volume type."""
+    body = client.show_volume(volume_id)['volume']
+    current_volume_type = body['volume_type']
+    start = int(time.time())
+
+    while current_volume_type != new_volume_type:
         time.sleep(client.build_interval)
         body = client.show_volume(volume_id)['volume']
-        volume_status = body['status']
-        if volume_status == 'error' and status != 'error':
-            raise exceptions.VolumeBuildErrorException(volume_id=volume_id)
-        if volume_status == 'error_restoring':
-            raise exceptions.VolumeRestoreErrorException(volume_id=volume_id)
+        current_volume_type = body['volume_type']
 
         if int(time.time()) - start >= client.build_timeout:
-            message = ('Volume %s failed to reach %s status (current %s) '
+            message = ('Volume %s failed to reach %s volume type (current %s) '
                        'within the required time (%s s).' %
-                       (volume_id, status, volume_status,
-                        client.build_timeout))
-            raise lib_exc.TimeoutException(message)
-
-
-def wait_for_snapshot_status(client, snapshot_id, status):
-    """Waits for a Snapshot to reach a given status."""
-    body = client.show_snapshot(snapshot_id)['snapshot']
-    snapshot_status = body['status']
-    start = int(time.time())
-
-    while snapshot_status != status:
-        time.sleep(client.build_interval)
-        body = client.show_snapshot(snapshot_id)['snapshot']
-        snapshot_status = body['status']
-        if snapshot_status == 'error':
-            raise exceptions.SnapshotBuildErrorException(
-                snapshot_id=snapshot_id)
-        if int(time.time()) - start >= client.build_timeout:
-            message = ('Snapshot %s failed to reach %s status (current %s) '
-                       'within the required time (%s s).' %
-                       (snapshot_id, status, snapshot_status,
-                        client.build_timeout))
-            raise lib_exc.TimeoutException(message)
-
-
-def wait_for_backup_status(client, backup_id, status):
-    """Waits for a Backup to reach a given status."""
-    body = client.show_backup(backup_id)['backup']
-    backup_status = body['status']
-    start = int(time.time())
-
-    while backup_status != status:
-        time.sleep(client.build_interval)
-        body = client.show_backup(backup_id)['backup']
-        backup_status = body['status']
-        if backup_status == 'error' and backup_status != status:
-            raise lib_exc.VolumeBackupException(backup_id=backup_id)
-
-        if int(time.time()) - start >= client.build_timeout:
-            message = ('Volume backup %s failed to reach %s status '
-                       '(current %s) within the required time (%s s).' %
-                       (backup_id, status, backup_status,
+                       (volume_id, new_volume_type, current_volume_type,
                         client.build_timeout))
             raise lib_exc.TimeoutException(message)
 
@@ -263,16 +261,16 @@
         time.sleep(client.build_interval)
 
 
-def wait_for_interface_status(client, server, port_id, status):
+def wait_for_interface_status(client, server_id, port_id, status):
     """Waits for an interface to reach a given status."""
-    body = (client.show_interface(server, port_id)
+    body = (client.show_interface(server_id, port_id)
             ['interfaceAttachment'])
     interface_status = body['port_state']
     start = int(time.time())
 
     while(interface_status != status):
         time.sleep(client.build_interval)
-        body = (client.show_interface(server, port_id)
+        body = (client.show_interface(server_id, port_id)
                 ['interfaceAttachment'])
         interface_status = body['port_state']
 
diff --git a/tempest/config.py b/tempest/config.py
index 80e6d2e..00c69b0 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -16,10 +16,10 @@
 from __future__ import print_function
 
 import functools
-import logging as std_logging
 import os
 import tempfile
 
+import debtcollector.removals
 from oslo_concurrency import lockutils
 from oslo_config import cfg
 from oslo_log import log as logging
@@ -133,7 +133,7 @@
     cfg.StrOpt('uri_v3',
                help='Full URI of the OpenStack Identity API (Keystone), v3'),
     cfg.StrOpt('auth_version',
-               default='v2',
+               default='v3',
                help="Identity API version to be used for authentication "
                     "for API tests."),
     cfg.StrOpt('region',
@@ -217,11 +217,13 @@
                      "entry all which indicates every extension is enabled. "
                      "Empty list indicates all extensions are disabled. "
                      "To get the list of extensions run: 'keystone discover'"),
-    # TODO(rodrigods): Remove the reseller flag when Kilo and Liberty is end
-    # of life.
-    cfg.BoolOpt('reseller',
+    # TODO(rodrigods): This is a feature flag for bug 1590578 which is fixed
+    # in Newton and Ocata. This option can be removed after Mitaka is end of
+    # life.
+    cfg.BoolOpt('forbid_global_implied_dsr',
                 default=False,
-                help='Does the environment support reseller?'),
+                help='Does the environment forbid global roles implying '
+                     'domain specific ones?'),
     cfg.BoolOpt('security_compliance',
                 default=False,
                 help='Does the environment have the security compliance '
@@ -281,7 +283,9 @@
     cfg.StrOpt('volume_device_name',
                default='vdb',
                help="Expected device name when a volume is attached to "
-                    "an instance"),
+                    "an instance. Not all hypervisors guarantee that they "
+                    "will respect the user defined device name, tests may "
+                    "fail if inappropriate device name is set."),
     cfg.IntOpt('shelved_offload_time',
                default=0,
                help='Time in seconds before a shelved instance is eligible '
@@ -308,8 +312,7 @@
                     "min_microversion and max_microversion. "
                     "If both values are not specified, Tempest avoids tests "
                     "which require a microversion. Valid values are string "
-                    "with format 'X.Y' or string 'latest'",
-                    deprecated_group='compute-feature-enabled'),
+                    "with format 'X.Y' or string 'latest'"),
     cfg.StrOpt('max_microversion',
                default=None,
                help="Upper version of the test target microversion range. "
@@ -318,20 +321,13 @@
                     "min_microversion and max_microversion. "
                     "If both values are not specified, Tempest avoids tests "
                     "which require a microversion. Valid values are string "
-                    "with format 'X.Y' or string 'latest'",
-                    deprecated_group='compute-feature-enabled'),
+                    "with format 'X.Y' or string 'latest'"),
 ]
 
 compute_features_group = cfg.OptGroup(name='compute-feature-enabled',
                                       title="Enabled Compute Service Features")
 
 ComputeFeaturesGroup = [
-    # NOTE(mriedem): This is a feature toggle for bug 1175464 which is fixed in
-    # mitaka and newton. This option can be removed after liberty-eol.
-    cfg.BoolOpt('allow_port_security_disabled',
-                default=False,
-                help='Does the test environment support creating ports in a '
-                     'network where port security is disabled?'),
     cfg.BoolOpt('disk_config',
                 default=True,
                 help="If false, skip disk config tests"),
@@ -497,7 +493,7 @@
                      "users can specify."),
     cfg.ListOpt('disk_formats',
                 default=['ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2',
-                         'vdi', 'iso'],
+                         'vdi', 'iso', 'vhdx'],
                 help="A list of image's disk formats "
                      "users can specify.")
 ]
@@ -508,14 +504,27 @@
 ImageFeaturesGroup = [
     cfg.BoolOpt('api_v2',
                 default=True,
-                help="Is the v2 image API enabled"),
+                help="Is the v2 image API enabled",
+                deprecated_for_removal=True,
+                deprecated_reason='Glance v1 APIs are deprecated and v2 APIs '
+                                  'are current one. In future, Tempest will '
+                                  'test v2 APIs only so this config option '
+                                  'will be removed.'),
     cfg.BoolOpt('api_v1',
                 default=True,
-                help="Is the v1 image API enabled"),
+                help="Is the v1 image API enabled",
+                deprecated_for_removal=True,
+                deprecated_reason='Glance v1 APIs are deprecated and v2 APIs '
+                                  'are current one. In future, Tempest will '
+                                  'test v2 APIs only so this config option '
+                                  'will be removed.'),
     cfg.BoolOpt('deactivate_image',
                 default=False,
                 help="Is the deactivate-image feature enabled."
-                     " The feature has been integrated since Kilo."),
+                     " The feature has been integrated since Kilo.",
+                deprecated_for_removal=True,
+                deprecated_reason="All supported versions of OpenStack now "
+                                  "support the 'deactivate_image' feature"),
 ]
 
 network_group = cfg.OptGroup(name='network',
@@ -537,23 +546,18 @@
                         'publicURL', 'adminURL', 'internalURL'],
                help="The endpoint type to use for the network service."),
     cfg.StrOpt('project_network_cidr',
-               deprecated_name='tenant_network_cidr',
                default="10.100.0.0/16",
                help="The cidr block to allocate project ipv4 subnets from"),
     cfg.IntOpt('project_network_mask_bits',
-               deprecated_name='tenant_network_mask_bits',
                default=28,
                help="The mask bits for project ipv4 subnets"),
     cfg.StrOpt('project_network_v6_cidr',
-               deprecated_name='tenant_network_v6_cidr',
                default="2003::/48",
                help="The cidr block to allocate project ipv6 subnets from"),
     cfg.IntOpt('project_network_v6_mask_bits',
-               deprecated_name='tenant_network_v6_mask_bits',
                default=64,
                help="The mask bits for project ipv6 subnets"),
     cfg.BoolOpt('project_networks_reachable',
-                deprecated_name='tenant_networks_reachable',
                 default=False,
                 help="Whether project networks can be reached directly from "
                      "the test client. This must be set to True when the "
@@ -597,15 +601,6 @@
                 default=False,
                 help="The environment does not support network separation "
                      "between tenants."),
-    # TODO(ylobankov): Delete this option once the Liberty release is EOL.
-    cfg.BoolOpt('dvr_extra_resources',
-                default=True,
-                help="Whether or not to create internal network, subnet, "
-                     "port and add network interface to distributed router "
-                     "in L3 agent scheduler test. Extra resources need to be "
-                     "provisioned in order to bind router to L3 agent in the "
-                     "Liberty release or older, and are not required since "
-                     "the Mitaka release.")
 ]
 
 network_feature_group = cfg.OptGroup(name='network-feature-enabled',
@@ -655,25 +650,19 @@
                choices=['fixed', 'floating'],
                help='Default IP type used for validation: '
                     '-fixed: uses the first IP belonging to the fixed network '
-                    '-floating: creates and uses a floating IP',
-               deprecated_opts=[cfg.DeprecatedOpt('use_floatingip_for_ssh',
-                                                  group='compute')]),
+                    '-floating: creates and uses a floating IP'),
     cfg.StrOpt('auth_method',
                default='keypair',
                choices=['keypair'],
                help='Default authentication method to the instance. '
                     'Only ssh via keypair is supported for now. '
-                    'Additional methods will be handled in a separate spec.',
-               deprecated_opts=[cfg.DeprecatedOpt('ssh_auth_method',
-                                                  group='compute')]),
+                    'Additional methods will be handled in a separate spec.'),
     cfg.IntOpt('ip_version_for_ssh',
                default=4,
                help='Default IP version for ssh connections.'),
     cfg.IntOpt('ping_timeout',
                default=120,
-               help='Timeout in seconds to wait for ping to succeed.',
-               deprecated_opts=[cfg.DeprecatedOpt('ping_timeout',
-                                                  group='compute')]),
+               help='Timeout in seconds to wait for ping to succeed.'),
     cfg.IntOpt('connect_timeout',
                default=60,
                help='Timeout in seconds to wait for the TCP connection to be '
@@ -683,50 +672,32 @@
                help='Timeout in seconds to wait for the ssh banner.'),
     cfg.StrOpt('image_ssh_user',
                default="root",
-               help="User name used to authenticate to an instance.",
-               deprecated_opts=[cfg.DeprecatedOpt('image_ssh_user',
-                                                  group='compute'),
-                                cfg.DeprecatedOpt('ssh_user',
-                                                  group='compute'),
-                                cfg.DeprecatedOpt('ssh_user',
-                                                  group='scenario')]),
+               help="User name used to authenticate to an instance."),
     cfg.StrOpt('image_ssh_password',
                default="password",
-               help="Password used to authenticate to an instance.",
-               deprecated_opts=[cfg.DeprecatedOpt('image_ssh_password',
-                                                  group='compute')]),
+               help="Password used to authenticate to an instance."),
     cfg.StrOpt('ssh_shell_prologue',
                default="set -eu -o pipefail; PATH=$$PATH:/sbin;",
                help="Shell fragments to use before executing a command "
-                    "when sshing to a guest.",
-               deprecated_opts=[cfg.DeprecatedOpt('ssh_shell_prologue',
-                                                  group='compute')]),
+                    "when sshing to a guest."),
     cfg.IntOpt('ping_size',
                default=56,
                help="The packet size for ping packets originating "
-                    "from remote linux hosts",
-               deprecated_opts=[cfg.DeprecatedOpt('ping_size',
-                                                  group='compute')]),
+                    "from remote linux hosts"),
     cfg.IntOpt('ping_count',
                default=1,
                help="The number of ping packets originating from remote "
-                    "linux hosts",
-               deprecated_opts=[cfg.DeprecatedOpt('ping_count',
-                                                  group='compute')]),
+                    "linux hosts"),
     cfg.StrOpt('floating_ip_range',
                default='10.0.0.0/29',
                help='Unallocated floating IP range, which will be used to '
                     'test the floating IP bulk feature for CRUD operation. '
                     'This block must not overlap an existing floating IP '
-                    'pool.',
-               deprecated_opts=[cfg.DeprecatedOpt('floating_ip_range',
-                                                  group='compute')]),
+                    'pool.'),
     cfg.StrOpt('network_for_ssh',
                default='public',
                help="Network used for SSH connections. Ignored if "
-                    "connect_method=floating.",
-               deprecated_opts=[cfg.DeprecatedOpt('network_for_ssh',
-                                                  group='compute')]),
+                    "connect_method=floating."),
 ]
 
 volume_group = cfg.OptGroup(name='volume',
@@ -770,6 +741,12 @@
     cfg.IntOpt('volume_size',
                default=1,
                help='Default size in GB for volumes created by volumes tests'),
+    cfg.ListOpt('manage_volume_ref',
+                default=['source-name', 'volume-%s'],
+                help="A reference to existing volume for volume manage. "
+                     "It contains two elements, the first is ref type "
+                     "(like 'source-name', 'source-id', etc), the second is "
+                     "volume name template used in storage backend"),
     cfg.StrOpt('min_microversion',
                default=None,
                help="Lower version of the test target microversion range. "
@@ -806,24 +783,30 @@
     cfg.BoolOpt('clone',
                 default=True,
                 help='Runs Cinder volume clone test'),
+    cfg.BoolOpt('manage_snapshot',
+                default=False,
+                help='Runs Cinder manage snapshot tests'),
+    cfg.BoolOpt('manage_volume',
+                default=False,
+                help='Runs Cinder manage volume tests'),
     cfg.ListOpt('api_extensions',
                 default=['all'],
                 help='A list of enabled volume extensions with a special '
                      'entry all which indicates every extension is enabled. '
                      'Empty list indicates all extensions are disabled'),
     cfg.BoolOpt('api_v1',
-                default=True,
-                help="Is the v1 volume API enabled"),
+                default=False,
+                help="Is the v1 volume API enabled",
+                deprecated_for_removal=True,
+                deprecated_reason="The v1 volume API has been deprecated "
+                                  "since Juno release, and the API will be "
+                                  "removed."),
     cfg.BoolOpt('api_v2',
                 default=True,
                 help="Is the v2 volume API enabled"),
     cfg.BoolOpt('api_v3',
                 default=False,
-                help="Is the v3 volume API enabled"),
-    # TODO(ynesenenko): Remove volume_services once liberty-eol happens.
-    cfg.BoolOpt('volume_services',
-                default=False,
-                help='Extract correct host info from host@backend')
+                help="Is the v3 volume API enabled")
 ]
 
 
@@ -998,9 +981,6 @@
     cfg.BoolOpt('heat',
                 default=False,
                 help="Whether or not Heat is expected to be available"),
-    cfg.BoolOpt('sahara',
-                default=False,
-                help="Whether or not Sahara is expected to be available"),
 ]
 
 debug_group = cfg.OptGroup(name="debug",
@@ -1029,39 +1009,18 @@
 """)
 ]
 
-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',
                help="Prefix to be added when generating the name for "
                     "test resources. It can be used to discover all "
                     "resources associated with a specific test run when "
-                    "running tempest on a real-life cloud"),
+                    "running tempest on a real-life cloud",
+               deprecated_for_removal=True,
+               deprecated_reason="It is enough to add 'tempest' as this "
+                                 "prefix to ideintify resources which are "
+                                 "created by Tempest and no projects set "
+                                 "this option on OpenStack dev community."),
 ]
 
 _opts = [
@@ -1084,7 +1043,6 @@
     (scenario_group, ScenarioGroup),
     (service_available_group, ServiceAvailableGroup),
     (debug_group, DebugGroup),
-    (input_scenario_group, InputScenarioGroup),
     (None, DefaultGroup)
 ]
 
@@ -1126,6 +1084,12 @@
         return getattr(_CONF, attr)
 
     def _set_attrs(self):
+        # This methods ensures that config options in Tempest as well as
+        # in Tempest plugins can be accessed via:
+        #     CONF.<normalised_group_name>.<key_name>
+        # where:
+        #     normalised_group_name = group_name.replace('-', '_')
+        # Attributes are set at __init__ time *only* for known option groups
         self.auth = _CONF.auth
         self.compute = _CONF.compute
         self.compute_feature_enabled = _CONF['compute-feature-enabled']
@@ -1146,8 +1110,24 @@
         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')
+        # Setting attributes for plugins
+        # NOTE(andreaf) Plugins have no access to the TempestConfigPrivate
+        # instance at discovery time, so they have no way of setting these
+        # aliases themselves.
+        ext_plugins = plugins.TempestTestPluginManager()
+        for group, _ in ext_plugins.get_plugin_options_list():
+            if isinstance(group, cfg.OptGroup):
+                # If we have an OptGroup
+                group_name = group.name
+                group_dest = group.dest
+            else:
+                # If we have a group name as a string
+                group_name = group
+                group_dest = group.replace('-', '_')
+            # NOTE(andreaf) We can set the attribute safely here since in
+            # case of name conflict we would not have reached this point.
+            setattr(self, group_dest, _CONF[group_name])
 
     def __init__(self, parse_conf=True, config_path=None):
         """Initialize a configuration from a conf directory and conf file."""
@@ -1192,7 +1172,7 @@
         register_opts()
         self._set_attrs()
         if parse_conf:
-            _CONF.log_opt_values(LOG, std_logging.DEBUG)
+            _CONF.log_opt_values(LOG, logging.DEBUG)
 
 
 class TempestConfigProxy(object):
@@ -1200,14 +1180,14 @@
     _path = None
 
     _extra_log_defaults = [
-        ('paramiko.transport', std_logging.INFO),
-        ('requests.packages.urllib3.connectionpool', std_logging.WARN),
+        ('paramiko.transport', logging.INFO),
+        ('requests.packages.urllib3.connectionpool', logging.WARN),
     ]
 
     def _fix_log_levels(self):
         """Tweak the oslo log defaults."""
         for name, level in self._extra_log_defaults:
-            std_logging.getLogger(name).setLevel(level)
+            logging.getLogger(name).logger.setLevel(level)
 
     def __getattr__(self, attr):
         if not self._config:
@@ -1225,6 +1205,12 @@
             # loaded, options registered, and _config is set.
             _register_tempest_service_clients()
 
+            # Registering service clients and pushing their configuration to
+            # the service clients register. Doing this in the config module
+            # ensures that the configuration is available by the time we
+            # discover tests from plugins.
+            plugins.TempestTestPluginManager()._register_service_clients()
+
         return getattr(self._config, attr)
 
     def set_config_path(self, path):
@@ -1234,6 +1220,8 @@
 CONF = TempestConfigProxy()
 
 
+@debtcollector.removals.remove(
+    message='use testtools.skipUnless instead', removal_version='Queens')
 def skip_unless_config(*args):
     """Decorator to raise a skip if a config opt doesn't exist or is False
 
@@ -1272,6 +1260,8 @@
     return decorator
 
 
+@debtcollector.removals.remove(
+    message='use testtools.skipIf instead', removal_version='Queens')
 def skip_if_config(*args):
     """Raise a skipException if a config exists and is True
 
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 43f919a..f48d7ac 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'"
 
@@ -33,18 +37,15 @@
     message = "Image %(image_id)s failed to become ACTIVE in the allotted time"
 
 
-class VolumeBuildErrorException(exceptions.TempestException):
-    message = "Volume %(volume_id)s failed to build and is in ERROR status"
+class VolumeResourceBuildErrorException(exceptions.TempestException):
+    message = ("%(resource_name)s %(resource_id)s failed to build and is in "
+               "ERROR status")
 
 
 class VolumeRestoreErrorException(exceptions.TempestException):
     message = "Volume %(volume_id)s failed to restore and is in ERROR status"
 
 
-class SnapshotBuildErrorException(exceptions.TempestException):
-    message = "Snapshot %(snapshot_id)s failed to build and is in ERROR status"
-
-
 class StackBuildErrorException(exceptions.TempestException):
     message = ("Stack %(stack_identifier)s is in %(stack_status)s status "
                "due to '%(stack_status_reason)s'")
diff --git a/tempest/hacking/ignored_list_T110.txt b/tempest/hacking/ignored_list_T110.txt
index be875ee..0e7e894 100644
--- a/tempest/hacking/ignored_list_T110.txt
+++ b/tempest/hacking/ignored_list_T110.txt
@@ -1,4 +1 @@
 ./tempest/services/object_storage/object_client.py
-./tempest/services/volume/base/base_qos_client.py
-./tempest/services/volume/base/base_backups_client.py
-./tempest/services/baremetal/base.py
diff --git a/tempest/hacking/ignored_list_T111.txt b/tempest/hacking/ignored_list_T111.txt
deleted file mode 100644
index 8017e76..0000000
--- a/tempest/hacking/ignored_list_T111.txt
+++ /dev/null
@@ -1 +0,0 @@
-./tempest/services/baremetal/base.py
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/hosts.py b/tempest/lib/api_schema/response/compute/v2_1/hosts.py
index ae70ff1..cae3435 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/hosts.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/hosts.py
@@ -111,6 +111,9 @@
             'status': {'enum': ['enabled', 'disabled']}
         },
         'additionalProperties': False,
-        'required': ['host', 'maintenance_mode', 'status']
+        'anyOf': [
+            {'required': ['host', 'status']},
+            {'required': ['host', 'maintenance_mode']}
+        ]
     }
 }
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..e7dcf79 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,19 +27,16 @@
                     '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'}
 
                 },
                 'additionalProperties': False,
-                # When we run the get keypair API, response body includes
-                # all the above mentioned attributes.
-                # But in Nova API sample file, response body includes only
-                # 'public_key', 'name' & 'fingerprint'. So only 'public_key',
-                # 'name' & 'fingerprint' are defined as 'required'.
-                'required': ['public_key', 'name', 'fingerprint']
+                'required': ['public_key', 'name', 'fingerprint', 'user_id',
+                             'deleted', 'created_at', 'updated_at',
+                             'deleted_at', 'id']
             }
         },
         'additionalProperties': False,
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/quotas.py b/tempest/lib/api_schema/response/compute/v2_1/quotas.py
index 7953983..44f5bdf 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/quotas.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/quotas.py
@@ -60,6 +60,124 @@
 get_quota_set['response_body']['properties']['quota_set']['required'].extend([
     'id'])
 
+get_quota_set_details = copy.deepcopy(get_quota_set)
+get_quota_set_details['response_body']['properties']['quota_set'][
+    'properties'] = {
+    'id': {'type': 'string'},
+    'instances': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'cores': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'ram': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'floating_ips': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'fixed_ips': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'metadata_items': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'key_pairs': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'security_groups': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'security_group_rules': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'server_group_members': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'server_groups': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'injected_files': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'injected_file_content_bytes': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    },
+    'injected_file_path_bytes': {
+        'type': 'object',
+        'properties': {
+            'reserved': {'type': 'integer'},
+            'limit': {'type': 'integer'},
+            'in_use': {'type': 'integer'}
+        }
+    }
+}
+
 delete_quota = {
     'status_code': [202]
 }
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 63e8467..33a7757 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/servers.py
@@ -100,8 +100,10 @@
                 'id': {'type': 'string'},
                 'links': parameter_types.links
             },
-            'additionalProperties': False,
-            'required': ['id', 'links']
+            # NOTE(gmann): This will be empty object if there is no
+            # flavor info present in DB. This can happen when flavor info is
+            # deleted after server creation.
+            'additionalProperties': False
         },
         'fault': {
             'type': 'object',
@@ -118,8 +120,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,
@@ -238,14 +240,17 @@
     'status_code': [200],
     'response_body': {
         'type': 'object',
-        'properties': {
-            'adminPass': {'type': 'string'}
-        },
         'additionalProperties': False,
-        'required': ['adminPass']
     }
 }
 
+rescue_server_with_admin_pass = copy.deepcopy(rescue_server)
+rescue_server_with_admin_pass['response_body'].update(
+    {'properties': {'adminPass': {'type': 'string'}}})
+rescue_server_with_admin_pass['response_body'].update(
+    {'required': ['adminPass']})
+
+
 list_virtual_interfaces = {
     'status_code': [200],
     'response_body': {
@@ -399,7 +404,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'}
     },
@@ -414,8 +419,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']}
         },
@@ -561,3 +566,19 @@
 update_attached_volume = {
     'status_code': [202]
 }
+
+evacuate_server = {
+    'status_code': [200]
+}
+
+evacuate_server_with_admin_pass = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'adminPass': {'type': 'string'}
+        },
+        'additionalProperties': False,
+        'required': ['adminPass']
+    }
+}
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/api_schema/response/compute/v2_26/servers.py b/tempest/lib/api_schema/response/compute/v2_26/servers.py
index bc5d18e..b03bdf6 100644
--- a/tempest/lib/api_schema/response/compute/v2_26/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_26/servers.py
@@ -1,4 +1,5 @@
 # Copyright 2016 IBM Corp.
+# Copyright 2017 AT&T 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
@@ -45,3 +46,36 @@
 # list response schema wasn't changed for v2.26 so use v2.1
 
 list_servers = copy.deepcopy(servers21.list_servers)
+
+list_tags = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'tags': tag_items,
+        },
+        'additionalProperties': False,
+        'required': ['tags']
+    }
+}
+
+update_all_tags = copy.deepcopy(list_tags)
+
+delete_all_tags = {'status_code': [204]}
+
+check_tag_existence = {'status_code': [204]}
+
+update_tag = {
+    'status_code': [201, 204],
+    'response_header': {
+        'type': 'object',
+        'properties': {
+            'location': {
+                'type': 'string'
+            }
+        },
+        'required': ['location']
+    }
+}
+
+delete_tag = {'status_code': [204]}
diff --git a/tempest/tests/negative/__init__.py b/tempest/lib/api_schema/response/volume/__init__.py
similarity index 100%
copy from tempest/tests/negative/__init__.py
copy to tempest/lib/api_schema/response/volume/__init__.py
diff --git a/tempest/lib/api_schema/response/volume/versions.py b/tempest/lib/api_schema/response/volume/versions.py
new file mode 100644
index 0000000..2391a8c
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/versions.py
@@ -0,0 +1,60 @@
+# Copyright 2015 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.
+
+
+list_versions = {
+    'status_code': [300],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'versions': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'status': {'type': 'string'},
+                        'updated': {'type': 'string'},
+                        'id': {'type': 'string'},
+                        'links': {
+                            'type': 'array',
+                            'items': {
+                                'type': 'object',
+                                'properties': {
+                                    'href': {'type': 'string',
+                                             'format': 'uri'},
+                                    'rel': {'type': 'string'},
+                                    'type': {'type': 'string'},
+                                },
+                                'required': ['href', 'rel']
+                            }
+                        },
+                        'min_version': {'type': 'string'},
+                        'version': {'type': 'string'},
+                        'media-types': {
+                            'type': 'array',
+                            'properties': {
+                                'base': {'type': 'string'},
+                                'type': {'type': 'string'}
+                            },
+                            'required': ['base', 'type']
+                        }
+                    },
+                    'required': ['status', 'updated', 'id', 'links',
+                                 'min_version', 'version', 'media-types']
+                }
+            }
+        },
+        'required': ['versions'],
+    }
+}
diff --git a/tempest/lib/cli/base.py b/tempest/lib/cli/base.py
index 5d7fbe3..5468a7b 100644
--- a/tempest/lib/cli/base.py
+++ b/tempest/lib/cli/base.py
@@ -13,11 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import logging
 import os
 import shlex
 import subprocess
 
+from oslo_log import log as logging
 import six
 
 from tempest.lib import base
diff --git a/tempest/lib/cli/output_parser.py b/tempest/lib/cli/output_parser.py
index c71c7a7..716f374 100644
--- a/tempest/lib/cli/output_parser.py
+++ b/tempest/lib/cli/output_parser.py
@@ -15,9 +15,10 @@
 
 """Collection of utilities for parsing CLI clients output."""
 
-import logging
 import re
 
+from oslo_log import log as logging
+
 from tempest.lib import exceptions
 
 
diff --git a/tempest/lib/cmd/check_uuid.py b/tempest/lib/cmd/check_uuid.py
index 88ce775..101d692 100755
--- a/tempest/lib/cmd/check_uuid.py
+++ b/tempest/lib/cmd/check_uuid.py
@@ -26,10 +26,10 @@
 from oslo_utils import uuidutils
 import six.moves.urllib.parse as urlparse
 
-DECORATOR_MODULE = 'test'
+DECORATOR_MODULE = 'decorators'
 DECORATOR_NAME = 'idempotent_id'
 DECORATOR_IMPORT = 'tempest.%s' % DECORATOR_MODULE
-IMPORT_LINE = 'from tempest import %s' % DECORATOR_MODULE
+IMPORT_LINE = 'from tempest.lib import %s' % DECORATOR_MODULE
 DECORATOR_TEMPLATE = "@%s.%s('%%s')" % (DECORATOR_MODULE,
                                         DECORATOR_NAME)
 UNIT_TESTS_EXCLUDE = 'tempest.tests'
@@ -117,7 +117,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
@@ -304,7 +304,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
@@ -352,9 +353,10 @@
     else:
         errors = checker.report_untagged(untagged) or errors
     if errors:
-        sys.exit("@test.idempotent_id existence and uniqueness checks failed\n"
-                 "Run 'tox -v -euuidgen' to automatically fix tests with\n"
-                 "missing @test.idempotent_id decorators.")
+        sys.exit("@decorators.idempotent_id existence and uniqueness checks "
+                 "failed\n"
+                 "Run 'tox -v -e uuidgen' to automatically fix tests with\n"
+                 "missing @decorators.idempotent_id decorators.")
 
 if __name__ == '__main__':
     run()
diff --git a/tempest/lib/cmd/skip_tracker.py b/tempest/lib/cmd/skip_tracker.py
index d95aa46..07b811d 100755
--- a/tempest/lib/cmd/skip_tracker.py
+++ b/tempest/lib/cmd/skip_tracker.py
@@ -21,16 +21,18 @@
 """
 
 import argparse
-import logging
 import os
 import re
 
+from oslo_log import log as logging
+
 try:
     from launchpadlib import launchpad
 except ImportError:
     launchpad = None
 
 LPCACHEDIR = os.path.expanduser('~/.launchpadlib/cache')
+LOG = logging.getLogger(__name__)
 
 
 def parse_args():
@@ -40,11 +42,11 @@
 
 
 def info(msg, *args, **kwargs):
-    logging.info(msg, *args, **kwargs)
+    LOG.info(msg, *args, **kwargs)
 
 
 def debug(msg, *args, **kwargs):
-    logging.debug(msg, *args, **kwargs)
+    LOG.debug(msg, *args, **kwargs)
 
 
 def find_skips(start):
@@ -110,8 +112,6 @@
 
 
 def main():
-    logging.basicConfig(format='%(levelname)s: %(message)s',
-                        level=logging.INFO)
     parser = parse_args()
     results = find_skips(parser.test_path)
     unique_bugs = sorted(set([bug for (method, bug) in get_results(results)]))
diff --git a/tempest/lib/common/cred_client.py b/tempest/lib/common/cred_client.py
index ea06011..a81f53c 100644
--- a/tempest/lib/common/cred_client.py
+++ b/tempest/lib/common/cred_client.py
@@ -59,7 +59,8 @@
     def _check_role_exists(self, role_name):
         try:
             roles = self._list_roles()
-            role = next(r for r in roles if r['name'] == role_name)
+            lc_role_name = role_name.lower()
+            role = next(r for r in roles if r['name'].lower() == lc_role_name)
         except StopIteration:
             return None
         return role
diff --git a/tempest/lib/common/http.py b/tempest/lib/common/http.py
index 86ea26e..8a47d44 100644
--- a/tempest/lib/common/http.py
+++ b/tempest/lib/common/http.py
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import six
 import urllib3
 
 
@@ -39,7 +40,9 @@
         class Response(dict):
             def __init__(self, info):
                 for key, value in info.getheaders().items():
-                    self[key.lower()] = value
+                    # We assume HTTP header name to be string, not random
+                    # bytes, thus ensure we have string keys.
+                    self[six.u(key).lower()] = value
                 self.status = info.status
                 self['status'] = str(self.status)
                 self.reason = info.reason
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 31d2ba5..99ba6ab 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -16,7 +16,6 @@
 
 import collections
 import email.utils
-import logging as real_logging
 import re
 import time
 
@@ -24,8 +23,10 @@
 from oslo_log import log as logging
 from oslo_serialization import jsonutils as json
 import six
+from six.moves import urllib
 
 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
 
@@ -39,8 +40,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):
@@ -248,8 +249,8 @@
         # NOTE(afazekas): the http status code above 400 is processed by
         # the _error_checker method
         if read_code < 400:
-            pattern = """Unexpected http success status code {0},
-                         The expected status code is {1}"""
+            pattern = ("Unexpected http success status code {0}, "
+                       "The expected status code is {1}")
             if ((not isinstance(expected_code, list) and
                  (read_code != expected_code)) or
                 (isinstance(expected_code, list) and
@@ -455,7 +456,7 @@
 
         # Also look everything at DEBUG if you want to filter this
         # out, don't run at debug.
-        if self.LOG.isEnabledFor(real_logging.DEBUG):
+        if self.LOG.isEnabledFor(logging.DEBUG):
             self._log_request_full(resp, req_headers, req_body,
                                    resp_body, extra)
 
@@ -617,6 +618,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
@@ -730,12 +732,21 @@
         if resp.status < 400:
             return
 
-        JSON_ENC = ['application/json', 'application/json; charset=utf-8']
+        # NOTE(zhipengh): There is a purposefully duplicate of content-type
+        # with the only difference is with or without spaces, as specified
+        # in RFC7231.
+        JSON_ENC = ['application/json', 'application/json; charset=utf-8',
+                    'application/json;charset=utf-8']
+
         # NOTE(mtreinish): This is for compatibility with Glance and swift
         # APIs. These are the return content types that Glance api v1
         # (and occasionally swift) are using.
+        # NOTE(zhipengh): There is a purposefully duplicate of content-type
+        # with the only difference is with or without spaces, as specified
+        # in RFC7231.
         TXT_ENC = ['text/plain', 'text/html', 'text/html; charset=utf-8',
-                   'text/plain; charset=utf-8']
+                   'text/plain; charset=utf-8', 'text/html;charset=utf-8',
+                   'text/plain;charset=utf-8']
 
         if ctype.lower() in JSON_ENC:
             parse_resp = True
@@ -775,6 +786,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)
@@ -909,6 +925,16 @@
                     msg = ("HTTP response header is invalid (%s)" % ex)
                     raise exceptions.InvalidHTTPResponseHeader(msg)
 
+    def _get_base_version_url(self):
+        # TODO(oomichi): This method can be used for auth's replace_version().
+        # So it is nice to have common logic for the maintenance.
+        endpoint = self.base_url
+        url = urllib.parse.urlsplit(endpoint)
+        new_path = re.split(r'(^|/)+v\d+(\.\d+)?', url.path)[0]
+        url = list(url)
+        url[2] = new_path + '/'
+        return urllib.parse.urlunsplit(url)
+
 
 class ResponseBody(dict):
     """Class that wraps an http response and dict body into a single value.
diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py
index 4226cd6..657c0c1 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,13 +103,15 @@
                             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
             except (EOFError,
                     socket.error, socket.timeout,
                     paramiko.SSHException) as e:
+                ssh.close()
                 if self._is_timed_out(_start_time):
                     LOG.exception("Failed to establish authenticated ssh"
                                   " connection to %s@%s after %d attempts",
@@ -175,3 +206,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/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py
index 75c2e51..a0941ef 100644
--- a/tempest/lib/common/utils/data_utils.py
+++ b/tempest/lib/common/utils/data_utils.py
@@ -14,12 +14,12 @@
 #    under the License.
 
 import itertools
-import netaddr
 import random
 import string
 import uuid
 
 from debtcollector import removals
+import netaddr
 from oslo_utils import netutils
 from oslo_utils import uuidutils
 import six.moves
@@ -43,7 +43,7 @@
     return uuid.uuid4().hex
 
 
-def rand_name(name='', prefix=None):
+def rand_name(name='', prefix='tempest'):
     """Generate a random name that includes a random number
 
     :param str name: The name that you want to include
diff --git a/tempest/api/volume/admin/v2/__init__.py b/tempest/lib/common/utils/linux/__init__.py
similarity index 100%
rename from tempest/api/volume/admin/v2/__init__.py
rename to tempest/lib/common/utils/linux/__init__.py
diff --git a/tempest/lib/common/utils/linux/remote_client.py b/tempest/lib/common/utils/linux/remote_client.py
new file mode 100644
index 0000000..64d6be2
--- /dev/null
+++ b/tempest/lib/common/utils/linux/remote_client.py
@@ -0,0 +1,117 @@
+#    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 sys
+
+import netaddr
+from oslo_log import log as logging
+import six
+
+from tempest.lib.common import ssh
+from tempest.lib.common.utils import test_utils
+import tempest.lib.exceptions
+
+LOG = logging.getLogger(__name__)
+
+
+def debug_ssh(function):
+    """Decorator to generate extra debug info in case off SSH failure"""
+    def wrapper(self, *args, **kwargs):
+        try:
+            return function(self, *args, **kwargs)
+        except tempest.lib.exceptions.SSHTimeout:
+            try:
+                original_exception = sys.exc_info()
+                caller = test_utils.find_test_caller() or "not found"
+                if self.server:
+                    msg = 'Caller: %s. Timeout trying to ssh to server %s'
+                    LOG.debug(msg, caller, self.server)
+                    if self.console_output_enabled and self.servers_client:
+                        try:
+                            msg = 'Console log for server %s: %s'
+                            console_log = (
+                                self.servers_client.get_console_output(
+                                    self.server['id'])['output'])
+                            LOG.debug(msg, self.server['id'], console_log)
+                        except Exception:
+                            msg = 'Could not get console_log for server %s'
+                            LOG.debug(msg, self.server['id'])
+                # re-raise the original ssh timeout exception
+                six.reraise(*original_exception)
+            finally:
+                # Delete the traceback to avoid circular references
+                _, _, trace = original_exception
+                del trace
+    return wrapper
+
+
+class RemoteClient(object):
+
+    def __init__(self, ip_address, username, password=None, pkey=None,
+                 server=None, servers_client=None, ssh_timeout=300,
+                 connect_timeout=60, console_output_enabled=True,
+                 ssh_shell_prologue="set -eu -o pipefail; PATH=$$PATH:/sbin;",
+                 ping_count=1, ping_size=56):
+        """Executes commands in a VM over ssh
+
+        :param ip_address: IP address to ssh to
+        :param username: Ssh username
+        :param password: Ssh password
+        :param pkey: Ssh public key
+        :param server: Server dict, used for debugging purposes
+        :param servers_client: Servers client, used for debugging purposes
+        :param ssh_timeout: Timeout in seconds to wait for the ssh banner
+        :param connect_timeout: Timeout in seconds to wait for TCP connection
+        :param console_output_enabled: Support serial console output?
+        :param ssh_shell_prologue: Shell fragments to use before command
+        :param ping_count: Number of ping packets
+        :param ping_size: Packet size for ping packets
+        """
+        self.server = server
+        self.servers_client = servers_client
+        self.console_output_enabled = console_output_enabled
+        self.ssh_shell_prologue = ssh_shell_prologue
+        self.ping_count = ping_count
+        self.ping_size = ping_size
+
+        self.ssh_client = ssh.Client(ip_address, username, password,
+                                     ssh_timeout, pkey=pkey,
+                                     channel_timeout=connect_timeout)
+
+    @debug_ssh
+    def exec_command(self, cmd):
+        # Shell options below add more clearness on failures,
+        # path is extended for some non-cirros guest oses (centos7)
+        cmd = self.ssh_shell_prologue + " " + cmd
+        LOG.debug("Remote command: %s", cmd)
+        return self.ssh_client.exec_command(cmd)
+
+    @debug_ssh
+    def validate_authentication(self):
+        """Validate ssh connection and authentication
+
+           This method raises an Exception when the validation fails.
+        """
+        self.ssh_client.test_connection_auth()
+
+    def ping_host(self, host, count=None, size=None, nic=None):
+        if count is None:
+            count = self.ping_count
+        if size is None:
+            size = self.ping_size
+
+        addr = netaddr.IPAddress(host)
+        cmd = 'ping6' if addr.version == 6 else 'ping'
+        if nic:
+            cmd = 'sudo {cmd} -I {nic}'.format(cmd=cmd, nic=nic)
+        cmd += ' -c{0} -w{0} -s{1} {2}'.format(count, size, host)
+        return self.exec_command(cmd)
diff --git a/tempest/lib/decorators.py b/tempest/lib/decorators.py
index 6ed99b4..92f9698 100644
--- a/tempest/lib/decorators.py
+++ b/tempest/lib/decorators.py
@@ -15,6 +15,7 @@
 import functools
 import uuid
 
+import debtcollector.removals
 import six
 import testtools
 
@@ -61,6 +62,7 @@
     return decorator
 
 
+@debtcollector.removals.remove(removal_version='Queen')
 class skip_unless_attr(object):
     """Decorator to skip tests if a specified attr does not exists or False"""
     def __init__(self, attr, msg=None):
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
index 108ba70..dea3289 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"
@@ -259,3 +264,8 @@
 
 class VolumeBackupException(TempestException):
     message = "Volume backup %(backup_id)s failed and is in ERROR status"
+
+
+class DeleteErrorException(TempestException):
+    message = ("Resource %(resource_id)s failed to delete "
+               "and is in ERROR status")
diff --git a/tempest/lib/services/clients.py b/tempest/lib/services/clients.py
index 262a894..eefac66 100644
--- a/tempest/lib/services/clients.py
+++ b/tempest/lib/services/clients.py
@@ -17,7 +17,8 @@
 import copy
 import importlib
 import inspect
-import logging
+
+from oslo_log import log as logging
 
 from tempest.lib import auth
 from tempest.lib.common.utils import misc
@@ -124,6 +125,9 @@
                 name=plugin_name,
                 detailed_error=detailed_error % plugin_name)
         self._service_clients[plugin_name] = service_client_data
+        LOG.debug("Successfully registered plugin %s in the service client "
+                  "registry with configuration: %s", plugin_name,
+                  service_client_data)
 
     def get_service_clients(self):
         return self._service_clients
@@ -279,7 +283,7 @@
         a dictionary ready to be injected in kwargs.
 
         Exceptions are:
-        - Token clients for 'identity' have a very different interface
+        - Token clients for 'identity' must be given an 'auth_url' parameter
         - Volume client for 'volume' accepts 'default_volume_size'
         - Servers client from 'compute' accepts 'enable_instance_password'
 
diff --git a/tempest/lib/services/compute/agents_client.py b/tempest/lib/services/compute/agents_client.py
index 169d978..408f75d 100644
--- a/tempest/lib/services/compute/agents_client.py
+++ b/tempest/lib/services/compute/agents_client.py
@@ -28,7 +28,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listbuilds
+        https://developer.openstack.org/api-ref/compute/#list-agent-builds
         """
         url = 'os-agents'
         if params:
@@ -43,7 +43,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#agentbuild
+        https://developer.openstack.org/api-ref/compute/#create-agent-build
         """
         post_body = json.dumps({'agent': kwargs})
         resp, body = self.post('os-agents', post_body)
@@ -56,7 +56,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#deleteBuild
+        https://developer.openstack.org/api-ref/compute/#delete-agent-build
         """
         resp, body = self.delete("os-agents/%s" % agent_id)
         self.validate_response(schema.delete_agent, resp, body)
@@ -67,7 +67,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#updatebuild
+        https://developer.openstack.org/api-ref/compute/#update-agent-build
         """
         put_body = json.dumps({'para': kwargs})
         resp, body = self.put('os-agents/%s' % agent_id, put_body)
diff --git a/tempest/lib/services/compute/aggregates_client.py b/tempest/lib/services/compute/aggregates_client.py
index c1a6c8c..713d7a3 100644
--- a/tempest/lib/services/compute/aggregates_client.py
+++ b/tempest/lib/services/compute/aggregates_client.py
@@ -42,7 +42,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createAggregate
+        https://developer.openstack.org/api-ref/compute/#create-aggregate
         """
         post_body = json.dumps({'aggregate': kwargs})
         resp, body = self.post('os-aggregates', post_body)
@@ -56,7 +56,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#updateAggregate
+        https://developer.openstack.org/api-ref/compute/#update-aggregate
         """
         put_body = json.dumps({'aggregate': kwargs})
         resp, body = self.put('os-aggregates/%s' % aggregate_id, put_body)
@@ -88,7 +88,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#addHost
+        https://developer.openstack.org/api-ref/compute/#add-host
         """
         post_body = json.dumps({'add_host': kwargs})
         resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
@@ -102,7 +102,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#removeAggregateHost
+        https://developer.openstack.org/api-ref/compute/#remove-host
         """
         post_body = json.dumps({'remove_host': kwargs})
         resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
@@ -116,7 +116,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#addAggregateMetadata
+        https://developer.openstack.org/api-ref/compute/#create-or-update-aggregate-metadata
         """
         post_body = json.dumps({'set_metadata': kwargs})
         resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
diff --git a/tempest/lib/services/compute/fixed_ips_client.py b/tempest/lib/services/compute/fixed_ips_client.py
index 682ee86..968646c 100644
--- a/tempest/lib/services/compute/fixed_ips_client.py
+++ b/tempest/lib/services/compute/fixed_ips_client.py
@@ -34,7 +34,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#reserveIP
+        https://developer.openstack.org/api-ref/compute/#reserve-or-release-a-fixed-ip
         """
         url = "os-fixed-ips/%s/action" % fixed_ip
         resp, body = self.post(url, json.dumps(kwargs))
diff --git a/tempest/lib/services/compute/flavors_client.py b/tempest/lib/services/compute/flavors_client.py
index a83c68b..0fb1991 100644
--- a/tempest/lib/services/compute/flavors_client.py
+++ b/tempest/lib/services/compute/flavors_client.py
@@ -32,7 +32,8 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listFlavors
+        https://developer.openstack.org/api-ref/compute/#list-flavors
+        https://developer.openstack.org/api-ref/compute/#list-flavors-with-details
         """
         url = 'flavors'
         _schema = schema.list_flavors
@@ -53,7 +54,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#showFlavor
+        https://developer.openstack.org/api-ref/compute/#show-flavor-details
         """
         resp, body = self.get("flavors/%s" % flavor_id)
         body = json.loads(body)
@@ -65,7 +66,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createFlavor
+        https://developer.openstack.org/api-ref/compute/#create-flavor
         """
         if 'ephemeral' in kwargs:
             kwargs['OS-FLV-EXT-DATA:ephemeral'] = kwargs.pop('ephemeral')
@@ -84,7 +85,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#deleteFlavor
+        https://developer.openstack.org/api-ref/compute/#delete-flavor
         """
         resp, body = self.delete("flavors/{0}".format(flavor_id))
         self.validate_response(schema.delete_flavor, resp, body)
@@ -110,7 +111,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createFlavorExtraSpec
+        https://developer.openstack.org/api-ref/compute/#create-extra-specs-for-a-flavor
         """
         post_body = json.dumps({'extra_specs': kwargs})
         resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id,
@@ -125,7 +126,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listFlavorExtraSpecs
+        https://developer.openstack.org/api-ref/compute/#list-extra-specs-for-a-flavor
         """
         resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id)
         body = json.loads(body)
@@ -138,7 +139,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#showFlavorExtraSpec
+        https://developer.openstack.org/api-ref/compute/#show-an-extra-spec-for-a-flavor
         """
         resp, body = self.get('flavors/%s/os-extra_specs/%s' % (flavor_id,
                               key))
@@ -153,7 +154,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#updateFlavorExtraSpec
+        https://developer.openstack.org/api-ref/compute/#update-an-extra-spec-for-a-flavor
         """
         resp, body = self.put('flavors/%s/os-extra_specs/%s' %
                               (flavor_id, key), json.dumps(kwargs))
@@ -170,7 +171,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#deleteFlavorExtraSpec
+        https://developer.openstack.org/api-ref/compute/#delete-an-extra-spec-for-a-flavor
         """
         resp, body = self.delete('flavors/%s/os-extra_specs/%s' %
                                  (flavor_id, key))
@@ -182,7 +183,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listFlavorAccess
+        https://developer.openstack.org/api-ref/compute/#list-flavor-access-information-for-given-flavor
         """
         resp, body = self.get('flavors/%s/os-flavor-access' % flavor_id)
         body = json.loads(body)
@@ -195,7 +196,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#addFlavorAccess
+        https://developer.openstack.org/api-ref/compute/#add-flavor-access-to-tenant-addtenantaccess-action
         """
         post_body = {
             'addTenantAccess': {
@@ -214,7 +215,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#removeFlavorAccess
+        https://developer.openstack.org/api-ref/compute/#remove-flavor-access-from-tenant-removetenantaccess-action
         """
         post_body = {
             'removeTenantAccess': {
diff --git a/tempest/lib/services/compute/floating_ips_client.py b/tempest/lib/services/compute/floating_ips_client.py
index 744e14c..5364d97 100644
--- a/tempest/lib/services/compute/floating_ips_client.py
+++ b/tempest/lib/services/compute/floating_ips_client.py
@@ -29,7 +29,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listfloatingipsObject
+        https://developer.openstack.org/api-ref/compute/#list-floating-ip-addresses
         """
         url = 'os-floating-ips'
         if params:
@@ -45,7 +45,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#showFloatingIP
+        https://developer.openstack.org/api-ref/compute/#show-floating-ip-address-details
         """
         url = "os-floating-ips/%s" % floating_ip_id
         resp, body = self.get(url)
@@ -58,7 +58,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createFloatingIP
+        https://developer.openstack.org/api-ref/compute/#create-allocate-floating-ip-address
         """
         url = 'os-floating-ips'
         post_body = json.dumps(kwargs)
@@ -72,7 +72,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#deleteFloatingIP
+        https://developer.openstack.org/api-ref/compute/#delete-deallocate-floating-ip-address
         """
         url = "os-floating-ips/%s" % floating_ip_id
         resp, body = self.delete(url)
diff --git a/tempest/lib/services/compute/hosts_client.py b/tempest/lib/services/compute/hosts_client.py
index 1b93b00..1fdd907 100644
--- a/tempest/lib/services/compute/hosts_client.py
+++ b/tempest/lib/services/compute/hosts_client.py
@@ -23,7 +23,12 @@
 class HostsClient(base_compute_client.BaseComputeClient):
 
     def list_hosts(self, **params):
-        """List all hosts."""
+        """List all hosts.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/compute/#list-hosts
+        """
 
         url = 'os-hosts'
         if params:
@@ -47,7 +52,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#enablehost
+        https://developer.openstack.org/api-ref/compute/#update-host-status
         """
 
         request_body = {
diff --git a/tempest/lib/services/compute/images_client.py b/tempest/lib/services/compute/images_client.py
index e937c13..86bea9e 100644
--- a/tempest/lib/services/compute/images_client.py
+++ b/tempest/lib/services/compute/images_client.py
@@ -29,7 +29,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createImage
+        https://developer.openstack.org/api-ref/compute/#create-image-createimage-action
         """
 
         post_body = {'createImage': kwargs}
@@ -44,7 +44,8 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listImages
+        https://developer.openstack.org/api-ref/compute/#list-images
+        https://developer.openstack.org/api-ref/compute/#list-images-with-details
         """
         url = 'images'
         _schema = schema.list_images
@@ -85,7 +86,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createImageMetadata
+        https://developer.openstack.org/api-ref/compute/#update-image-metadata
         """
         post_body = json.dumps({'metadata': meta})
         resp, body = self.put('images/%s/metadata' % image_id, post_body)
@@ -98,7 +99,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#updateImageMetadata
+        https://developer.openstack.org/api-ref/compute/#create-image-metadata
         """
         post_body = json.dumps({'metadata': meta})
         resp, body = self.post('images/%s/metadata' % image_id, post_body)
@@ -118,7 +119,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#setImageMetadataItem
+        https://developer.openstack.org/api-ref/compute/#create-or-update-image-metadata-item
         """
         post_body = json.dumps({'meta': meta})
         resp, body = self.put('images/%s/metadata/%s' % (image_id, key),
diff --git a/tempest/lib/services/compute/interfaces_client.py b/tempest/lib/services/compute/interfaces_client.py
index 37157a4..d7c3107 100644
--- a/tempest/lib/services/compute/interfaces_client.py
+++ b/tempest/lib/services/compute/interfaces_client.py
@@ -33,7 +33,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createAttachInterface
+        https://developer.openstack.org/api-ref/compute/#create-interface
         """
         post_body = {'interfaceAttachment': kwargs}
         post_body = json.dumps(post_body)
diff --git a/tempest/lib/services/compute/keypairs_client.py b/tempest/lib/services/compute/keypairs_client.py
index c3f1781..5215fca 100644
--- a/tempest/lib/services/compute/keypairs_client.py
+++ b/tempest/lib/services/compute/keypairs_client.py
@@ -32,7 +32,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listKeypairs
+        https://developer.openstack.org/api-ref/compute/#list-keypairs
         """
         url = 'os-keypairs'
         if params:
@@ -48,7 +48,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#showKeypair
+        https://developer.openstack.org/api-ref/compute/#show-keypair-details
         """
         url = "os-keypairs/%s" % keypair_name
         if params:
@@ -64,7 +64,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createKeypair
+        https://developer.openstack.org/api-ref/compute/#create-or-import-keypair
         """
         post_body = json.dumps({'keypair': kwargs})
         resp, body = self.post("os-keypairs", body=post_body)
@@ -78,7 +78,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#deleteKeypair
+        https://developer.openstack.org/api-ref/compute/#delete-keypair
         """
         url = "os-keypairs/%s" % keypair_name
         if params:
diff --git a/tempest/lib/services/compute/migrations_client.py b/tempest/lib/services/compute/migrations_client.py
index 375cbda..68c8f3f 100644
--- a/tempest/lib/services/compute/migrations_client.py
+++ b/tempest/lib/services/compute/migrations_client.py
@@ -32,7 +32,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listMigrations
+        https://developer.openstack.org/api-ref/compute/#list-migrations
         """
 
         url = 'os-migrations'
diff --git a/tempest/lib/services/compute/quotas_client.py b/tempest/lib/services/compute/quotas_client.py
index a2b0397..daf4bc0 100644
--- a/tempest/lib/services/compute/quotas_client.py
+++ b/tempest/lib/services/compute/quotas_client.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
 
 from tempest.lib.api_schema.response.compute.v2_1 import quotas as schema
 from tempest.lib.common import rest_client
@@ -22,15 +23,29 @@
 
 class QuotasClient(base_compute_client.BaseComputeClient):
 
-    def show_quota_set(self, tenant_id, user_id=None):
-        """List the quota set for a tenant."""
+    def show_quota_set(self, tenant_id, user_id=None, detail=False):
+        """List the quota set for a tenant.
 
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref-compute-v2.1.html/#show-a-quota
+        http://developer.openstack.org/api-ref-compute-v2.1.html/#show-the-detail-of-quota
+        """
+
+        params = {}
         url = 'os-quota-sets/%s' % tenant_id
+        if detail:
+            url += '/detail'
         if user_id:
-            url += '?user_id=%s' % user_id
+            params.update({'user_id': user_id})
+        if params:
+            url += '?%s' % urllib.urlencode(params)
         resp, body = self.get(url)
         body = json.loads(body)
-        self.validate_response(schema.get_quota_set, resp, body)
+        if detail:
+            self.validate_response(schema.get_quota_set_details, resp, body)
+        else:
+            self.validate_response(schema.get_quota_set, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def show_default_quota_set(self, tenant_id):
@@ -47,7 +62,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#updateQuota
+        https://developer.openstack.org/api-ref/compute/#update-quotas
         """
 
         post_body = json.dumps({'quota_set': kwargs})
diff --git a/tempest/lib/services/compute/security_group_default_rules_client.py b/tempest/lib/services/compute/security_group_default_rules_client.py
index e2d3c98..70cab88 100644
--- a/tempest/lib/services/compute/security_group_default_rules_client.py
+++ b/tempest/lib/services/compute/security_group_default_rules_client.py
@@ -28,7 +28,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createSecGroupDefaultRule
+        https://developer.openstack.org/api-ref/compute/#create-default-security-group-rule
         """
         post_body = json.dumps({'security_group_default_rule': kwargs})
         url = 'os-security-group-default-rules'
diff --git a/tempest/lib/services/compute/security_group_rules_client.py b/tempest/lib/services/compute/security_group_rules_client.py
index 3121e24..710bfab 100644
--- a/tempest/lib/services/compute/security_group_rules_client.py
+++ b/tempest/lib/services/compute/security_group_rules_client.py
@@ -28,7 +28,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createSecGroupRule
+        https://developer.openstack.org/api-ref/compute/#create-security-group-rule
         """
         post_body = json.dumps({'security_group_rule': kwargs})
         url = 'os-security-group-rules'
diff --git a/tempest/lib/services/compute/security_groups_client.py b/tempest/lib/services/compute/security_groups_client.py
index a247346..b525f68 100644
--- a/tempest/lib/services/compute/security_groups_client.py
+++ b/tempest/lib/services/compute/security_groups_client.py
@@ -30,7 +30,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listSecGroups
+        https://developer.openstack.org/api-ref/compute/#list-security-groups
         """
 
         url = 'os-security-groups'
@@ -47,7 +47,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#showSecGroup
+        https://developer.openstack.org/api-ref/compute/#show-security-group-details
         """
         url = "os-security-groups/%s" % security_group_id
         resp, body = self.get(url)
@@ -60,7 +60,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createSecGroup
+        https://developer.openstack.org/api-ref/compute/#create-security-group
         """
         post_body = json.dumps({'security_group': kwargs})
         resp, body = self.post('os-security-groups', post_body)
@@ -73,7 +73,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#updateSecGroup
+        https://developer.openstack.org/api-ref/compute/#update-security-group
         """
         post_body = json.dumps({'security_group': kwargs})
         resp, body = self.put('os-security-groups/%s' % security_group_id,
@@ -87,7 +87,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#deleteSecGroup
+        https://developer.openstack.org/api-ref/compute/#delete-security-group
         """
         resp, body = self.delete(
             'os-security-groups/%s' % security_group_id)
diff --git a/tempest/lib/services/compute/server_groups_client.py b/tempest/lib/services/compute/server_groups_client.py
index 9ba8d38..3a935b4 100644
--- a/tempest/lib/services/compute/server_groups_client.py
+++ b/tempest/lib/services/compute/server_groups_client.py
@@ -28,7 +28,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createServerGroup
+        https://developer.openstack.org/api-ref/compute/#create-server-group
         """
         post_body = json.dumps({'server_group': kwargs})
         resp, body = self.post('os-server-groups', post_body)
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index 597e815..0d355a1 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -1,5 +1,6 @@
 # Copyright 2012 OpenStack Foundation
 # Copyright 2013 Hewlett-Packard Development Company, L.P.
+# Copyright 2017 AT&T Corp.
 # All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -19,6 +20,8 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
+from tempest.lib.api_schema.response.compute.v2_1 import \
+    security_groups as security_groups_schema
 from tempest.lib.api_schema.response.compute.v2_1 import servers as schema
 from tempest.lib.api_schema.response.compute.v2_16 import servers as schemav216
 from tempest.lib.api_schema.response.compute.v2_19 import servers as schemav219
@@ -30,6 +33,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},
@@ -94,7 +99,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#updateServer
+        https://developer.openstack.org/api-ref/compute/#update-server
 
         Most parameters except the following are passed to the API without
         any changes.
@@ -128,7 +133,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#deleteServer
+        https://developer.openstack.org/api-ref/compute/#delete-server
         """
         resp, body = self.delete("servers/%s" % server_id)
         self.validate_response(schema.delete_server, resp, body)
@@ -139,8 +144,8 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listServers
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listDetailServers
+        https://developer.openstack.org/api-ref/compute/#list-servers
+        https://developer.openstack.org/api-ref/compute/#list-servers-detailed
         """
 
         url = 'servers'
@@ -163,7 +168,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#list-ips
+        https://developer.openstack.org/api-ref/compute/#list-ips
         """
         resp, body = self.get("servers/%s/ips" % server_id)
         body = json.loads(body)
@@ -194,7 +199,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createBackup
+        https://developer.openstack.org/api-ref/compute/#create-server-back-up-createbackup-action
         """
         return self.action(server_id, "createBackup", **kwargs)
 
@@ -203,7 +208,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#changePassword
+        https://developer.openstack.org/api-ref/compute/#change-administrative-password-changepassword-action
         """
         return self.action(server_id, 'changePassword', **kwargs)
 
@@ -231,7 +236,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#reboot
+        https://developer.openstack.org/api-ref/compute/#reboot-server-reboot-action
         """
         return self.action(server_id, 'reboot', **kwargs)
 
@@ -240,7 +245,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#rebuild
+        https://developer.openstack.org/api-ref/compute/#rebuild-server-rebuild-action
 
         Most parameters except the following are passed to the API without
         any changes.
@@ -262,7 +267,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#resize
+        https://developer.openstack.org/api-ref/compute/#resize-server-resize-action
 
         Most parameters except the following are passed to the API without
         any changes.
@@ -278,7 +283,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#confirmResize
+        https://developer.openstack.org/api-ref/compute/#confirm-resized-server-confirmresize-action
         """
         return self.action(server_id, 'confirmResize',
                            schema.server_actions_confirm_resize,
@@ -289,7 +294,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#revertResize
+        https://developer.openstack.org/api-ref/compute/#revert-resized-server-revertresize-action
         """
         return self.action(server_id, 'revertResize', **kwargs)
 
@@ -298,7 +303,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listServerMetadata
+        https://developer.openstack.org/api-ref/compute/#list-all-metadata
         """
         resp, body = self.get("servers/%s/metadata" % server_id)
         body = json.loads(body)
@@ -310,7 +315,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createServerMetadata
+        https://developer.openstack.org/api-ref/compute/#create-or-replace-metadata-items
         """
         if no_metadata_field:
             post_body = ""
@@ -327,7 +332,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#updateServerMetadata
+        https://developer.openstack.org/api-ref/compute/#update-metadata-items
         """
         post_body = json.dumps({'metadata': meta})
         resp, body = self.post('servers/%s/metadata' % server_id,
@@ -342,7 +347,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#showServerMetadataItem
+        https://developer.openstack.org/api-ref/compute/#show-metadata-item-details
         """
         resp, body = self.get("servers/%s/metadata/%s" % (server_id, key))
         body = json.loads(body)
@@ -355,7 +360,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#setServerMetadataItem
+        https://developer.openstack.org/api-ref/compute/#create-or-update-metadata-item
         """
         post_body = json.dumps({'meta': meta})
         resp, body = self.put('servers/%s/metadata/%s' % (server_id, key),
@@ -370,7 +375,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#deleteServerMetadataItem
+        https://developer.openstack.org/api-ref/compute/#delete-metadata-item
         """
         resp, body = self.delete("servers/%s/metadata/%s" %
                                  (server_id, key))
@@ -383,7 +388,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#stop
+        https://developer.openstack.org/api-ref/compute/#stop-server-os-stop-action
         """
         return self.action(server_id, 'os-stop', **kwargs)
 
@@ -392,7 +397,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#start
+        https://developer.openstack.org/api-ref/compute/#start-server-os-start-action
         """
         return self.action(server_id, 'os-start', **kwargs)
 
@@ -401,7 +406,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#attachVolume
+        https://developer.openstack.org/api-ref/compute/#attach-a-volume-to-an-instance
         """
         post_body = json.dumps({'volumeAttachment': kwargs})
         resp, body = self.post('servers/%s/os-volume_attachments' % server_id,
@@ -424,7 +429,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#deleteVolumeAttachment
+        https://developer.openstack.org/api-ref/compute/#detach-a-volume-from-an-instance
         """
         resp, body = self.delete('servers/%s/os-volume_attachments/%s' %
                                  (server_id, volume_id))
@@ -436,7 +441,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#getVolumeAttachmentDetails
+        https://developer.openstack.org/api-ref/compute/#show-a-detail-of-a-volume-attachment
         """
         resp, body = self.get('servers/%s/os-volume_attachments/%s' % (
             server_id, volume_id))
@@ -449,7 +454,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listVolumeAttachments
+        https://developer.openstack.org/api-ref/compute/#list-volume-attachments-for-an-instance
         """
         resp, body = self.get('servers/%s/os-volume_attachments' % (
             server_id))
@@ -462,12 +467,8 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#addSecurityGroup
+        https://developer.openstack.org/api-ref/compute/#add-security-group-to-a-server-addsecuritygroup-action
         """
-        # TODO(oomichi): The api-site doesn't contain this API description.
-        # So the above should be changed to the api-site link after
-        # adding the description on the api-site.
-        # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1524199
         return self.action(server_id, 'addSecurityGroup', **kwargs)
 
     def remove_security_group(self, server_id, **kwargs):
@@ -475,12 +476,8 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#removeSecurityGroup
+        https://developer.openstack.org/api-ref/compute/#remove-security-group-from-a-server-removesecuritygroup-action
         """
-        # TODO(oomichi): The api-site doesn't contain this API description.
-        # So the above should be changed to the api-site link after
-        # adding the description on the api-site.
-        # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1524199
         return self.action(server_id, 'removeSecurityGroup', **kwargs)
 
     def live_migrate_server(self, server_id, **kwargs):
@@ -488,7 +485,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#migrateLive
+        https://developer.openstack.org/api-ref/compute/#live-migrate-server-os-migratelive-action
         """
         return self.action(server_id, 'os-migrateLive', **kwargs)
 
@@ -497,7 +494,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#migrate
+        https://developer.openstack.org/api-ref/compute/#migrate-server-migrate-action
         """
         return self.action(server_id, 'migrate', **kwargs)
 
@@ -506,7 +503,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#lock
+        https://developer.openstack.org/api-ref/compute/#lock-server-lock-action
         """
         return self.action(server_id, 'lock', **kwargs)
 
@@ -515,7 +512,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#unlock
+        https://developer.openstack.org/api-ref/compute/#unlock-server-unlock-action
         """
         return self.action(server_id, 'unlock', **kwargs)
 
@@ -524,7 +521,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#suspend
+        https://developer.openstack.org/api-ref/compute/#suspend-server-suspend-action
         """
         return self.action(server_id, 'suspend', **kwargs)
 
@@ -533,7 +530,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#resume
+        https://developer.openstack.org/api-ref/compute/#resume-suspended-server-resume-action
         """
         return self.action(server_id, 'resume', **kwargs)
 
@@ -542,7 +539,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#pause
+        https://developer.openstack.org/api-ref/compute/#pause-server-pause-action
         """
         return self.action(server_id, 'pause', **kwargs)
 
@@ -551,7 +548,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#unpause
+        https://developer.openstack.org/api-ref/compute/#unpause-server-unpause-action
         """
         return self.action(server_id, 'unpause', **kwargs)
 
@@ -560,7 +557,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#resetState
+        https://developer.openstack.org/api-ref/compute/#reset-server-state-os-resetstate-action
         """
         return self.action(server_id, 'os-resetState', **kwargs)
 
@@ -569,7 +566,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#shelve
+        https://developer.openstack.org/api-ref/compute/#shelve-server-shelve-action
         """
         return self.action(server_id, 'shelve', **kwargs)
 
@@ -578,7 +575,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#unshelve
+        https://developer.openstack.org/api-ref/compute/#unshelve-restore-shelved-server-unshelve-action
         """
         return self.action(server_id, 'unshelve', **kwargs)
 
@@ -587,7 +584,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#shelveOffload
+        https://developer.openstack.org/api-ref/compute/#shelf-offload-remove-server-shelveoffload-action
         """
         return self.action(server_id, 'shelveOffload', **kwargs)
 
@@ -596,7 +593,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#getConsoleOutput
+        https://developer.openstack.org/api-ref/compute/#show-console-output-os-getconsoleoutput-action
         """
         return self.action(server_id, 'os-getConsoleOutput',
                            schema.get_console_output, **kwargs)
@@ -614,16 +611,20 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#rescue
+        https://developer.openstack.org/api-ref/compute/#rescue-server-rescue-action
         """
-        return self.action(server_id, 'rescue', schema.rescue_server, **kwargs)
+        if self.enable_instance_password:
+            rescue_schema = schema.rescue_server_with_admin_pass
+        else:
+            rescue_schema = schema.rescue_server
+        return self.action(server_id, 'rescue', rescue_schema, **kwargs)
 
     def unrescue_server(self, server_id):
         """Unrescue the provided server.
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#unrescue
+        https://developer.openstack.org/api-ref/compute/#unrescue-server-unrescue-action
         """
         return self.action(server_id, 'unrescue')
 
@@ -653,7 +654,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#forceDelete
+        https://developer.openstack.org/api-ref/compute/#force-delete-server-forcedelete-action
         """
         return self.action(server_id, 'forceDelete', **kwargs)
 
@@ -662,7 +663,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#restore
+        https://developer.openstack.org/api-ref/compute/#restore-soft-deleted-instance-restore-action
         """
         return self.action(server_id, 'restore', **kwargs)
 
@@ -671,7 +672,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#resetNetwork
+        https://developer.openstack.org/api-ref/compute/#reset-networking-on-a-server-resetnetwork-action
         """
         return self.action(server_id, 'resetNetwork', **kwargs)
 
@@ -680,7 +681,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#injectNetworkInfo
+        https://developer.openstack.org/api-ref/compute/#inject-network-information-injectnetworkinfo-action
         """
         return self.action(server_id, 'injectNetworkInfo', **kwargs)
 
@@ -689,7 +690,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#getVNCConsole
+        https://developer.openstack.org/api-ref/compute/#get-vnc-console-os-getvncconsole-action
         """
         return self.action(server_id, "os-getVNCConsole",
                            schema.get_vnc_console, **kwargs)
@@ -699,7 +700,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#addFixedIp
+        https://developer.openstack.org/api-ref/compute/#add-associate-fixed-ip-addfixedip-action
         """
         return self.action(server_id, 'addFixedIp', **kwargs)
 
@@ -708,6 +709,124 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#removeFixedIp
+        https://developer.openstack.org/api-ref/compute/#remove-disassociate-fixed-ip-removefixedip-action
         """
         return self.action(server_id, 'removeFixedIp', **kwargs)
+
+    def list_security_groups_by_server(self, server_id):
+        """Lists security groups for a server.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/compute/#list-security-groups-by-server
+        """
+        resp, body = self.get("servers/%s/os-security-groups" % server_id)
+        body = json.loads(body)
+        self.validate_response(security_groups_schema.list_security_groups,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_tags(self, server_id):
+        """Lists all tags for a server.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/compute/#list-tags
+        """
+        url = 'servers/%s/tags' % server_id
+        resp, body = self.get(url)
+        body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
+        self.validate_response(schema.list_tags, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_all_tags(self, server_id, tags):
+        """Replaces all tags on specified server with the new set of tags.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/compute/#replace-tags
+
+        :param tags: List of tags to replace current server tags with.
+        """
+        url = 'servers/%s/tags' % server_id
+        put_body = {'tags': tags}
+        resp, body = self.put(url, json.dumps(put_body))
+        body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
+        self.validate_response(schema.update_all_tags, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_all_tags(self, server_id):
+        """Deletes all tags from the specified server.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/compute/#delete-all-tags
+        """
+        url = 'servers/%s/tags' % server_id
+        resp, body = self.delete(url)
+        schema = self.get_schema(self.schema_versions_info)
+        self.validate_response(schema.delete_all_tags, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_tag_existence(self, server_id, tag):
+        """Checks tag existence on the server.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/compute/#check-tag-existence
+
+        :param tag: Check for existence of tag on specified server.
+        """
+        url = 'servers/%s/tags/%s' % (server_id, tag)
+        resp, body = self.get(url)
+        schema = self.get_schema(self.schema_versions_info)
+        self.validate_response(schema.check_tag_existence, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_tag(self, server_id, tag):
+        """Adds a single tag to the server if server has no specified tag.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/compute/#add-a-single-tag
+
+        :param tag: Tag to be added to the specified server.
+        """
+        url = 'servers/%s/tags/%s' % (server_id, tag)
+        resp, body = self.put(url, None)
+        schema = self.get_schema(self.schema_versions_info)
+        self.validate_response(schema.update_tag, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_tag(self, server_id, tag):
+        """Deletes a single tag from the specified server.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/compute/#delete-a-single-tag
+
+        :param tag: Tag to be removed from the specified server.
+        """
+        url = 'servers/%s/tags/%s' % (server_id, tag)
+        resp, body = self.delete(url)
+        schema = self.get_schema(self.schema_versions_info)
+        self.validate_response(schema.delete_tag, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def evacuate_server(self, server_id, **kwargs):
+        """Evacuate the given server.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/compute/#evacuate-server-evacuate-action
+        """
+        if self.enable_instance_password:
+            evacuate_schema = schema.evacuate_server_with_admin_pass
+        else:
+            evacuate_schema = schema.evacuate_server
+
+        return self.action(server_id, 'evacuate',
+                           evacuate_schema,
+                           **kwargs)
diff --git a/tempest/lib/services/compute/services_client.py b/tempest/lib/services/compute/services_client.py
index 0dbd1b2..77ac82f 100644
--- a/tempest/lib/services/compute/services_client.py
+++ b/tempest/lib/services/compute/services_client.py
@@ -29,7 +29,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listServices
+        https://developer.openstack.org/api-ref/compute/#list-compute-services
         """
         url = 'os-services'
         if params:
@@ -45,7 +45,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#enableScheduling
+        https://developer.openstack.org/api-ref/compute/#enable-scheduling-for-a-compute-service
         """
         post_body = json.dumps(kwargs)
         resp, body = self.put('os-services/enable', post_body)
@@ -58,7 +58,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#disableScheduling
+        https://developer.openstack.org/api-ref/compute/#disable-scheduling-for-a-compute-service
         """
         post_body = json.dumps(kwargs)
         resp, body = self.put('os-services/disable', post_body)
diff --git a/tempest/lib/services/compute/snapshots_client.py b/tempest/lib/services/compute/snapshots_client.py
index fde5288..df8d6fb 100644
--- a/tempest/lib/services/compute/snapshots_client.py
+++ b/tempest/lib/services/compute/snapshots_client.py
@@ -29,7 +29,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createSnapshot
+        https://developer.openstack.org/api-ref/compute/#create-snapshot
         """
         post_body = {
             'volume_id': volume_id
@@ -49,6 +49,12 @@
         return rest_client.ResponseBody(resp, body)
 
     def list_snapshots(self, detail=False, params=None):
+        """List snapshots.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/compute/#list-snapshots
+        """
         url = 'os-snapshots'
 
         if detail:
diff --git a/tempest/lib/services/compute/versions_client.py b/tempest/lib/services/compute/versions_client.py
index b2052c3..8fbb136 100644
--- a/tempest/lib/services/compute/versions_client.py
+++ b/tempest/lib/services/compute/versions_client.py
@@ -12,10 +12,9 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-import re
+import time
 
 from oslo_serialization import jsonutils as json
-from six.moves import urllib
 
 from tempest.lib.api_schema.response.compute.v2_1 import versions as schema
 from tempest.lib.common import rest_client
@@ -24,22 +23,15 @@
 
 class VersionsClient(base_compute_client.BaseComputeClient):
 
-    def _get_base_version_url(self):
-        # NOTE: The URL which is got from keystone's catalog contains
-        # API version and project-id like "/app-name/v2/{project-id}" or
-        # "/v2/{project-id}", but we need to access the URL which doesn't
-        # contain API version for getting API versions. For that, here
-        # should use raw_request() instead of get().
-        endpoint = self.base_url
-        url = urllib.parse.urlsplit(endpoint)
-        new_path = re.split(r'(^|/)+v\d+(\.\d+)?', url.path)[0]
-        url = list(url)
-        url[2] = new_path + '/'
-        return urllib.parse.urlunsplit(url)
-
     def list_versions(self):
         version_url = self._get_base_version_url()
+
+        start = time.time()
         resp, body = self.raw_request(version_url, 'GET')
+        end = time.time()
+        self._log_request('GET', version_url, resp, secs=(end - start),
+                          resp_body=body)
+
         self._error_checker(resp, body)
         body = json.loads(body)
         self.validate_response(schema.list_versions, resp, body)
diff --git a/tempest/lib/services/compute/volumes_client.py b/tempest/lib/services/compute/volumes_client.py
index b75f22e..95cdd53 100644
--- a/tempest/lib/services/compute/volumes_client.py
+++ b/tempest/lib/services/compute/volumes_client.py
@@ -29,7 +29,8 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#listVolumes
+        https://developer.openstack.org/api-ref/compute/#list-volumes
+        https://developer.openstack.org/api-ref/compute/#list-volumes-with-details
         """
         url = 'os-volumes'
 
@@ -48,7 +49,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#showVolume
+        https://developer.openstack.org/api-ref/compute/#show-volume-details
         """
         url = "os-volumes/%s" % volume_id
         resp, body = self.get(url)
@@ -61,7 +62,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#createVolume
+        https://developer.openstack.org/api-ref/compute/#create-volume
         """
         post_body = json.dumps({'volume': kwargs})
         resp, body = self.post('os-volumes', post_body)
@@ -74,7 +75,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-compute-v2.1.html#deleteVolume
+        https://developer.openstack.org/api-ref/compute/#delete-volume
         """
         resp, body = self.delete("os-volumes/%s" % volume_id)
         self.validate_response(schema.delete_volume, resp, body)
diff --git a/tempest/lib/services/identity/v2/roles_client.py b/tempest/lib/services/identity/v2/roles_client.py
index 635d013..9e841dd 100644
--- a/tempest/lib/services/identity/v2/roles_client.py
+++ b/tempest/lib/services/identity/v2/roles_client.py
@@ -24,7 +24,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-identity-v2-ext.html#createRole
+        https://developer.openstack.org/api-ref/identity/v2-ext/index.html#create-a-role
         """
         post_body = json.dumps({'role': kwargs})
         resp, body = self.post('OS-KSADM/roles', post_body)
@@ -37,9 +37,9 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-identity-v2-ext.html#showRoleByID
+        https://developer.openstack.org/api-ref/identity/v2-ext/index.html#show-a-role
         OR
-        http://developer.openstack.org/api-ref-identity-v2-ext.html#showRoleByName
+        https://developer.openstack.org/api-ref/identity/v2-ext/index.html#show-role-information-by-name
         """
         resp, body = self.get('OS-KSADM/roles/%s' % role_id_or_name)
         self.expected_success(200, resp.status)
@@ -51,7 +51,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-identity-v2-ext.html#listRoles
+        https://developer.openstack.org/api-ref/identity/v2-ext/index.html#list-all-roles
         """
         url = 'OS-KSADM/roles'
         if params:
@@ -66,7 +66,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-identity-v2-ext.html#deleteRole
+        https://developer.openstack.org/api-ref/identity/v2-ext/index.html#delete-a-role
         """
         resp, body = self.delete('OS-KSADM/roles/%s' % role_id)
         self.expected_success(204, resp.status)
@@ -77,7 +77,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-identity-v2-ext.html#grantRoleToUserOnTenant
+        https://developer.openstack.org/api-ref/identity/v2-ext/index.html#grant-roles-to-user-on-tenant
         """
         resp, body = self.put('/tenants/%s/users/%s/roles/OS-KSADM/%s' %
                               (tenant_id, user_id, role_id), "")
@@ -101,7 +101,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-identity-v2-ext.html#revokeRoleFromUserOnTenant
+        https://developer.openstack.org/api-ref/identity/v2-ext/index.html#revoke-role-from-user-on-tenant
         """
         resp, body = self.delete('/tenants/%s/users/%s/roles/OS-KSADM/%s' %
                                  (tenant_id, user_id, role_id))
diff --git a/tempest/lib/services/identity/v2/services_client.py b/tempest/lib/services/identity/v2/services_client.py
index b3f94aa..47398db 100644
--- a/tempest/lib/services/identity/v2/services_client.py
+++ b/tempest/lib/services/identity/v2/services_client.py
@@ -26,7 +26,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/identity/v2-ext/?expanded=#create-service-admin-extension
+        http://developer.openstack.org/api-ref/identity/v2-ext/#create-service-admin-extension
         """
         post_body = json.dumps({'OS-KSADM:service': kwargs})
         resp, body = self.post('/OS-KSADM/services', post_body)
@@ -47,7 +47,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/identity/v2-ext/?expanded=#list-services-admin-extension
+        http://developer.openstack.org/api-ref/identity/v2-ext/#list-services-admin-extension
         """
         url = '/OS-KSADM/services'
         if params:
diff --git a/tempest/lib/services/identity/v2/tenants_client.py b/tempest/lib/services/identity/v2/tenants_client.py
index b687332..026db64 100644
--- a/tempest/lib/services/identity/v2/tenants_client.py
+++ b/tempest/lib/services/identity/v2/tenants_client.py
@@ -39,7 +39,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-identity-v2-ext.html#deleteTenant
+        https://developer.openstack.org/api-ref/identity/v2-admin/index.html#delete-tenant
         """
         resp, body = self.delete('tenants/%s' % str(tenant_id))
         self.expected_success(204, resp.status)
@@ -50,7 +50,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-identity-v2-ext.html#admin-showTenantById
+        https://developer.openstack.org/api-ref/identity/v2-admin/index.html#show-tenant-details-by-id
         """
         resp, body = self.get('tenants/%s' % str(tenant_id))
         self.expected_success(200, resp.status)
diff --git a/tempest/lib/services/identity/v2/token_client.py b/tempest/lib/services/identity/v2/token_client.py
index c4fd483..458c862 100644
--- a/tempest/lib/services/identity/v2/token_client.py
+++ b/tempest/lib/services/identity/v2/token_client.py
@@ -23,7 +23,22 @@
 
     def __init__(self, auth_url, disable_ssl_certificate_validation=None,
                  ca_certs=None, trace_requests=None, **kwargs):
+        """Initialises the Token client
+
+        :param auth_url: URL to which the token request is sent
+        :param disable_ssl_certificate_validation: pass-through to rest client
+        :param ca_certs: pass-through to rest client
+        :param trace_requests: pass-through to rest client
+        :param kwargs: any extra parameter to pass through the rest client.
+               region, service and auth_provider will be ignored, if passed,
+               as they are not meaningful for token client
+        """
         dscv = disable_ssl_certificate_validation
+        # NOTE(andreaf) region, service and auth_provider are passed
+        # positionally with None. Having them in kwargs would raise a
+        # "multiple values for keyword arguments" error
+        for unwanted_kwargs in ['region', 'service', 'auth_provider']:
+            kwargs.pop(unwanted_kwargs, None)
         super(TokenClient, self).__init__(
             None, None, None, disable_ssl_certificate_validation=dscv,
             ca_certs=ca_certs, trace_requests=trace_requests, **kwargs)
diff --git a/tempest/lib/services/identity/v2/users_client.py b/tempest/lib/services/identity/v2/users_client.py
index f20fdc4..cfd97bb 100644
--- a/tempest/lib/services/identity/v2/users_client.py
+++ b/tempest/lib/services/identity/v2/users_client.py
@@ -50,7 +50,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-identity-admin-v2.html#admin-showUser
+        https://developer.openstack.org/api-ref/identity/v2-admin/index.html#show-user-details-admin-endpoint
         """
         resp, body = self.get("users/%s" % user_id)
         self.expected_success(200, resp.status)
@@ -62,7 +62,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-identity-admin-v2.html#admin-deleteUser
+        https://developer.openstack.org/api-ref/identity/v2-admin/index.html#delete-user-admin-endpoint
         """
         resp, body = self.delete("users/%s" % user_id)
         self.expected_success(204, resp.status)
diff --git a/tempest/lib/services/identity/v3/__init__.py b/tempest/lib/services/identity/v3/__init__.py
index 8058d51..1489b50 100644
--- a/tempest/lib/services/identity/v3/__init__.py
+++ b/tempest/lib/services/identity/v3/__init__.py
@@ -20,6 +20,8 @@
 from tempest.lib.services.identity.v3.identity_client import IdentityClient
 from tempest.lib.services.identity.v3.inherited_roles_client import \
     InheritedRolesClient
+from tempest.lib.services.identity.v3.oauth_consumers_client import \
+    OAUTHConsumerClient
 from tempest.lib.services.identity.v3.policies_client import PoliciesClient
 from tempest.lib.services.identity.v3.projects_client import ProjectsClient
 from tempest.lib.services.identity.v3.regions_client import RegionsClient
@@ -30,9 +32,11 @@
 from tempest.lib.services.identity.v3.token_client import V3TokenClient
 from tempest.lib.services.identity.v3.trusts_client import TrustsClient
 from tempest.lib.services.identity.v3.users_client import UsersClient
+from tempest.lib.services.identity.v3.versions_client import VersionsClient
 
 __all__ = ['CredentialsClient', 'DomainsClient', 'EndPointsClient',
            'GroupsClient', 'IdentityClient', 'InheritedRolesClient',
            'PoliciesClient', 'ProjectsClient', 'RegionsClient',
            'RoleAssignmentsClient', 'RolesClient', 'ServicesClient',
-           'V3TokenClient', 'TrustsClient', 'UsersClient', ]
+           'V3TokenClient', 'TrustsClient', 'UsersClient', 'VersionsClient',
+           'OAUTHConsumerClient']
diff --git a/tempest/lib/services/identity/v3/endpoints_client.py b/tempest/lib/services/identity/v3/endpoints_client.py
index c4c0d8d..91592de 100644
--- a/tempest/lib/services/identity/v3/endpoints_client.py
+++ b/tempest/lib/services/identity/v3/endpoints_client.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 """
-http://developer.openstack.org/api-ref-identity-v3.html#endpoints-v3
+https://developer.openstack.org/api-ref/identity/v3/index.html#service-catalog-and-endpoints
 """
 
 from oslo_serialization import jsonutils as json
diff --git a/tempest/lib/services/identity/v3/groups_client.py b/tempest/lib/services/identity/v3/groups_client.py
index 5e68939..bc6ead0 100644
--- a/tempest/lib/services/identity/v3/groups_client.py
+++ b/tempest/lib/services/identity/v3/groups_client.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 """
-http://developer.openstack.org/api-ref-identity-v3.html#groups-v3
+https://developer.openstack.org/api-ref/identity/v3/index.html#groups
 """
 
 from oslo_serialization import jsonutils as json
diff --git a/tempest/lib/services/identity/v3/identity_client.py b/tempest/lib/services/identity/v3/identity_client.py
index 8177e35..755c14b 100644
--- a/tempest/lib/services/identity/v3/identity_client.py
+++ b/tempest/lib/services/identity/v3/identity_client.py
@@ -43,3 +43,10 @@
         resp, body = self.delete("auth/tokens", headers=headers)
         self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp, body)
+
+    def list_auth_projects(self):
+        """Get available project scopes."""
+        resp, body = self.get("auth/projects")
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/identity/v3/oauth_consumers_client.py b/tempest/lib/services/identity/v3/oauth_consumers_client.py
new file mode 100644
index 0000000..582c9e0
--- /dev/null
+++ b/tempest/lib/services/identity/v3/oauth_consumers_client.py
@@ -0,0 +1,95 @@
+# Copyright 2017 AT&T 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 oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class OAUTHConsumerClient(rest_client.RestClient):
+    api_version = "v3"
+
+    def create_consumer(self, description=None):
+        """Creates a consumer.
+
+        :param str description: Optional field to add notes about the consumer
+
+        For more information, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/identity/v3-ext/#create-consumer
+        """
+        post_body = {"description": description}
+        post_body = json.dumps({'consumer': post_body})
+        resp, body = self.post('OS-OAUTH1/consumers', post_body)
+        self.expected_success(201, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_consumer(self, consumer_id):
+        """Deletes a consumer.
+
+        :param str consumer_id: The ID of the consumer that will be deleted
+
+        For more information, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/identity/v3-ext/#delete-consumer
+        """
+        resp, body = self.delete('OS-OAUTH1/consumers/%s' % consumer_id)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_consumer(self, consumer_id, description=None):
+        """Updates a consumer.
+
+        :param str consumer_id: The ID of the consumer that will be updated
+        :param str description: Optional field to add notes about the consumer
+
+        For more information, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/identity/v3-ext/#update-consumers
+        """
+        post_body = {"description": description}
+        post_body = json.dumps({'consumer': post_body})
+        resp, body = self.patch('OS-OAUTH1/consumers/%s' % consumer_id,
+                                post_body)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_consumer(self, consumer_id):
+        """Show consumer details.
+
+        :param str consumer_id: The ID of the consumer that will be shown
+
+        For more information, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/identity/v3-ext/#show-consumer-details
+        """
+        resp, body = self.get('OS-OAUTH1/consumers/%s' % consumer_id)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_consumers(self):
+        """List all consumers.
+
+        For more information, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/identity/v3-ext/#list-consumers
+        """
+        resp, body = self.get('OS-OAUTH1/consumers')
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/identity/v3/policies_client.py b/tempest/lib/services/identity/v3/policies_client.py
index 0282745..d4560e2 100644
--- a/tempest/lib/services/identity/v3/policies_client.py
+++ b/tempest/lib/services/identity/v3/policies_client.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 """
-http://developer.openstack.org/api-ref-identity-v3.html#policies-v3
+https://developer.openstack.org/api-ref/identity/v3/index.html#policies
 """
 
 from oslo_serialization import jsonutils as json
diff --git a/tempest/lib/services/identity/v3/regions_client.py b/tempest/lib/services/identity/v3/regions_client.py
index 33c754a..d7507cf 100644
--- a/tempest/lib/services/identity/v3/regions_client.py
+++ b/tempest/lib/services/identity/v3/regions_client.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 """
-http://developer.openstack.org/api-ref-identity-v3.html#regions-v3
+https://developer.openstack.org/api-ref/identity/v3/index.html#regions
 """
 
 from oslo_serialization import jsonutils as json
diff --git a/tempest/lib/services/identity/v3/role_assignments_client.py b/tempest/lib/services/identity/v3/role_assignments_client.py
index 10de03f..a426e69 100644
--- a/tempest/lib/services/identity/v3/role_assignments_client.py
+++ b/tempest/lib/services/identity/v3/role_assignments_client.py
@@ -26,7 +26,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/identity/v3/?expanded=list-effective-role-assignments-detail
+        http://developer.openstack.org/api-ref/identity/v3/#list-role-assignments
 
         :param effective: If True, returns the effective assignments, including
                           any assignments gained by virtue of group membership
diff --git a/tempest/lib/services/identity/v3/roles_client.py b/tempest/lib/services/identity/v3/roles_client.py
index f1339dd..43e3c01 100644
--- a/tempest/lib/services/identity/v3/roles_client.py
+++ b/tempest/lib/services/identity/v3/roles_client.py
@@ -190,3 +190,52 @@
                                (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 list_all_role_inference_rules(self):
+        """Lists all role inference rules.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/identity/v3/index.html#list-all-role-inference-rules
+        """
+        resp, body = self.get('role_inferences')
+        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/lib/services/identity/v3/services_client.py b/tempest/lib/services/identity/v3/services_client.py
index 14c81cc..17b0f24 100644
--- a/tempest/lib/services/identity/v3/services_client.py
+++ b/tempest/lib/services/identity/v3/services_client.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 """
-http://developer.openstack.org/api-ref-identity-v3.html#service-catalog-v3
+https://developer.openstack.org/api-ref/identity/v3/index.html#service-catalog-and-endpoints
 """
 
 from oslo_serialization import jsonutils as json
diff --git a/tempest/lib/services/identity/v3/token_client.py b/tempest/lib/services/identity/v3/token_client.py
index 06927f4..33f6f16 100644
--- a/tempest/lib/services/identity/v3/token_client.py
+++ b/tempest/lib/services/identity/v3/token_client.py
@@ -23,7 +23,19 @@
 
     def __init__(self, auth_url, disable_ssl_certificate_validation=None,
                  ca_certs=None, trace_requests=None, **kwargs):
+        """Initialises the Token client
+
+        :param auth_url: URL to which the token request is sent
+        :param disable_ssl_certificate_validation: pass-through to rest client
+        :param ca_certs: pass-through to rest client
+        :param trace_requests: pass-through to rest client
+        :param kwargs: any extra parameter to pass through the rest client.
+               Three kwargs are forbidden: region, service and auth_provider
+               as they are not meaningful for token client
+        """
         dscv = disable_ssl_certificate_validation
+        for unwanted_kwargs in ['region', 'service', 'auth_provider']:
+            kwargs.pop(unwanted_kwargs, None)
         super(V3TokenClient, self).__init__(
             None, None, None, disable_ssl_certificate_validation=dscv,
             ca_certs=ca_certs, trace_requests=trace_requests, **kwargs)
diff --git a/tempest/lib/services/identity/v3/versions_client.py b/tempest/lib/services/identity/v3/versions_client.py
new file mode 100644
index 0000000..441ee0d
--- /dev/null
+++ b/tempest/lib/services/identity/v3/versions_client.py
@@ -0,0 +1,38 @@
+# Copyright 2017 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 time
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class VersionsClient(rest_client.RestClient):
+    api_version = "v3"
+
+    def list_versions(self):
+        """List API versions"""
+        version_url = self._get_base_version_url()
+
+        start = time.time()
+        resp, body = self.raw_request(version_url, 'GET')
+        end = time.time()
+        self._log_request('GET', version_url, resp, secs=(end - start),
+                          resp_body=body)
+        self._error_checker(resp, body)
+
+        self.expected_success(300, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/image/v1/images_client.py b/tempest/lib/services/image/v1/images_client.py
index 03f4c4b..faafb4a 100644
--- a/tempest/lib/services/image/v1/images_client.py
+++ b/tempest/lib/services/image/v1/images_client.py
@@ -61,7 +61,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-image-v1.html#createImage-v1
+        https://developer.openstack.org/api-ref/image/v1/index.html#create-image
         """
         if headers is None:
             headers = {}
@@ -79,7 +79,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-image-v1.html#updateImage-v1
+        https://developer.openstack.org/api-ref/image/v1/index.html#update-image
         """
         if headers is None:
             headers = {}
diff --git a/tempest/lib/services/image/v2/__init__.py b/tempest/lib/services/image/v2/__init__.py
index d359d4b..99a5321 100644
--- a/tempest/lib/services/image/v2/__init__.py
+++ b/tempest/lib/services/image/v2/__init__.py
@@ -15,12 +15,19 @@
 from tempest.lib.services.image.v2.image_members_client import \
     ImageMembersClient
 from tempest.lib.services.image.v2.images_client import ImagesClient
+from tempest.lib.services.image.v2.namespace_objects_client import \
+    NamespaceObjectsClient
 from tempest.lib.services.image.v2.namespace_properties_client import \
     NamespacePropertiesClient
+from tempest.lib.services.image.v2.namespace_tags_client import \
+    NamespaceTagsClient
 from tempest.lib.services.image.v2.namespaces_client import NamespacesClient
 from tempest.lib.services.image.v2.resource_types_client import \
     ResourceTypesClient
 from tempest.lib.services.image.v2.schemas_client import SchemasClient
+from tempest.lib.services.image.v2.versions_client import VersionsClient
 
-__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespacePropertiesClient',
-           'NamespacesClient', 'ResourceTypesClient', 'SchemasClient']
+__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespaceObjectsClient',
+           'NamespacePropertiesClient', 'NamespaceTagsClient',
+           'NamespacesClient', 'ResourceTypesClient', 'SchemasClient',
+           'VersionsClient']
diff --git a/tempest/lib/services/image/v2/namespace_objects_client.py b/tempest/lib/services/image/v2/namespace_objects_client.py
new file mode 100644
index 0000000..ac2e63e
--- /dev/null
+++ b/tempest/lib/services/image/v2/namespace_objects_client.py
@@ -0,0 +1,91 @@
+# Copyright 2016 EasyStack.
+# 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 oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
+
+from tempest.lib.common import rest_client
+
+
+class NamespaceObjectsClient(rest_client.RestClient):
+    api_version = "v2"
+
+    def list_namespace_objects(self, namespace, **kwargs):
+        """Lists all namespace objects.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-objects
+        """
+        url = 'metadefs/namespaces/%s/objects' % namespace
+        if kwargs:
+            url += '?%s' % urllib.urlencode(kwargs)
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_namespace_object(self, namespace, **kwargs):
+        """Create a namespace object
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-object
+        """
+        url = 'metadefs/namespaces/%s/objects' % namespace
+        data = json.dumps(kwargs)
+        resp, body = self.post(url, data)
+        self.expected_success(201, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_namespace_object(self, namespace, object_name, **kwargs):
+        """Update a namespace object
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-object
+        """
+        url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name)
+        data = json.dumps(kwargs)
+        resp, body = self.put(url, data)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_namespace_object(self, namespace, object_name):
+        """Show a namespace object
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#show-object
+        """
+        url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name)
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_namespace_object(self, namespace, object_name):
+        """Delete a namespace object
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-object
+        """
+        url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name)
+        resp, _ = self.delete(url)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
diff --git a/tempest/lib/services/image/v2/namespace_tags_client.py b/tempest/lib/services/image/v2/namespace_tags_client.py
new file mode 100644
index 0000000..a7f8c39
--- /dev/null
+++ b/tempest/lib/services/image/v2/namespace_tags_client.py
@@ -0,0 +1,125 @@
+# Copyright 2016 EasyStack.
+# 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 oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
+
+from tempest.lib.common import rest_client
+
+
+class NamespaceTagsClient(rest_client.RestClient):
+    api_version = "v2"
+
+    def create_namespace_tag(self, namespace, tag_name):
+        """Adds a tag to the list of namespace tag definitions.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-tag-definition
+        """
+        url = 'metadefs/namespaces/%s/tags/%s' % (namespace,
+                                                  tag_name)
+        resp, body = self.post(url, None)
+        self.expected_success(201, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_namespace_tag(self, namespace, tag_name):
+        """Gets a definition for a tag.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#get_tag_definition
+        """
+        url = 'metadefs/namespaces/%s/tags/%s' % (namespace,
+                                                  tag_name)
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_namespace_tag(self, namespace, tag_name, **kwargs):
+        """Renames a tag definition.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-tag-definition
+        """
+        url = 'metadefs/namespaces/%s/tags/%s' % (namespace,
+                                                  tag_name)
+        data = json.dumps(kwargs)
+        resp, body = self.put(url, data)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_namespace_tag(self, namespace, tag_name):
+        """Deletes a tag definition within a namespace.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-tag-definition
+        """
+        url = 'metadefs/namespaces/%s/tags/%s' % (namespace, tag_name)
+        resp, _ = self.delete(url)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def create_namespace_tags(self, namespace, **kwargs):
+        """Creates one or more tag definitions in a namespace.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-tags
+        """
+        url = 'metadefs/namespaces/%s/tags' % namespace
+        data = json.dumps(kwargs)
+        resp, body = self.post(url, data)
+        self.expected_success(201, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_namespace_tags(self, namespace, **params):
+        """Lists the tag definitions within a namespace.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-tags
+        """
+        url = 'metadefs/namespaces/%s/tags' % namespace
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_namespace_tags(self, namespace):
+        """Deletes all tag definitions within a namespace.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-all-tag-definitions
+        """
+        url = 'metadefs/namespaces/%s/tags' % namespace
+        resp, _ = self.delete(url)
+
+        # NOTE(rosmaita): Bug 1656183 fixed the success response code for
+        # this call to make it consistent with the other metadefs delete
+        # calls.  Accept both codes in case tempest is being run against
+        # an old Glance.
+        self.expected_success([200, 204], resp.status)
+
+        return rest_client.ResponseBody(resp)
diff --git a/tempest/lib/services/image/v2/resource_types_client.py b/tempest/lib/services/image/v2/resource_types_client.py
index 1b6889f..13259d1 100644
--- a/tempest/lib/services/image/v2/resource_types_client.py
+++ b/tempest/lib/services/image/v2/resource_types_client.py
@@ -26,7 +26,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html?expanded=#list-resource-types
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-resource-types
         """
         url = 'metadefs/resource_types'
         resp, body = self.get(url)
@@ -39,7 +39,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html?expanded=#create-resource-type-association
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-resource-type-association
         """
         url = 'metadefs/namespaces/%s/resource_types' % namespace_id
         data = json.dumps(kwargs)
@@ -53,7 +53,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html?expanded=#list-resource-type-associations
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-resource-type-associations
         """
         url = 'metadefs/namespaces/%s/resource_types' % namespace_id
         resp, body = self.get(url)
@@ -66,7 +66,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html?expanded=#remove-resource-type-association
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#remove-resource-type-association
         """
         url = 'metadefs/namespaces/%s/resource_types/%s' % (namespace_id,
                                                             resource_name)
diff --git a/tempest/lib/services/image/v2/versions_client.py b/tempest/lib/services/image/v2/versions_client.py
new file mode 100644
index 0000000..1adc466
--- /dev/null
+++ b/tempest/lib/services/image/v2/versions_client.py
@@ -0,0 +1,38 @@
+# Copyright 2017 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 time
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class VersionsClient(rest_client.RestClient):
+    api_version = "v2"
+
+    def list_versions(self):
+        """List API versions"""
+        version_url = self._get_base_version_url()
+
+        start = time.time()
+        resp, body = self.raw_request(version_url, 'GET')
+        end = time.time()
+        self._log_request('GET', version_url, resp, secs=(end - start),
+                          resp_body=body)
+        self._error_checker(resp, body)
+
+        self.expected_success(300, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/network/ports_client.py b/tempest/lib/services/network/ports_client.py
index 93138b9..daa15d7 100644
--- a/tempest/lib/services/network/ports_client.py
+++ b/tempest/lib/services/network/ports_client.py
@@ -73,7 +73,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/networking/v2/index.html?expanded=#bulk-create-ports
+        http://developer.openstack.org/api-ref/networking/v2/index.html#bulk-create-ports
         """
         uri = '/ports'
         return self.create_resource(uri, kwargs)
diff --git a/tempest/lib/services/volume/v2/__init__.py b/tempest/lib/services/volume/v2/__init__.py
index 837b4f6..9434896 100644
--- a/tempest/lib/services/volume/v2/__init__.py
+++ b/tempest/lib/services/volume/v2/__init__.py
@@ -27,11 +27,17 @@
 from tempest.lib.services.volume.v2.scheduler_stats_client import \
     SchedulerStatsClient
 from tempest.lib.services.volume.v2.services_client import ServicesClient
+from tempest.lib.services.volume.v2.snapshot_manage_client import \
+    SnapshotManageClient
 from tempest.lib.services.volume.v2.snapshots_client import SnapshotsClient
+from tempest.lib.services.volume.v2.transfers_client import TransfersClient
 from tempest.lib.services.volume.v2.types_client import TypesClient
+from tempest.lib.services.volume.v2.volume_manage_client import \
+    VolumeManageClient
 from tempest.lib.services.volume.v2.volumes_client import VolumesClient
 
 __all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient',
            'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient',
            'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient',
-           'LimitsClient', 'CapabilitiesClient', 'SchedulerStatsClient']
+           'LimitsClient', 'CapabilitiesClient', 'SchedulerStatsClient',
+           'SnapshotManageClient', 'VolumeManageClient', 'TransfersClient']
diff --git a/tempest/lib/services/volume/v2/backups_client.py b/tempest/lib/services/volume/v2/backups_client.py
index ab5eefd..2b5e82d 100644
--- a/tempest/lib/services/volume/v2/backups_client.py
+++ b/tempest/lib/services/volume/v2/backups_client.py
@@ -28,7 +28,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#createBackup
+        https://developer.openstack.org/api-ref/block-storage/v2/index.html#create-backup
         """
         post_body = json.dumps({'backup': kwargs})
         resp, body = self.post('backups', post_body)
@@ -41,7 +41,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#restoreBackup
+        https://developer.openstack.org/api-ref/block-storage/v2/index.html#restore-backup
         """
         post_body = json.dumps({'restore': kwargs})
         resp, body = self.post('backups/%s/restore' % (backup_id), post_body)
diff --git a/tempest/lib/services/volume/v2/capabilities_client.py b/tempest/lib/services/volume/v2/capabilities_client.py
index b6de5b9..40cb8bf 100644
--- a/tempest/lib/services/volume/v2/capabilities_client.py
+++ b/tempest/lib/services/volume/v2/capabilities_client.py
@@ -19,6 +19,7 @@
 
 
 class CapabilitiesClient(rest_client.RestClient):
+    api_version = "v2"
 
     def show_backend_capabilities(self, host):
         """Shows capabilities for a storage back end.
diff --git a/tempest/lib/services/volume/v2/encryption_types_client.py b/tempest/lib/services/volume/v2/encryption_types_client.py
index 8b01f11..eeff537 100755
--- a/tempest/lib/services/volume/v2/encryption_types_client.py
+++ b/tempest/lib/services/volume/v2/encryption_types_client.py
@@ -67,3 +67,17 @@
             "/types/%s/encryption/provider" % volume_type_id)
         self.expected_success(202, resp.status)
         return rest_client.ResponseBody(resp, body)
+
+    def update_encryption_type(self, volume_type_id, **kwargs):
+        """Update an encryption type for an existing volume type.
+
+        TODO: Current api-site doesn't contain this API description.
+        After fixing the api-site, we need to fix here also for putting
+        the link to api-site.
+        """
+        url = "/types/%s/encryption/provider" % volume_type_id
+        put_body = json.dumps({'encryption': kwargs})
+        resp, body = self.put(url, put_body)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v2/qos_client.py b/tempest/lib/services/volume/v2/qos_client.py
index 40d4a3f..47d3914 100644
--- a/tempest/lib/services/volume/v2/qos_client.py
+++ b/tempest/lib/services/volume/v2/qos_client.py
@@ -43,9 +43,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/index.html
-                                ?expanded=create-qos-specification-detail
-                                #quality-of-service-qos-specifications-qos-specs
+        http://developer.openstack.org/api-ref/block-storage/v2/#create-qos-specification
         """
         post_body = json.dumps({'qos_specs': kwargs})
         resp, body = self.post('qos-specs', post_body)
@@ -81,9 +79,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/index.html
-                            ?expanded=set-keys-in-qos-specification-detail
-                            #quality-of-service-qos-specifications-qos-specs
+        http://developer.openstack.org/api-ref/block-storage/v2/#set-keys-in-qos-specification
         """
         put_body = json.dumps({"qos_specs": kwargs})
         resp, body = self.put('qos-specs/%s' % qos_id, put_body)
@@ -98,9 +94,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/index.html
-                            ?expanded=unset-keys-in-qos-specification-detail
-                            #quality-of-service-qos-specifications-qos-specs
+        http://developer.openstack.org/api-ref/block-storage/v2/#unset-keys-in-qos-specification
         """
         put_body = json.dumps({'keys': keys})
         resp, body = self.put('qos-specs/%s/delete_keys' % qos_id, put_body)
diff --git a/tempest/lib/services/volume/v2/quotas_client.py b/tempest/lib/services/volume/v2/quotas_client.py
index 430957d..e4b2895 100644
--- a/tempest/lib/services/volume/v2/quotas_client.py
+++ b/tempest/lib/services/volume/v2/quotas_client.py
@@ -49,7 +49,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v2.html#updateQuota
+        https://developer.openstack.org/api-ref/block-storage/v2/index.html#update-quotas
         """
         put_body = jsonutils.dumps({'quota_set': kwargs})
         resp, body = self.put('os-quota-sets/%s' % tenant_id, put_body)
diff --git a/tempest/lib/services/volume/v2/scheduler_stats_client.py b/tempest/lib/services/volume/v2/scheduler_stats_client.py
index 637254b..3f56f82 100644
--- a/tempest/lib/services/volume/v2/scheduler_stats_client.py
+++ b/tempest/lib/services/volume/v2/scheduler_stats_client.py
@@ -19,6 +19,7 @@
 
 
 class SchedulerStatsClient(rest_client.RestClient):
+    api_version = "v2"
 
     def list_pools(self, detail=False):
         """List all the volumes pools (hosts).
diff --git a/tempest/lib/services/volume/v2/snapshot_manage_client.py b/tempest/lib/services/volume/v2/snapshot_manage_client.py
new file mode 100644
index 0000000..aecd30b
--- /dev/null
+++ b/tempest/lib/services/volume/v2/snapshot_manage_client.py
@@ -0,0 +1,33 @@
+# Copyright 2016 Red Hat, Inc.
+# 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 oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class SnapshotManageClient(rest_client.RestClient):
+    """Snapshot manage V2 client."""
+
+    api_version = "v2"
+
+    def manage_snapshot(self, **kwargs):
+        """Manage a snapshot."""
+        post_body = json.dumps({'snapshot': kwargs})
+        url = 'os-snapshot-manage'
+        resp, body = self.post(url, post_body)
+        self.expected_success(202, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v2/snapshots_client.py b/tempest/lib/services/volume/v2/snapshots_client.py
index 6f51b51..983ed89 100644
--- a/tempest/lib/services/volume/v2/snapshots_client.py
+++ b/tempest/lib/services/volume/v2/snapshots_client.py
@@ -27,7 +27,8 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#list-snapshots-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#list-snapshots-with-details
+        http://developer.openstack.org/api-ref/block-storage/v2/#list-snapshots
         """
         url = 'snapshots'
         if detail:
@@ -45,7 +46,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#show-snapshot-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#show-snapshot-details
         """
         url = "snapshots/%s" % snapshot_id
         resp, body = self.get(url)
@@ -71,7 +72,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#update-snapshot-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#update-snapshot
         """
         put_body = json.dumps({'snapshot': kwargs})
         resp, body = self.put('snapshots/%s' % snapshot_id, put_body)
@@ -84,7 +85,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#delete-snapshot-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#delete-snapshot
         """
         resp, body = self.delete("snapshots/%s" % snapshot_id)
         self.expected_success(202, resp.status)
@@ -136,7 +137,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#show-snapshot-metadata-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#show-snapshot-metadata
         """
         url = "snapshots/%s/metadata" % snapshot_id
         resp, body = self.get(url)
@@ -149,7 +150,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#update-snapshot-metadata-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#update-snapshot-metadata
         """
         put_body = json.dumps(kwargs)
         url = "snapshots/%s/metadata" % snapshot_id
@@ -184,3 +185,11 @@
         resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body)
         self.expected_success(202, resp.status)
         return rest_client.ResponseBody(resp, body)
+
+    def unmanage_snapshot(self, snapshot_id):
+        """Unmanage a snapshot."""
+        post_body = json.dumps({'os-unmanage': {}})
+        url = 'snapshots/%s/action' % (snapshot_id)
+        resp, body = self.post(url, post_body)
+        self.expected_success(202, resp.status)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v2/transfers_client.py b/tempest/lib/services/volume/v2/transfers_client.py
new file mode 100644
index 0000000..6f21944
--- /dev/null
+++ b/tempest/lib/services/volume/v2/transfers_client.py
@@ -0,0 +1,80 @@
+# Copyright 2012 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.
+
+from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
+
+from tempest.lib.common import rest_client
+
+
+class TransfersClient(rest_client.RestClient):
+    """Client class to send CRUD Volume Transfer V2 API requests"""
+    api_version = "v2"
+
+    def create_volume_transfer(self, **kwargs):
+        """Create a volume transfer.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-transfer-v2
+        """
+        post_body = json.dumps({'transfer': kwargs})
+        resp, body = self.post('os-volume-transfer', post_body)
+        body = json.loads(body)
+        self.expected_success(202, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_volume_transfer(self, transfer_id):
+        """Returns the details of a volume transfer."""
+        url = "os-volume-transfer/%s" % transfer_id
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_volume_transfers(self, **params):
+        """List all the volume transfers created.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/block-storage/v2/#list-volume-transfers-v2
+        """
+        url = 'os-volume-transfer'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_volume_transfer(self, transfer_id):
+        """Delete a volume transfer."""
+        resp, body = self.delete("os-volume-transfer/%s" % transfer_id)
+        self.expected_success(202, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def accept_volume_transfer(self, transfer_id, **kwargs):
+        """Accept a volume transfer.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/block-storage/v2/#accept-volume-transfer-v2
+        """
+        url = 'os-volume-transfer/%s/accept' % transfer_id
+        post_body = json.dumps({'accept': kwargs})
+        resp, body = self.post(url, post_body)
+        body = json.loads(body)
+        self.expected_success(202, resp.status)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v2/types_client.py b/tempest/lib/services/volume/v2/types_client.py
index 31597d7..5d30615 100644
--- a/tempest/lib/services/volume/v2/types_client.py
+++ b/tempest/lib/services/volume/v2/types_client.py
@@ -41,7 +41,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#list-volume-types-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#list-volume-types
         """
         url = 'types'
         if params:
@@ -57,7 +57,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#show-volume-type-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#show-volume-type-details
         """
         url = "types/%s" % volume_type_id
         resp, body = self.get(url)
@@ -70,7 +70,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-type-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-type
         """
         post_body = json.dumps({'volume_type': kwargs})
         resp, body = self.post('types', post_body)
@@ -83,7 +83,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#delete-volume-type-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#delete-volume-type
         """
         resp, body = self.delete("types/%s" % volume_type_id)
         self.expected_success(202, resp.status)
@@ -138,7 +138,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-type-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-type
         """
         put_body = json.dumps({'volume_type': kwargs})
         resp, body = self.put('types/%s' % volume_type_id, put_body)
@@ -156,7 +156,7 @@
                      updated value.
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-type-extra-specs-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#update-extra-specs-for-a-volume-type
         """
         url = "types/%s/extra_specs/%s" % (volume_type_id, extra_spec_name)
         put_body = json.dumps(extra_specs)
@@ -170,7 +170,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#add-type-access-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#add-private-volume-type-access
         """
         post_body = json.dumps({'addProjectAccess': kwargs})
         url = 'types/%s/action' % volume_type_id
@@ -183,7 +183,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#remove-type-access-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#remove-private-volume-type-access
         """
         post_body = json.dumps({'removeProjectAccess': kwargs})
         url = 'types/%s/action' % volume_type_id
@@ -196,7 +196,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#list-type-access-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#list-private-volume-type-access-details
         """
         url = 'types/%s/os-volume-type-access' % volume_type_id
         resp, body = self.get(url)
diff --git a/tempest/lib/services/volume/v2/volume_manage_client.py b/tempest/lib/services/volume/v2/volume_manage_client.py
new file mode 100644
index 0000000..12f4240
--- /dev/null
+++ b/tempest/lib/services/volume/v2/volume_manage_client.py
@@ -0,0 +1,37 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# 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 oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class VolumeManageClient(rest_client.RestClient):
+    """Volume manage V2 client."""
+
+    api_version = "v2"
+
+    def manage_volume(self, **kwargs):
+        """Manage existing volume.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/block-storage/v2/#manage-existing-volume
+        """
+        post_body = json.dumps({'volume': kwargs})
+        resp, body = self.post('os-volume-manage', post_body)
+        self.expected_success(202, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v2/volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py
index 8b8e249..44d4d65 100644
--- a/tempest/lib/services/volume/v2/volumes_client.py
+++ b/tempest/lib/services/volume/v2/volumes_client.py
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from debtcollector import moves
 from debtcollector import removals
 from oslo_serialization import jsonutils as json
 import six
@@ -20,12 +21,43 @@
 
 from tempest.lib.common import rest_client
 from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.volume.v2 import transfers_client
 
 
 class VolumesClient(rest_client.RestClient):
     """Client class to send CRUD Volume V2 API requests"""
     api_version = "v2"
 
+    create_volume_transfer = moves.moved_function(
+        transfers_client.TransfersClient.create_volume_transfer,
+        'VolumesClient.create_volume_transfer', __name__,
+        message='Use create_volume_transfer from new location.',
+        version='Pike', removal_version='Queens')
+
+    show_volume_transfer = moves.moved_function(
+        transfers_client.TransfersClient.show_volume_transfer,
+        'VolumesClient.show_volume_transfer', __name__,
+        message='Use show_volume_transfer from new location.',
+        version='Pike', removal_version='Queens')
+
+    list_volume_transfers = moves.moved_function(
+        transfers_client.TransfersClient.list_volume_transfers,
+        'VolumesClient.list_volume_transfers', __name__,
+        message='Use list_volume_transfer from new location.',
+        version='Pike', removal_version='Queens')
+
+    delete_volume_transfer = moves.moved_function(
+        transfers_client.TransfersClient.delete_volume_transfer,
+        'VolumesClient.delete_volume_transfer', __name__,
+        message='Use delete_volume_transfer from new location.',
+        version='Pike', removal_version='Queens')
+
+    accept_volume_transfer = moves.moved_function(
+        transfers_client.TransfersClient.accept_volume_transfer,
+        'VolumesClient.accept_volume_transfer', __name__,
+        message='Use accept_volume_transfer from new location.',
+        version='Pike', removal_version='Queens')
+
     def _prepare_params(self, params):
         """Prepares params for use in get or _ext_get methods.
 
@@ -65,7 +97,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#create-volume
         """
         post_body = json.dumps({'volume': kwargs})
         resp, body = self.post('volumes', post_body)
@@ -78,7 +110,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#update-volume
         """
         put_body = json.dumps({'volume': kwargs})
         resp, body = self.put('volumes/%s' % volume_id, put_body)
@@ -106,7 +138,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#attach-volume-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#attach-volume-to-server
         """
         post_body = json.dumps({'os-attach': kwargs})
         url = 'volumes/%s/action' % (volume_id)
@@ -163,7 +195,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#extend-volume-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#extend-volume-size
         """
         post_body = json.dumps({'os-extend': kwargs})
         url = 'volumes/%s/action' % (volume_id)
@@ -176,69 +208,13 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#reset-volume-status-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#reset-volume-statuses
         """
         post_body = json.dumps({'os-reset_status': kwargs})
         resp, body = self.post('volumes/%s/action' % volume_id, post_body)
         self.expected_success(202, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def create_volume_transfer(self, **kwargs):
-        """Create a volume transfer.
-
-        For a full list of available parameters, please refer to the official
-        API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-transfer-v2
-        """
-        post_body = json.dumps({'transfer': kwargs})
-        resp, body = self.post('os-volume-transfer', post_body)
-        body = json.loads(body)
-        self.expected_success(202, resp.status)
-        return rest_client.ResponseBody(resp, body)
-
-    def show_volume_transfer(self, transfer_id):
-        """Returns the details of a volume transfer."""
-        url = "os-volume-transfer/%s" % transfer_id
-        resp, body = self.get(url)
-        body = json.loads(body)
-        self.expected_success(200, resp.status)
-        return rest_client.ResponseBody(resp, body)
-
-    def list_volume_transfers(self, **params):
-        """List all the volume transfers created.
-
-        For a full list of available parameters, please refer to the official
-        API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#list-volume-transfers-v2
-        """
-        url = 'os-volume-transfer'
-        if params:
-            url += '?%s' % urllib.urlencode(params)
-        resp, body = self.get(url)
-        body = json.loads(body)
-        self.expected_success(200, resp.status)
-        return rest_client.ResponseBody(resp, body)
-
-    def delete_volume_transfer(self, transfer_id):
-        """Delete a volume transfer."""
-        resp, body = self.delete("os-volume-transfer/%s" % transfer_id)
-        self.expected_success(202, resp.status)
-        return rest_client.ResponseBody(resp, body)
-
-    def accept_volume_transfer(self, transfer_id, **kwargs):
-        """Accept a volume transfer.
-
-        For a full list of available parameters, please refer to the official
-        API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#accept-volume-transfer-v2
-        """
-        url = 'os-volume-transfer/%s/accept' % transfer_id
-        post_body = json.dumps({'accept': kwargs})
-        resp, body = self.post(url, post_body)
-        body = json.loads(body)
-        self.expected_success(202, resp.status)
-        return rest_client.ResponseBody(resp, body)
-
     def update_volume_readonly(self, volume_id, **kwargs):
         """Update the Specified Volume readonly."""
         post_body = json.dumps({'os-update_readonly_flag': kwargs})
@@ -307,7 +283,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-image-metadata-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#set-image-metadata-for-volume
         """
         post_body = json.dumps({'os-set_image_metadata': {'metadata': kwargs}})
         url = "volumes/%s/action" % (volume_id)
@@ -344,10 +320,22 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#show_backend_capabilities-v2
+        http://developer.openstack.org/api-ref/block-storage/v2/#show-back-end-capabilities
         """
         url = 'capabilities/%s' % host
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
+
+    def unmanage_volume(self, volume_id):
+        """Unmanage volume.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/block-storage/v2/#unmanage-volume
+        """
+        post_body = json.dumps({'os-unmanage': {}})
+        resp, body = self.post('volumes/%s/action' % volume_id, post_body)
+        self.expected_success(202, resp.status)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v3/__init__.py b/tempest/lib/services/volume/v3/__init__.py
index a4600a8..72ab785 100644
--- a/tempest/lib/services/volume/v3/__init__.py
+++ b/tempest/lib/services/volume/v3/__init__.py
@@ -14,5 +14,6 @@
 
 from tempest.lib.services.volume.v3.base_client import BaseClient
 from tempest.lib.services.volume.v3.messages_client import MessagesClient
+from tempest.lib.services.volume.v3.versions_client import VersionsClient
 
-__all__ = ['MessagesClient', 'BaseClient']
+__all__ = ['MessagesClient', 'BaseClient', 'VersionsClient']
diff --git a/tempest/lib/services/volume/v3/versions_client.py b/tempest/lib/services/volume/v3/versions_client.py
new file mode 100644
index 0000000..e2941c4
--- /dev/null
+++ b/tempest/lib/services/volume/v3/versions_client.py
@@ -0,0 +1,47 @@
+# Copyright 2017 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 time
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.api_schema.response.volume import versions as schema
+from tempest.lib.common import rest_client
+from tempest.lib.services.volume.v3 import base_client
+
+
+class VersionsClient(base_client.BaseClient):
+
+    def list_versions(self):
+        """List API versions
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/block-storage/v3/#list-all-api-versions
+        """
+        version_url = self._get_base_version_url()
+
+        start = time.time()
+        resp, body = self.raw_request(version_url, 'GET')
+        end = time.time()
+        # NOTE: We need a raw_request() here instead of request() call because
+        # "list API versions" API doesn't require an authentication and we can
+        # skip it with raw_request() call.
+        self._log_request('GET', version_url, resp, secs=(end - start),
+                          resp_body=body)
+        self._error_checker(resp, body)
+
+        body = json.loads(body)
+        self.validate_response(schema.list_versions, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 052f175..c1270c7 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -20,16 +20,15 @@
 from oslo_log import log
 from oslo_serialization import jsonutils as json
 from oslo_utils import netutils
-import six
 
 from tempest.common import compute
 from tempest.common import image as common_image
-from tempest.common.utils import data_utils
 from tempest.common.utils.linux import remote_client
 from tempest.common.utils import net_utils
 from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
+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
@@ -80,13 +79,8 @@
         cls.security_groups_client = cls.manager.security_groups_client
         cls.security_group_rules_client = (
             cls.manager.security_group_rules_client)
-
-        if CONF.volume_feature_enabled.api_v2:
-            cls.volumes_client = cls.manager.volumes_v2_client
-            cls.snapshots_client = cls.manager.snapshots_v2_client
-        else:
-            cls.volumes_client = cls.manager.volumes_client
-            cls.snapshots_client = cls.manager.snapshots_client
+        cls.volumes_client = cls.manager.volumes_v2_client
+        cls.snapshots_client = cls.manager.snapshots_v2_client
 
     # ## Test functions library
     #
@@ -118,7 +112,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.
 
@@ -236,19 +230,35 @@
                         volume['id'])
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.volumes_client.delete_volume, volume['id'])
-
-        # NOTE(e0ne): Cinder API v2 uses name instead of display_name
-        if 'display_name' in volume:
-            self.assertEqual(name, volume['display_name'])
-        else:
-            self.assertEqual(name, volume['name'])
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume['id'], 'available')
+        self.assertEqual(name, volume['name'])
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'available')
         # The volume retrieved on creation has a non-up-to-date status.
         # Retrieval after it becomes active ensures correct details.
         volume = self.volumes_client.show_volume(volume['id'])['volume']
         return volume
 
+    def create_volume_type(self, client=None, name=None, backend_name=None):
+        if not client:
+            client = self.admin_volume_types_client
+        if not name:
+            class_name = self.__class__.__name__
+            name = data_utils.rand_name(class_name + '-volume-type')
+        randomized_name = data_utils.rand_name('scenario-type-' + name)
+
+        LOG.debug("Creating a volume type: %s on backend %s",
+                  randomized_name, backend_name)
+        extra_specs = {}
+        if backend_name:
+            extra_specs = {"volume_backend_name": backend_name}
+
+        body = client.create_volume_type(name=randomized_name,
+                                         extra_specs=extra_specs)
+        volume_type = body['volume_type']
+        self.assertIn('id', volume_type)
+        self.addCleanup(client.delete_volume_type, volume_type['id'])
+        return volume_type
+
     def _create_loginable_secgroup_rule(self, secgroup_id=None):
         _client = self.compute_security_groups_client
         _client_rules = self.compute_security_group_rules_client
@@ -461,8 +471,9 @@
                 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                                 self.snapshots_client.delete_snapshot,
                                 snapshot_id)
-                waiters.wait_for_snapshot_status(self.snapshots_client,
-                                                 snapshot_id, 'available')
+                waiters.wait_for_volume_resource_status(self.snapshots_client,
+                                                        snapshot_id,
+                                                        'available')
         image_name = snapshot_image['name']
         self.assertEqual(name, image_name)
         LOG.debug("Created snapshot image %s for server %s",
@@ -474,16 +485,16 @@
             server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
             % CONF.compute.volume_device_name)['volumeAttachment']
         self.assertEqual(volume_to_attach['id'], volume['id'])
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume['id'], 'in-use')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'in-use')
 
         # Return the updated volume after the attachment
         return self.volumes_client.show_volume(volume['id'])['volume']
 
     def nova_volume_detach(self, server, volume):
         self.servers_client.detach_volume(server['id'], volume['id'])
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'available')
 
         volume = self.volumes_client.show_volume(volume['id'])['volume']
         self.assertEqual('available', volume['status'])
@@ -530,14 +541,14 @@
 
         caller = test_utils.find_test_caller()
         LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
-                  ' expected result is %(should_succeed)s', **{
+                  ' expected result is %(should_succeed)s', {
                       'caller': caller, 'ip': ip_address, 'timeout': timeout,
                       'should_succeed':
                       'reachable' if should_succeed else 'unreachable'
                   })
         result = test_utils.call_until_true(ping, timeout, 1)
         LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
-                  'ping result is %(result)s', **{
+                  'ping result is %(result)s', {
                       'caller': caller, 'ip': ip_address, 'timeout': timeout,
                       'result': 'expected' if result else 'unexpected'
                   })
@@ -614,13 +625,14 @@
                                             private_key=private_key)
         if dev_name is not None:
             ssh_client.make_fs(dev_name)
-            ssh_client.mount(dev_name, mount_path)
+            ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name,
+                                                               mount_path))
         cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
         ssh_client.exec_command(cmd_timestamp)
         timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
                                             % mount_path)
         if dev_name is not None:
-            ssh_client.umount(mount_path)
+            ssh_client.exec_command('sudo umount %s' % mount_path)
         return timestamp
 
     def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
@@ -632,7 +644,7 @@
         timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
                                             % mount_path)
         if dev_name is not None:
-            ssh_client.umount(mount_path)
+            ssh_client.exec_command('sudo umount %s' % mount_path)
         return timestamp
 
     def get_server_ip(self, server):
@@ -688,13 +700,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)
@@ -708,40 +718,10 @@
 
         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
 
-    def _list_networks(self, *args, **kwargs):
-        """List networks using admin creds """
-        networks_list = self.admin_manager.networks_client.list_networks(
-            *args, **kwargs)
-        return networks_list['networks']
-
-    def _list_subnets(self, *args, **kwargs):
-        """List subnets using admin creds """
-        subnets_list = self.admin_manager.subnets_client.list_subnets(
-            *args, **kwargs)
-        return subnets_list['subnets']
-
-    def _list_routers(self, *args, **kwargs):
-        """List routers using admin creds """
-        routers_list = self.admin_manager.routers_client.list_routers(
-            *args, **kwargs)
-        return routers_list['routers']
-
-    def _list_ports(self, *args, **kwargs):
-        """List ports using admin creds """
-        ports_list = self.admin_manager.ports_client.list_ports(
-            *args, **kwargs)
-        return ports_list['ports']
-
-    def _list_agents(self, *args, **kwargs):
-        """List agents using admin creds """
-        agents_list = self.admin_manager.network_agents_client.list_agents(
-            *args, **kwargs)
-        return agents_list['agents']
-
     def _create_subnet(self, network, subnets_client=None,
                        routers_client=None, namestart='subnet-smoke',
                        **kwargs):
@@ -760,7 +740,8 @@
             :returns: True if subnet with cidr already exist in tenant
                   False else
             """
-            cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
+            cidr_in_use = self.admin_manager.subnets_client.list_subnets(
+                tenant_id=tenant_id, cidr=cidr)['subnets']
             return len(cidr_in_use) != 0
 
         ip_version = kwargs.pop('ip_version', 4)
@@ -808,7 +789,8 @@
         return subnet
 
     def _get_server_port_id_and_ip4(self, server, ip_addr=None):
-        ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
+        ports = self.admin_manager.ports_client.list_ports(
+            device_id=server['id'], fixed_ip=ip_addr)['ports']
         # A port can have more than one IP address in some cases.
         # If the network is dual-stack (IPv4 + IPv6), this port is associated
         # with 2 subnets
@@ -837,7 +819,8 @@
         return port_map[0]
 
     def _get_network_by_name(self, network_name):
-        net = self._list_networks(name=network_name)
+        net = self.admin_manager.networks_client.list_networks(
+            name=network_name)['networks']
         self.assertNotEqual(len(net), 0,
                             "Unable to get network by name: %s" % network_name)
         return net[0]
@@ -861,7 +844,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
 
@@ -895,16 +878,16 @@
                       show_floatingip(floatingip_id)['floatingip'])
             return status == result['status']
 
-        test_utils.call_until_true(refresh,
-                                   CONF.network.build_timeout,
-                                   CONF.network.build_interval)
-        floating_ip = self.floating_ips_client.show_floatingip(
-            floatingip_id)['floatingip']
-        self.assertEqual(status, floating_ip['status'],
-                         message="FloatingIP: {fp} is at status: {cst}. "
-                                 "failed  to reach status: {st}"
-                         .format(fp=floating_ip, cst=floating_ip['status'],
-                                 st=status))
+        if not test_utils.call_until_true(refresh,
+                                          CONF.network.build_timeout,
+                                          CONF.network.build_interval):
+            floating_ip = self.floating_ips_client.show_floatingip(
+                floatingip_id)['floatingip']
+            self.assertEqual(status, floating_ip['status'],
+                             message="FloatingIP: {fp} is at status: {cst}. "
+                                     "failed  to reach status: {st}"
+                             .format(fp=floating_ip, cst=floating_ip['status'],
+                                     st=status))
         LOG.info("FloatingIP: {fp} is at status: {st}"
                  .format(fp=floating_ip, st=status))
 
@@ -920,7 +903,7 @@
         # The target login is assumed to have been configured for
         # key-based authentication by cloud-init.
         try:
-            for net_name, ip_addresses in six.iteritems(server['addresses']):
+            for ip_addresses in server['addresses'].values():
                 for ip_address in ip_addresses:
                     self.check_vm_connectivity(ip_address['addr'],
                                                username,
@@ -934,14 +917,15 @@
 
     def _check_remote_connectivity(self, source, dest, should_succeed=True,
                                    nic=None):
-        """check ping server via source ssh connection
+        """assert ping server via source ssh connection
+
+        Note: This is an internal method.  Use check_remote_connectivity
+        instead.
 
         :param source: RemoteClient: an ssh connection from which to ping
         :param dest: and IP to ping against
         :param should_succeed: boolean should ping succeed or not
         :param nic: specific network interface to ping from
-        :returns: boolean -- should_succeed == ping
-        :returns: ping is false if ping failed
         """
         def ping_remote():
             try:
@@ -956,6 +940,25 @@
                                           CONF.validation.ping_timeout,
                                           1)
 
+    def check_remote_connectivity(self, source, dest, should_succeed=True,
+                                  nic=None):
+        """assert ping server via source ssh connection
+
+        :param source: RemoteClient: an ssh connection from which to ping
+        :param dest: and IP to ping against
+        :param should_succeed: boolean should ping succeed or not
+        :param nic: specific network interface to ping from
+        """
+        result = self._check_remote_connectivity(source, dest, should_succeed,
+                                                 nic)
+        source_host = source.ssh_client.host
+        if should_succeed:
+            msg = "Timed out waiting for %s to become reachable from %s" \
+                % (dest, source_host)
+        else:
+            msg = "%s is reachable from %s" % (dest, source_host)
+        self.assertTrue(result, msg)
+
     def _create_security_group(self, security_group_rules_client=None,
                                tenant_id=None,
                                namestart='secgroup-smoke',
@@ -1238,27 +1241,9 @@
     @classmethod
     def setup_clients(cls):
         super(EncryptionScenarioTest, cls).setup_clients()
-        if CONF.volume_feature_enabled.api_v2:
-            cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
-            cls.admin_encryption_types_client =\
-                cls.os_adm.encryption_types_v2_client
-        else:
-            cls.admin_volume_types_client = cls.os_adm.volume_types_client
-            cls.admin_encryption_types_client =\
-                cls.os_adm.encryption_types_client
-
-    def create_volume_type(self, client=None, name=None):
-        if not client:
-            client = self.admin_volume_types_client
-        if not name:
-            name = 'generic'
-        randomized_name = data_utils.rand_name('scenario-type-' + name)
-        LOG.debug("Creating a volume type: %s", randomized_name)
-        body = client.create_volume_type(
-            name=randomized_name)['volume_type']
-        self.assertIn('id', body)
-        self.addCleanup(client.delete_volume_type, body['id'])
-        return body
+        cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
+        cls.admin_encryption_types_client =\
+            cls.os_adm.encryption_types_v2_client
 
     def create_encryption_type(self, client=None, type_id=None, provider=None,
                                key_size=None, cipher=None,
@@ -1327,7 +1312,7 @@
 
     def upload_object_to_container(self, container_name, obj_name=None):
         obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
-        obj_data = data_utils.arbitrary_string()
+        obj_data = data_utils.random_bytes()
         self.object_client.create_object(container_name, obj_name, obj_data)
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.object_client.delete_object,
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 8de3561..cefa119 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -14,7 +14,8 @@
 #    under the License.
 
 from tempest.common import tempest_fixtures as fixtures
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -35,9 +36,8 @@
     def setup_clients(cls):
         super(TestAggregatesBasicOps, cls).setup_clients()
         # Use admin client by default
-        cls.manager = cls.admin_manager
-        cls.aggregates_client = cls.manager.aggregates_client
-        cls.hosts_client = cls.manager.hosts_client
+        cls.aggregates_client = cls.admin_manager.aggregates_client
+        cls.hosts_client = cls.admin_manager.hosts_client
 
     def _create_aggregate(self, **kwargs):
         aggregate = (self.aggregates_client.create_aggregate(**kwargs)
@@ -82,7 +82,7 @@
         aggregate = self.aggregates_client.set_metadata(aggregate['id'],
                                                         metadata=meta)
 
-        for key, value in meta.items():
+        for key in meta.keys():
             self.assertEqual(meta[key],
                              aggregate['aggregate']['metadata'][key])
 
@@ -95,7 +95,8 @@
         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.attr(type='slow')
     @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..a05b1b1 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,8 @@
         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.attr(type='slow')
     @test.services('compute', 'volume', 'image')
     def test_encrypted_cinder_volumes_luks(self):
         server = self.launch_instance()
@@ -71,7 +71,8 @@
                                               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.attr(type='slow')
     @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..5fee801 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -13,10 +13,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 from tempest.common import custom_matchers
 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
@@ -91,21 +94,21 @@
             raise exceptions.TimeoutException(msg)
 
     def _get_floating_ip_in_server_addresses(self, floating_ip, server):
-        for network_name, addresses in server['addresses'].items():
+        for addresses in server['addresses'].values():
             for address in addresses:
                 if (address['OS-EXT-IPS:type'] == 'floating' and
                         address['addr'] == floating_ip['ip']):
                     return address
 
-    @test.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8')
+    @decorators.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     @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..6665fa7 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
 
@@ -38,7 +39,6 @@
     def setup_clients(cls):
         super(TestNetworkAdvancedServerOps, cls).setup_clients()
         cls.admin_servers_client = cls.os_adm.servers_client
-        cls.admin_hosts_client = cls.os_adm.hosts_client
 
     @classmethod
     def skip_checks(cls):
@@ -64,8 +64,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 +103,8 @@
         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.attr(type='slow')
     @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,8 @@
         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.attr(type='slow')
     @test.services('compute', 'network')
     def test_server_connectivity_rebuild(self):
         keypair = self.create_keypair()
@@ -141,9 +142,10 @@
         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.attr(type='slow')
     @test.services('compute', 'network')
     def test_server_connectivity_pause_unpause(self):
         keypair = self.create_keypair()
@@ -158,9 +160,10 @@
         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.attr(type='slow')
     @test.services('compute', 'network')
     def test_server_connectivity_suspend_resume(self):
         keypair = self.create_keypair()
@@ -175,9 +178,10 @@
         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.attr(type='slow')
     @test.services('compute', 'network')
     def test_server_connectivity_resize(self):
         resize_flavor = CONF.compute.flavor_ref_alt
@@ -195,12 +199,13 @@
         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,
                           'Less than 2 compute nodes, skipping multinode '
                           'tests.')
+    @test.attr(type='slow')
     @test.services('compute', 'network')
     def test_server_connectivity_cold_migration(self):
         keypair = self.create_keypair()
@@ -220,12 +225,13 @@
 
         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,
                           'Less than 2 compute nodes, skipping multinode '
                           'tests.')
+    @test.attr(type='slow')
     @test.services('compute', 'network')
     def test_server_connectivity_cold_migration_revert(self):
         keypair = self.create_keypair()
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 4bbe4eb..dec0ad0 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -104,18 +104,17 @@
 
     def _setup_network_and_servers(self, **kwargs):
         boot_with_port = kwargs.pop('boot_with_port', False)
-        self.security_group = self._create_security_group()
         self.network, self.subnet, self.router = self.create_networks(**kwargs)
         self.check_networks()
 
         self.ports = []
-        self.port_id = None
+        port_id = None
         if boot_with_port:
             # create a port on the network and boot with that
-            self.port_id = self._create_port(self.network['id'])['id']
-            self.ports.append({'port': self.port_id})
+            port_id = self._create_port(self.network['id'])['id']
+            self.ports.append({'port': port_id})
 
-        server = self._create_server(self.network, self.port_id)
+        server = self._create_server(self.network, port_id)
         self._check_tenant_network_connectivity()
 
         floating_ip = self.create_floating_ip(server)
@@ -127,23 +126,23 @@
         via checking the result of list_[networks,routers,subnets]
         """
 
-        seen_nets = self._list_networks()
-        seen_names = [n['name'] for n in seen_nets]
-        seen_ids = [n['id'] for n in seen_nets]
+        seen_nets = self.admin_manager.networks_client.list_networks()
+        seen_names = [n['name'] for n in seen_nets['networks']]
+        seen_ids = [n['id'] for n in seen_nets['networks']]
         self.assertIn(self.network['name'], seen_names)
         self.assertIn(self.network['id'], seen_ids)
 
         if self.subnet:
-            seen_subnets = self._list_subnets()
-            seen_net_ids = [n['network_id'] for n in seen_subnets]
-            seen_subnet_ids = [n['id'] for n in seen_subnets]
+            seen_subnets = self.admin_manager.subnets_client.list_subnets()
+            seen_net_ids = [n['network_id'] for n in seen_subnets['subnets']]
+            seen_subnet_ids = [n['id'] for n in seen_subnets['subnets']]
             self.assertIn(self.network['id'], seen_net_ids)
             self.assertIn(self.subnet['id'], seen_subnet_ids)
 
         if self.router:
-            seen_routers = self._list_routers()
-            seen_router_ids = [n['id'] for n in seen_routers]
-            seen_router_names = [n['name'] for n in seen_routers]
+            seen_routers = self.admin_manager.routers_client.list_routers()
+            seen_router_ids = [n['id'] for n in seen_routers['routers']]
+            seen_router_names = [n['name'] for n in seen_routers['routers']]
             self.assertIn(self.router['name'],
                           seen_router_names)
             self.assertIn(self.router['id'],
@@ -152,7 +151,9 @@
     def _create_server(self, network, port_id=None):
         keypair = self.create_keypair()
         self.keypairs[keypair['name']] = keypair
-        security_groups = [{'name': self.security_group['name']}]
+        security_groups = [
+            {'name': self._create_security_group()['name']}
+        ]
         network = {'uuid': network['id']}
         if port_id is not None:
             network['port'] = port_id
@@ -160,8 +161,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
 
@@ -241,7 +241,8 @@
             ip_address, private_key=private_key)
         old_nic_list = self._get_server_nics(ssh_client)
         # get a port from a list of one item
-        port_list = self._list_ports(device_id=server['id'])
+        port_list = self.admin_manager.ports_client.list_ports(
+            device_id=server['id'])['ports']
         self.assertEqual(1, len(port_list))
         old_port = port_list[0]
         interface = self.interface_client.create_interface(
@@ -254,9 +255,12 @@
                         server['id'], interface['port_id'])
 
         def check_ports():
-            self.new_port_list = [port for port in
-                                  self._list_ports(device_id=server['id'])
-                                  if port['id'] != old_port['id']]
+            self.new_port_list = [
+                port for port in
+                self.admin_manager.ports_client.list_ports(
+                    device_id=server['id'])['ports']
+                if port['id'] != old_port['id']
+            ]
             return len(self.new_port_list) == 1
 
         if not test_utils.call_until_true(
@@ -282,14 +286,15 @@
                                               % CONF.network.build_timeout)
 
         num, new_nic = self.diff_list[0]
-        ssh_client.assign_static_ip(nic=new_nic,
-                                    addr=new_port['fixed_ips'][0][
-                                        'ip_address'])
-        ssh_client.set_nic_state(nic=new_nic)
+        ssh_client.exec_command("sudo ip addr add %s/%s dev %s" % (
+                                new_port['fixed_ips'][0]['ip_address'],
+                                CONF.network.project_network_mask_bits,
+                                new_nic))
+        ssh_client.exec_command("sudo ip link set %s up" % new_nic)
 
     def _get_server_nics(self, ssh_client):
         reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
-        ipatxt = ssh_client.get_ip_list()
+        ipatxt = ssh_client.exec_command("ip address")
         return reg.findall(ipatxt)
 
     def _check_network_internal_connectivity(self, network,
@@ -302,10 +307,13 @@
         floating_ip, server = self.floating_ip_tuple
         # get internal ports' ips:
         # get all network ports in the new network
-        internal_ips = (p['fixed_ips'][0]['ip_address'] for p in
-                        self._list_ports(tenant_id=server['tenant_id'],
-                                         network_id=network['id'])
-                        if p['device_owner'].startswith('network'))
+        internal_ips = (
+            p['fixed_ips'][0]['ip_address'] for p in
+            self.admin_manager.ports_client.list_ports(
+                tenant_id=server['tenant_id'],
+                network_id=network['id'])['ports']
+            if p['device_owner'].startswith('network')
+        )
 
         self._check_server_connectivity(floating_ip,
                                         internal_ips,
@@ -321,8 +329,11 @@
         # We ping the external IP from the instance using its floating IP
         # which is always IPv4, so we must only test connectivity to
         # external IPv4 IPs if the external network is dualstack.
-        v4_subnets = [s for s in self._list_subnets(
-            network_id=CONF.network.public_network_id) if s['ip_version'] == 4]
+        v4_subnets = [
+            s for s in self.admin_manager.subnets_client.list_subnets(
+                network_id=CONF.network.public_network_id)['subnets']
+            if s['ip_version'] == 4
+        ]
         self.assertEqual(1, len(v4_subnets),
                          "Found %d IPv4 subnets" % len(v4_subnets))
 
@@ -338,23 +349,11 @@
             ip_address, private_key=private_key)
 
         for remote_ip in address_list:
-            if should_connect:
-                msg = ("Timed out waiting for %s to become "
-                       "reachable") % remote_ip
-            else:
-                msg = "ip address %s is reachable" % remote_ip
-            try:
-                self.assertTrue(self._check_remote_connectivity
-                                (ssh_source, remote_ip, should_connect),
-                                msg)
-            except Exception:
-                LOG.exception("Unable to access {dest} via ssh to "
-                              "floating-ip {src}".format(dest=remote_ip,
-                                                         src=floating_ip))
-                raise
+            self.check_remote_connectivity(ssh_source, remote_ip,
+                                           should_connect)
 
     @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,9 +405,10 @@
                                                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.attr(type='slow')
     @test.services('compute', 'network')
     def test_mtu_sized_frames(self):
         """Validate that network MTU sized frames fit through."""
@@ -416,11 +416,12 @@
         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')
     @decorators.skip_because(bug="1610994")
+    @test.attr(type='slow')
     @test.services('compute', 'network')
     def test_connectivity_between_vms_on_different_networks(self):
         """Test connectivity between VMs on different networks
@@ -469,7 +470,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,10 +493,11 @@
         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')
+    @test.attr(type='slow')
     @test.services('compute', 'network')
     def test_update_router_admin_state(self):
         """Test to update admin state up of router
@@ -524,11 +526,12 @@
             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,
                           "DHCP client is not available.")
+    @test.attr(type='slow')
     @test.services('compute', 'network')
     def test_subnet_details(self):
         """Tests that subnet's extra configuration details are affecting VMs.
@@ -595,7 +598,8 @@
             # NOTE(amuller): we are renewing the lease as part of the retry
             # because Neutron updates dnsmasq asynchronously after the
             # subnet-update API call returns.
-            ssh_client.renew_lease(fixed_ip=floating_ip['fixed_ip_address'])
+            ssh_client.renew_lease(fixed_ip=floating_ip['fixed_ip_address'],
+                                   dhcp_client=CONF.scenario.dhcp_client)
             if ssh_client.get_dns_servers() != [alt_dns_server]:
                 LOG.debug("Failed to update DNS nameservers")
                 return False
@@ -607,39 +611,57 @@
                         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")
+    @test.attr(type='slow')
     @test.services('compute', 'network')
     def test_update_instance_port_admin_state(self):
         """Test to update admin_state_up attribute of instance port
 
-        1. Check public connectivity before updating
+        1. Check public and project connectivity before updating
                 admin_state_up attribute of instance port to False
-        2. Check public connectivity after updating
+        2. Check public and project connectivity after updating
                 admin_state_up attribute of instance port to False
-        3. Check public connectivity after updating
+        3. Check public and project connectivity after updating
                 admin_state_up attribute of instance port to True
         """
         self._setup_network_and_servers()
         floating_ip, server = self.floating_ip_tuple
         server_id = server['id']
-        port_id = self._list_ports(device_id=server_id)[0]['id']
+        port_id = self.admin_manager.ports_client.list_ports(
+            device_id=server_id)['ports'][0]['id']
+        server_pip = server['addresses'][self.network['name']][0]['addr']
+
+        server2 = self._create_server(self.network)
+        server2_fip = self.create_floating_ip(server2)
+
+        private_key = self._get_server_key(server2)
+        ssh_client = self.get_remote_client(server2_fip['floating_ip_address'],
+                                            private_key=private_key)
+
         self.check_public_network_connectivity(
             should_connect=True, msg="before updating "
             "admin_state_up of instance port to False")
+        self.check_remote_connectivity(ssh_client, dest=server_pip,
+                                       should_succeed=True)
         self.ports_client.update_port(port_id, admin_state_up=False)
         self.check_public_network_connectivity(
             should_connect=False, msg="after updating "
             "admin_state_up of instance port to False",
             should_check_floating_ip_status=False)
+        self.check_remote_connectivity(ssh_client, dest=server_pip,
+                                       should_succeed=False)
         self.ports_client.update_port(port_id, admin_state_up=True)
         self.check_public_network_connectivity(
             should_connect=True, msg="after updating "
             "admin_state_up of instance port to True")
+        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.attr(type='slow')
     @test.services('compute', 'network')
     def test_preserve_preexisting_port(self):
         """Test preserve pre-existing port
@@ -663,8 +685,8 @@
                              'Server should have been created from a '
                              'pre-existing port.')
         # Assert the port is bound to the server.
-        port_list = self._list_ports(device_id=server['id'],
-                                     network_id=self.network['id'])
+        port_list = self.admin_manager.ports_client.list_ports(
+            device_id=server['id'], network_id=self.network['id'])['ports']
         self.assertEqual(1, len(port_list),
                          'There should only be one port created for '
                          'server %s.' % server['id'])
@@ -682,15 +704,16 @@
         # Boot another server with the same port to make sure nothing was
         # left around that could cause issues.
         server = self._create_server(self.network, port['id'])
-        port_list = self._list_ports(device_id=server['id'],
-                                     network_id=self.network['id'])
+        port_list = self.admin_manager.ports_client.list_ports(
+            device_id=server['id'], network_id=self.network['id'])['ports']
         self.assertEqual(1, len(port_list),
                          'There should only be one port created for '
                          'server %s.' % server['id'])
         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.attr(type='slow')
     @test.services('compute', 'network')
     def test_router_rescheduling(self):
         """Tests that router can be removed from agent and add to a new agent.
@@ -713,9 +736,11 @@
         unschedule_router = (self.admin_manager.network_agents_client.
                              delete_router_from_l3_agent)
 
-        agent_list_alive = set(a["id"] for a in
-                               self._list_agents(agent_type="L3 agent") if
-                               a["alive"] is True)
+        agent_list_alive = set(
+            a["id"] for a in
+            self.admin_manager.network_agents_client.list_agents(
+                agent_type="L3 agent")['agents'] if a["alive"] is True
+        )
         self._setup_network_and_servers()
 
         # NOTE(kevinbenton): we have to use the admin credentials to check
@@ -767,7 +792,8 @@
     @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.attr(type='slow')
     @test.services('compute', 'network')
     def test_port_security_macspoofing_port(self):
         """Tests port_security extension enforces mac spoofing
@@ -797,8 +823,8 @@
         self._create_new_network()
         self._hotplug_server()
         fip, server = self.floating_ip_tuple
-        new_ports = self._list_ports(device_id=server["id"],
-                                     network_id=self.new_net["id"])
+        new_ports = self.admin_manager.ports_client.list_ports(
+            device_id=server["id"], network_id=self.new_net["id"])['ports']
         spoof_port = new_ports[0]
         private_key = self._get_server_key(server)
         ssh_client = self.get_remote_client(fip['floating_ip_address'],
@@ -806,15 +832,21 @@
         spoof_nic = ssh_client.get_nic_name_by_mac(spoof_port["mac_address"])
         peer = self._create_server(self.new_net)
         peer_address = peer['addresses'][self.new_net['name']][0]['addr']
-        self._check_remote_connectivity(ssh_client, dest=peer_address,
-                                        nic=spoof_nic, should_succeed=True)
-        ssh_client.set_mac_address(spoof_nic, spoof_mac)
+        self.check_remote_connectivity(ssh_client, dest=peer_address,
+                                       nic=spoof_nic, should_succeed=True)
+        # Set a mac address by making nic down temporary
+        cmd = ("sudo ip link set {nic} down;"
+               "sudo ip link set dev {nic} address {mac};"
+               "sudo ip link set {nic} up").format(nic=spoof_nic,
+                                                   mac=spoof_mac)
+        ssh_client.exec_command(cmd)
+
         new_mac = ssh_client.get_mac_address(nic=spoof_nic)
         self.assertEqual(spoof_mac, new_mac)
-        self._check_remote_connectivity(ssh_client, dest=peer_address,
-                                        nic=spoof_nic, should_succeed=False)
+        self.check_remote_connectivity(ssh_client, dest=peer_address,
+                                       nic=spoof_nic, should_succeed=False)
         self.ports_client.update_port(spoof_port["id"],
                                       port_security_enabled=False,
                                       security_groups=[])
-        self._check_remote_connectivity(ssh_client, dest=peer_address,
-                                        nic=spoof_nic, should_succeed=True)
+        self.check_remote_connectivity(ssh_client, dest=peer_address,
+                                       nic=spoof_nic, should_succeed=True)
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 40b3317..4e8b004 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -14,14 +14,12 @@
 #    under the License.
 import functools
 
-import six
-
 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
 
 
@@ -74,11 +72,11 @@
         if dualnet - create IPv6 subnets on a different network
         :return: list of created networks
         """
-        self.network = self._create_network()
+        network = self._create_network()
         if dualnet:
-            self.network_v6 = self._create_network()
+            network_v6 = self._create_network()
 
-        sub4 = self._create_subnet(network=self.network,
+        sub4 = self._create_subnet(network=network,
                                    namestart='sub4',
                                    ip_version=4)
 
@@ -92,7 +90,7 @@
 
         self.subnets_v6 = []
         for _ in range(n_subnets6):
-            net6 = self.network_v6 if dualnet else self.network
+            net6 = network_v6 if dualnet else network
             sub6 = self._create_subnet(network=net6,
                                        namestart='sub6',
                                        ip_version=6,
@@ -107,12 +105,12 @@
                             router['id'], subnet_id=sub6['id'])
 
             self.subnets_v6.append(sub6)
-        return [self.network, self.network_v6] if dualnet else [self.network]
+        return [network, network_v6] if dualnet else [network]
 
     @staticmethod
     def define_server_ips(srv):
         ips = {'4': None, '6': []}
-        for net_name, nics in six.iteritems(srv['addresses']):
+        for nics in srv['addresses'].values():
             for nic in nics:
                 if nic['version'] == 6:
                     ips['6'].append(nic['addr'])
@@ -123,13 +121,10 @@
     def prepare_server(self, networks=None):
         username = CONF.validation.image_ssh_user
 
-        networks = networks or [self.network]
-
         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(
@@ -137,7 +132,7 @@
             username=username)
         return ssh, ips, srv["id"]
 
-    def turn_nic6_on(self, ssh, sid):
+    def turn_nic6_on(self, ssh, sid, network_id):
         """Turns the IPv6 vNIC on
 
         Required because guest images usually set only the first vNIC on boot.
@@ -145,16 +140,21 @@
 
         @param ssh: RemoteClient ssh instance to server
         @param sid: server uuid
+        @param network_id: the network id the NIC is connected to
         """
-        ports = [p["mac_address"] for p in
-                 self._list_ports(device_id=sid,
-                                  network_id=self.network_v6['id'])]
+        ports = [
+            p["mac_address"] for p in
+            self.admin_manager.ports_client.list_ports(
+                device_id=sid, network_id=network_id)['ports']
+        ]
+
         self.assertEqual(1, len(ports),
                          message=("Multiple IPv6 ports found on network %s. "
                                   "ports: %s")
-                         % (self.network_v6, ports))
+                         % (network_id, ports))
         mac6 = ports[0]
-        ssh.set_nic_state(ssh.get_nic_name_by_mac(mac6))
+        nic = ssh.get_nic_name_by_mac(mac6)
+        ssh.exec_command("sudo ip link set %s up" % nic)
 
     def _prepare_and_test(self, address6_mode, n_subnets6=1, dualnet=False):
         net_list = self.prepare_network(address6_mode=address6_mode,
@@ -165,16 +165,17 @@
         sshv4_2, ips_from_api_2, sid2 = self.prepare_server(networks=net_list)
 
         def guest_has_address(ssh, addr):
-            return addr in ssh.get_ip_list()
+            return addr in ssh.exec_command("ip address")
 
         # Turn on 2nd NIC for Cirros when dualnet
         if dualnet:
-            self.turn_nic6_on(sshv4_1, sid1)
-            self.turn_nic6_on(sshv4_2, sid2)
+            network, network_v6 = net_list
+            self.turn_nic6_on(sshv4_1, sid1, network_v6['id'])
+            self.turn_nic6_on(sshv4_2, sid2, network_v6['id'])
 
         # get addresses assigned to vNIC as reported by 'ip address' utility
-        ips_from_ip_1 = sshv4_1.get_ip_list()
-        ips_from_ip_2 = sshv4_2.get_ip_list()
+        ips_from_ip_1 = sshv4_1.exec_command("ip address")
+        ips_from_ip_2 = sshv4_2.exec_command("ip address")
         self.assertIn(ips_from_api_1['4'], ips_from_ip_1)
         self.assertIn(ips_from_api_2['4'], ips_from_ip_2)
         for i in range(n_subnets6):
@@ -192,69 +193,63 @@
             self.assertTrue(test_utils.call_until_true(srv2_v6_addr_assigned,
                             CONF.validation.ping_timeout, 1))
 
-        self._check_connectivity(sshv4_1, ips_from_api_2['4'])
-        self._check_connectivity(sshv4_2, ips_from_api_1['4'])
+        self.check_remote_connectivity(sshv4_1, ips_from_api_2['4'])
+        self.check_remote_connectivity(sshv4_2, ips_from_api_1['4'])
 
         for i in range(n_subnets6):
-            self._check_connectivity(sshv4_1,
-                                     ips_from_api_2['6'][i])
-            self._check_connectivity(sshv4_1,
-                                     self.subnets_v6[i]['gateway_ip'])
-            self._check_connectivity(sshv4_2,
-                                     ips_from_api_1['6'][i])
-            self._check_connectivity(sshv4_2,
-                                     self.subnets_v6[i]['gateway_ip'])
-
-    def _check_connectivity(self, source, dest):
-        self.assertTrue(
-            self._check_remote_connectivity(source, dest),
-            "Timed out waiting for %s to become reachable from %s" %
-            (dest, source.ssh_client.host)
-        )
+            self.check_remote_connectivity(sshv4_1,
+                                           ips_from_api_2['6'][i])
+            self.check_remote_connectivity(sshv4_1,
+                                           self.subnets_v6[i]['gateway_ip'])
+            self.check_remote_connectivity(sshv4_2,
+                                           ips_from_api_1['6'][i])
+            self.check_remote_connectivity(sshv4_2,
+                                           self.subnets_v6[i]['gateway_ip'])
 
     @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')
+    @test.attr(type='slow')
+    @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..7fd8c91 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,8 @@
                                               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.attr(type='slow')
     @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..55a3db8 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -15,9 +15,10 @@
 from oslo_log import log
 import testtools
 
-from tempest.common.utils import data_utils
 from tempest.common.utils import net_info
 from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -219,30 +220,36 @@
         # Checks that we see the newly created network/subnet/router via
         # checking the result of list_[networks,routers,subnets]
         # Check that (router, subnet) couple exist in port_list
-        seen_nets = self._list_networks()
-        seen_names = [n['name'] for n in seen_nets]
-        seen_ids = [n['id'] for n in seen_nets]
+        seen_nets = self.admin_manager.networks_client.list_networks()
+        seen_names = [n['name'] for n in seen_nets['networks']]
+        seen_ids = [n['id'] for n in seen_nets['networks']]
 
         self.assertIn(tenant.network['name'], seen_names)
         self.assertIn(tenant.network['id'], seen_ids)
 
-        seen_subnets = [(n['id'], n['cidr'], n['network_id'])
-                        for n in self._list_subnets()]
+        seen_subnets = [
+            (n['id'], n['cidr'], n['network_id']) for n in
+            self.admin_manager.subnets_client.list_subnets()['subnets']
+        ]
         mysubnet = (tenant.subnet['id'], tenant.subnet['cidr'],
                     tenant.network['id'])
         self.assertIn(mysubnet, seen_subnets)
 
-        seen_routers = self._list_routers()
-        seen_router_ids = [n['id'] for n in seen_routers]
-        seen_router_names = [n['name'] for n in seen_routers]
+        seen_routers = self.admin_manager.routers_client.list_routers()
+        seen_router_ids = [n['id'] for n in seen_routers['routers']]
+        seen_router_names = [n['name'] for n in seen_routers['routers']]
 
         self.assertIn(tenant.router['name'], seen_router_names)
         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.admin_manager.ports_client.list_ports(
+                device_id=tenant.router['id'])['ports']
+            if net_info.is_router_interface_port(i)
+            for f in i['fixed_ips']
+        ]
 
         self.assertIn(myport, router_ports)
 
@@ -262,7 +269,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:
@@ -362,20 +368,12 @@
             access_point_ssh, private_key=private_key)
         return access_point_ssh
 
-    def _check_connectivity(self, access_point, ip, should_succeed=True):
-        if should_succeed:
-            msg = "Timed out waiting for %s to become reachable" % ip
-        else:
-            msg = "%s is reachable" % ip
-        self.assertTrue(self._check_remote_connectivity(access_point, ip,
-                                                        should_succeed), msg)
-
     def _test_in_tenant_block(self, tenant):
         access_point_ssh = self._connect_to_access_point(tenant)
         for server in tenant.servers:
-            self._check_connectivity(access_point=access_point_ssh,
-                                     ip=self._get_server_ip(server),
-                                     should_succeed=False)
+            self.check_remote_connectivity(source=access_point_ssh,
+                                           dest=self._get_server_ip(server),
+                                           should_succeed=False)
 
     def _test_in_tenant_allow(self, tenant):
         ruleset = dict(
@@ -390,8 +388,8 @@
         )
         access_point_ssh = self._connect_to_access_point(tenant)
         for server in tenant.servers:
-            self._check_connectivity(access_point=access_point_ssh,
-                                     ip=self._get_server_ip(server))
+            self.check_remote_connectivity(source=access_point_ssh,
+                                           dest=self._get_server_ip(server))
 
     def _test_cross_tenant_block(self, source_tenant, dest_tenant):
         # if public router isn't defined, then dest_tenant access is via
@@ -399,8 +397,8 @@
         access_point_ssh = self._connect_to_access_point(source_tenant)
         ip = self._get_server_ip(dest_tenant.access_point,
                                  floating=self.floating_ip_access)
-        self._check_connectivity(access_point=access_point_ssh, ip=ip,
-                                 should_succeed=False)
+        self.check_remote_connectivity(source=access_point_ssh, dest=ip,
+                                       should_succeed=False)
 
     def _test_cross_tenant_allow(self, source_tenant, dest_tenant):
         """check for each direction:
@@ -421,7 +419,7 @@
         access_point_ssh = self._connect_to_access_point(source_tenant)
         ip = self._get_server_ip(dest_tenant.access_point,
                                  floating=self.floating_ip_access)
-        self._check_connectivity(access_point_ssh, ip)
+        self.check_remote_connectivity(access_point_ssh, ip)
 
         # test that reverse traffic is still blocked
         self._test_cross_tenant_block(dest_tenant, source_tenant)
@@ -438,7 +436,7 @@
         access_point_ssh_2 = self._connect_to_access_point(dest_tenant)
         ip = self._get_server_ip(source_tenant.access_point,
                                  floating=self.floating_ip_access)
-        self._check_connectivity(access_point_ssh_2, ip)
+        self.check_remote_connectivity(access_point_ssh_2, ip)
 
     def _verify_mac_addr(self, tenant):
         """Verify that VM has the same ip, mac as listed in port"""
@@ -448,7 +446,8 @@
         mac_addr = mac_addr.strip().lower()
         # Get the fixed_ips and mac_address fields of all ports. Select
         # only those two columns to reduce the size of the response.
-        port_list = self._list_ports(fields=['fixed_ips', 'mac_address'])
+        port_list = self.admin_manager.ports_client.list_ports(
+            fields=['fixed_ips', 'mac_address'])['ports']
         port_detail_list = [
             (port['fixed_ips'][0]['subnet_id'],
              port['fixed_ips'][0]['ip_address'],
@@ -459,7 +458,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 +479,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 +493,8 @@
                 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.attr(type='slow')
     @test.services('compute', 'network')
     def test_port_update_new_security_group(self):
         """Verifies the traffic after updating the vm port
@@ -530,24 +530,26 @@
         # Check connectivity failure with default security group
         try:
             access_point_ssh = self._connect_to_access_point(new_tenant)
-            self._check_connectivity(access_point=access_point_ssh,
-                                     ip=self._get_server_ip(server),
-                                     should_succeed=False)
+            self.check_remote_connectivity(source=access_point_ssh,
+                                           dest=self._get_server_ip(server),
+                                           should_succeed=False)
             server_id = server['id']
-            port_id = self._list_ports(device_id=server_id)[0]['id']
+            port_id = self.admin_manager.ports_client.list_ports(
+                device_id=server_id)['ports'][0]['id']
 
             # update port with new security group and check connectivity
             self.ports_client.update_port(port_id, security_groups=[
                 new_tenant.security_groups['new_sg']['id']])
-            self._check_connectivity(
-                access_point=access_point_ssh,
-                ip=self._get_server_ip(server))
+            self.check_remote_connectivity(
+                source=access_point_ssh,
+                dest=self._get_server_ip(server))
         except Exception:
             for tenant in self.tenants.values():
                 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.attr(type='slow')
     @test.services('compute', 'network')
     def test_multiple_security_groups(self):
         """Verify multiple security groups and checks that rules
@@ -579,8 +581,9 @@
                                    private_key=private_key,
                                    should_connect=True)
 
+    @test.attr(type='slow')
     @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."""
@@ -596,33 +599,32 @@
 
         access_point_ssh = self._connect_to_access_point(new_tenant)
         server_id = server['id']
-        port_id = self._list_ports(device_id=server_id)[0]['id']
+        port_id = self.admin_manager.ports_client.list_ports(
+            device_id=server_id)['ports'][0]['id']
 
         # Flip the port's port security and check connectivity
         try:
             self.ports_client.update_port(port_id,
                                           port_security_enabled=True,
                                           security_groups=[])
-            self._check_connectivity(access_point=access_point_ssh,
-                                     ip=self._get_server_ip(server),
-                                     should_succeed=False)
+            self.check_remote_connectivity(source=access_point_ssh,
+                                           dest=self._get_server_ip(server),
+                                           should_succeed=False)
 
             self.ports_client.update_port(port_id,
                                           port_security_enabled=False,
                                           security_groups=[])
-            self._check_connectivity(
-                access_point=access_point_ssh,
-                ip=self._get_server_ip(server))
+            self.check_remote_connectivity(
+                source=access_point_ssh,
+                dest=self._get_server_ip(server))
         except Exception:
             for tenant in self.tenants.values():
                 self._log_console_output(servers=tenant.servers)
             raise
 
+    @test.attr(type='slow')
     @test.requires_ext(service='network', extension='port-security')
-    @test.idempotent_id('13ccf253-e5ad-424b-9c4a-97b88a026699')
-    @testtools.skipUnless(
-        CONF.compute_feature_enabled.allow_port_security_disabled,
-        'Port security must be enabled.')
+    @decorators.idempotent_id('13ccf253-e5ad-424b-9c4a-97b88a026699')
     # TODO(mriedem): We shouldn't actually need to check this since neutron
     # disables the port_security extension by default, but the problem is nova
     # assumes port_security_enabled=True if it's not set on the network
@@ -640,7 +642,8 @@
         sec_groups = []
         server = self._create_server(name, tenant, sec_groups)
         server_id = server['id']
-        ports = self._list_ports(device_id=server_id)
+        ports = self.admin_manager.ports_client.list_ports(
+            device_id=server_id)['ports']
         self.assertEqual(1, len(ports))
         for port in ports:
             self.assertEmpty(port['security_groups'],
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index 504d72b..cc3687f 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
 
@@ -36,24 +37,23 @@
     """
 
     @classmethod
-    def skip_checks(cls):
-        super(TestServerAdvancedOps, cls).skip_checks()
-        if CONF.compute.flavor_ref_alt == CONF.compute.flavor_ref:
-            msg = "Skipping test - flavor_ref and flavor_ref_alt are identical"
-            raise cls.skipException(msg)
-
-    @classmethod
     def setup_credentials(cls):
         cls.set_network_resources()
         super(TestServerAdvancedOps, cls).setup_credentials()
 
-    @test.idempotent_id('e6c28180-7454-4b59-b188-0257af08a63b')
+    @test.attr(type='slow')
+    @decorators.idempotent_id('e6c28180-7454-4b59-b188-0257af08a63b')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize is not available.')
+    @testtools.skipUnless(CONF.compute.flavor_ref !=
+                          CONF.compute.flavor_ref_alt
+                          and CONF.compute.flavor_ref_alt != "",
+                          'The flavor_ref_alt option should not be empty and '
+                          'should not be identical with flavor_ref')
     @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,37 +68,22 @@
         waiters.wait_for_server_status(self.servers_client, instance_id,
                                        'ACTIVE')
 
-    @test.idempotent_id('949da7d5-72c8-4808-8802-e3d70df98e2c')
+    @test.attr(type='slow')
+    @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_id = instance['id']
-        LOG.debug("Suspending instance %s. Current status: %s",
-                  instance_id, instance['status'])
-        self.servers_client.suspend_server(instance_id)
-        waiters.wait_for_server_status(self.servers_client, instance_id,
-                                       'SUSPENDED')
-        fetched_instance = (self.servers_client.show_server(instance_id)
-                            ['server'])
-        LOG.debug("Resuming instance %s. Current status: %s",
-                  instance_id, fetched_instance['status'])
-        self.servers_client.resume_server(instance_id)
-        waiters.wait_for_server_status(self.servers_client, instance_id,
-                                       'ACTIVE')
-        fetched_instance = (self.servers_client.show_server(instance_id)
-                            ['server'])
-        LOG.debug("Suspending instance %s. Current status: %s",
-                  instance_id, fetched_instance['status'])
-        self.servers_client.suspend_server(instance_id)
-        waiters.wait_for_server_status(self.servers_client, instance_id,
-                                       'SUSPENDED')
-        fetched_instance = (self.servers_client.show_server(instance_id)
-                            ['server'])
-        LOG.debug("Resuming instance %s. Current status: %s",
-                  instance_id, fetched_instance['status'])
-        self.servers_client.resume_server(instance_id)
-        waiters.wait_for_server_status(self.servers_client, instance_id,
-                                       'ACTIVE')
+        instance_id = self.create_server()['id']
+
+        for _ in range(2):
+            LOG.debug("Suspending instance %s", instance_id)
+            self.servers_client.suspend_server(instance_id)
+            waiters.wait_for_server_status(self.servers_client, instance_id,
+                                           'SUSPENDED')
+
+            LOG.debug("Resuming instance %s", instance_id)
+            self.servers_client.resume_server(instance_id)
+            waiters.wait_for_server_status(self.servers_client, instance_id,
+                                           'ACTIVE')
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 2d2f7df..ddbaf5a 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -18,7 +18,9 @@
 
 from tempest.common import waiters
 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
@@ -43,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
 
@@ -79,6 +79,14 @@
                                                   'verify metadata on server. '
                                                   '%s is empty.' % md_url)
 
+            # Also, test a POST
+            md_url = 'http://169.254.169.254/openstack/2013-10-17/password'
+            data = data_utils.arbitrary_string(100)
+            cmd = 'curl -X POST -d ' + data + ' ' + md_url
+            self.ssh_client.exec_command(cmd)
+            result = self.servers_client.show_password(self.instance['id'])
+            self.assertEqual(data, result['password'])
+
     def _mount_config_drive(self):
         cmd_blkid = 'blkid | grep -i config-2'
         result = self.ssh_client.exec_command(cmd_blkid)
@@ -115,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):
@@ -123,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..9e763f8 100644
--- a/tempest/scenario/test_shelve_instance.py
+++ b/tempest/scenario/test_shelve_instance.py
@@ -13,9 +13,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 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 +57,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 +74,18 @@
                                         private_key=keypair['private_key'])
         self.assertEqual(timestamp, timestamp2)
 
-    @test.idempotent_id('1164e700-0af0-4a4c-8792-35909a88743c')
+    @test.attr(type='slow')
+    @decorators.idempotent_id('1164e700-0af0-4a4c-8792-35909a88743c')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     @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')
+    @test.attr(type='slow')
+    @decorators.idempotent_id('c1b6318c-b9da-490b-9c67-9339b627271f')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     @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..a699de2 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -13,7 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 from tempest import config
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -37,7 +40,10 @@
         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.attr(type='slow')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     @test.services('compute', 'network', 'image')
     def test_snapshot_pattern(self):
         # prepare for booting an instance
@@ -46,10 +52,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 +66,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..5f5d701 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -13,14 +13,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import time
-
 from oslo_log import log as logging
 import testtools
 
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 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 as lib_exc
@@ -63,21 +61,14 @@
         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)
-        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'])
+        self.addCleanup(self.snapshots_client.wait_for_resource_deletion,
+                        snapshot['id'])
+        self.addCleanup(self.snapshots_client.delete_snapshot, snapshot['id'])
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'available')
+        waiters.wait_for_volume_resource_status(self.snapshots_client,
+                                                snapshot['id'], 'available')
+        self.assertEqual(snapshot_name, snapshot['name'])
         return snapshot
 
     def _wait_for_volume_available_on_the_system(self, ip_address,
@@ -94,10 +85,13 @@
                                           CONF.compute.build_interval):
             raise lib_exc.TimeoutException
 
-    @decorators.skip_because(bug="1205344")
-    @test.idempotent_id('10fd234a-515c-41e5-b092-8323060598c5')
+    @test.attr(type='slow')
+    @decorators.skip_because(bug="1664793")
+    @decorators.idempotent_id('10fd234a-515c-41e5-b092-8323060598c5')
     @testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
                           'Snapshotting is not available.')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     @test.services('compute', 'network', 'volume', 'image')
     def test_stamp_pattern(self):
         # prepare for booting an instance
@@ -107,10 +101,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 +129,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..888bff2 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -11,10 +11,12 @@
 #    under the License.
 
 from oslo_log import log as logging
+import testtools
 
-from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
 from tempest.scenario import manager
 from tempest import test
 
@@ -40,20 +42,20 @@
             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):
-        # 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,
-            'delete_on_termination': str(int(delete_on_termination))}]
-        return {'block_device_mapping': bd_map}
+    def _get_bdm(self, source_id, source_type, delete_on_termination=False):
+        bd_map_v2 = [{
+            'uuid': source_id,
+            'source_type': source_type,
+            'destination_type': 'volume',
+            'boot_index': 0,
+            'delete_on_termination': delete_on_termination}]
+        return {'block_device_mapping_v2': bd_map_v2}
 
-    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 +63,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(
@@ -77,23 +79,18 @@
         self.addCleanup(
             self.snapshots_client.wait_for_resource_deletion, snap['id'])
         self.addCleanup(self.snapshots_client.delete_snapshot, snap['id'])
-        waiters.wait_for_snapshot_status(self.snapshots_client,
-                                         snap['id'], 'available')
-
-        # NOTE(e0ne): Cinder API v2 uses name instead of display_name
-        if 'display_name' in snap:
-            self.assertEqual(snap_name, snap['display_name'])
-        else:
-            self.assertEqual(snap_name, snap['name'])
-
+        waiters.wait_for_volume_resource_status(self.snapshots_client,
+                                                snap['id'], 'available')
+        self.assertEqual(snap_name, snap['name'])
         return snap
 
     def _delete_server(self, server):
         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')
-    @test.attr(type='smoke')
+    @decorators.idempotent_id('557cd2c2-4eb8-4dce-98be-f86765ff311b')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
     @test.services('compute', 'volume', 'image')
     def test_volume_boot_pattern(self):
 
@@ -116,8 +113,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 +131,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 +155,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 +169,52 @@
                                         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.attr(type='slow')
+    @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,20 +222,8 @@
         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
         self._delete_server(instance)
-
-
-class TestVolumeBootPatternV2(TestVolumeBootPattern):
-    def _get_bdm(self, vol_id, delete_on_termination=False):
-        bd_map_v2 = [{
-            'uuid': vol_id,
-            'source_type': 'volume',
-            'destination_type': 'volume',
-            'boot_index': 0,
-            'delete_on_termination': delete_on_termination}]
-        return {'block_device_mapping_v2': bd_map_v2}
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
new file mode 100644
index 0000000..f04947c
--- /dev/null
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -0,0 +1,127 @@
+#    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 oslo_log import log as logging
+
+from tempest.common import waiters
+from tempest import config
+from tempest.lib import decorators
+from tempest.scenario import manager
+from tempest import test
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+class TestVolumeMigrateRetypeAttached(manager.ScenarioTest):
+
+    """This test case attempts to reproduce the following steps:
+
+     * Create 2 volume types representing 2 different backends
+     * Create in Cinder some bootable volume importing a Glance image using
+     *   volume_type_1
+     * Boot an instance from the bootable volume
+     * Write to the volume
+     * Perform a cinder retype --on-demand of the volume to type of backend #2
+     * Check written content of migrated volume
+    """
+
+    credentials = ['primary', 'admin']
+
+    @classmethod
+    def setup_clients(cls):
+        super(TestVolumeMigrateRetypeAttached, cls).setup_clients()
+        cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
+
+    @classmethod
+    def skip_checks(cls):
+        super(TestVolumeMigrateRetypeAttached, cls).skip_checks()
+        if not CONF.volume_feature_enabled.multi_backend:
+            raise cls.skipException("Cinder multi-backend feature disabled")
+
+        if len(set(CONF.volume.backend_names)) < 2:
+            raise cls.skipException("Requires at least two different "
+                                    "backend names")
+
+    def _boot_instance_from_volume(self, vol_id, keypair, security_group):
+
+        key_name = keypair['name']
+        security_groups = [{'name': security_group['name']}]
+        block_device_mapping = [{'device_name': 'vda', 'volume_id': vol_id,
+                                 'delete_on_termination': False}]
+
+        return self.create_server(image_id='',
+                                  key_name=key_name,
+                                  security_groups=security_groups,
+                                  block_device_mapping=block_device_mapping)
+
+    def _create_volume_types(self):
+        backend_names = CONF.volume.backend_names
+
+        backend_source = backend_names[0]
+        backend_dest = backend_names[1]
+
+        source_body = self.create_volume_type(backend_name=backend_source)
+        dest_body = self.create_volume_type(backend_name=backend_dest)
+
+        LOG.info("Created Volume types: %(src)s -> %(src_backend)s, %(dst)s "
+                 "-> %(dst_backend)s", {'src': source_body['name'],
+                                        'src_backend': backend_source,
+                                        'dst': dest_body['name'],
+                                        'dst_backend': backend_dest})
+        return source_body['name'], dest_body['name']
+
+    def _volume_retype_with_migration(self, volume_id, new_volume_type):
+        migration_policy = 'on-demand'
+        self.volumes_client.retype_volume(
+            volume_id, new_type=new_volume_type,
+            migration_policy=migration_policy)
+        waiters.wait_for_volume_retype(self.volumes_client,
+                                       volume_id, new_volume_type)
+
+    @test.attr(type='slow')
+    @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")
+        keypair = self.create_keypair()
+        security_group = self._create_security_group()
+
+        # create volume types
+        LOG.info("Creating Volume types")
+        source_type, dest_type = self._create_volume_types()
+
+        # create an instance from volume
+        LOG.info("Booting instance from volume")
+        volume_origin = self.create_volume(imageRef=CONF.compute.image_ref,
+                                           volume_type=source_type)
+
+        instance = self._boot_instance_from_volume(volume_origin['id'],
+                                                   keypair, security_group)
+
+        # write content to volume on instance
+        LOG.info("Setting timestamp in instance %s", instance['id'])
+        ip_instance = self.get_server_ip(instance)
+        timestamp = self.create_timestamp(ip_instance,
+                                          private_key=keypair['private_key'])
+
+        # retype volume with migration from backend #1 to backend #2
+        LOG.info("Retyping Volume %s to new type %s", volume_origin['id'],
+                 dest_type)
+        self._volume_retype_with_migration(volume_origin['id'], dest_type)
+
+        # check the content of written file
+        LOG.info("Getting timestamp in postmigrated instance %s",
+                 instance['id'])
+        timestamp2 = self.get_timestamp(ip_instance,
+                                        private_key=keypair['private_key'])
+        self.assertEqual(timestamp, timestamp2)
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index 9932b4a..4859e75 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -128,6 +128,13 @@
             than the specified marker.
             DEFAULT: No Marker
 
+        prefix=[string value Y]
+            Given string value Y, return object names starting with that prefix
+
+        reverse=[boolean value Z]
+            Reverse the result order based on the boolean value Z
+            DEFAULT: False
+
         format=[string value, either 'json' or 'xml']
             Specify either json or xml to return the respective serialized
             response.
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index 2509156..afedd36 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -140,5 +140,11 @@
             body = json.loads(body)
         elif params and params.get('format') == 'xml':
             body = etree.fromstring(body)
+        # Else the content-type is plain/text
+        else:
+            body = [
+                obj_name for obj_name in body.decode().split('\n') if obj_name
+            ]
+
         self.expected_success([200, 204], resp.status)
         return resp, body
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 9445e34..6d656ec 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -13,7 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import six
 from six.moves import http_client as httplib
 from six.moves.urllib import parse as urlparse
 
@@ -189,7 +188,7 @@
         # Send the PUT request and the headers including the "Expect" header
         conn.putrequest('PUT', path)
 
-        for header, value in six.iteritems(headers):
+        for header, value in headers.items():
             conn.putheader(header, value)
         conn.endheaders()
 
diff --git a/tempest/test.py b/tempest/test.py
index 17dc94c..52994ac 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -31,7 +31,6 @@
 from tempest import config
 from tempest import exceptions
 from tempest.lib.common import cred_client
-from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 
@@ -39,7 +38,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):
@@ -219,7 +222,6 @@
     """
 
     setUpClassCalled = False
-    _service = None
 
     # NOTE(andreaf) credentials holds a list of the credentials to be allocated
     # at class setup time. Credential types can be 'primary', 'alt', 'admin' or
@@ -533,8 +535,7 @@
             else:
                 raise lib_exc.InvalidCredentials(
                     "Invalid credentials type %s" % credential_type)
-        manager = cls.client_manager(credentials=creds.credentials,
-                                     service=cls._service)
+        manager = cls.client_manager(credentials=creds.credentials)
         # NOTE(andreaf) Ensure credentials have user and project id fields.
         # It may not be the case when using pre-provisioned credentials.
         manager.auth_provider.set_auth()
@@ -642,12 +643,11 @@
             cred_provider, networks_client, CONF.compute.fixed_network_name)
 
     def assertEmpty(self, list, msg=None):
+        if msg is None:
+            msg = "list is not empty: %s" % list
         self.assertEqual(0, len(list), msg)
 
     def assertNotEmpty(self, list, msg=None):
+        if msg is None:
+            msg = "list is empty."
         self.assertGreater(len(list), 0, msg)
-
-
-call_until_true = debtcollector.moves.moved_function(
-    test_utils.call_until_true, 'call_until_true', __name__,
-    version='Newton', removal_version='Ocata')
diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py
index e9f59af..613ab92 100644
--- a/tempest/test_discover/plugins.py
+++ b/tempest/test_discover/plugins.py
@@ -13,8 +13,8 @@
 # under the License.
 
 import abc
-import logging
 
+from oslo_log import log as logging
 import six
 import stevedore
 
@@ -46,10 +46,41 @@
         """Add additional configuration options to tempest.
 
         This method will be run for the plugin during the register_opts()
-        function in tempest.config
+        function in tempest.config.
 
         :param ConfigOpts conf: The conf object that can be used to register
             additional options on.
+
+        Example:
+            >>> # Config options are defined in a config.py module
+            >>> service_option = cfg.BoolOpt(
+            >>>     "my_service",
+            >>>     default=True,
+            >>>     help="Whether or not my service is available")
+            >>>
+            >>> # Note: as long as the group is listed in get_opt_lists,
+            >>> # it will be possible to access its optins in the plugin code
+            >>> # via ("-" in the group name are replaces with "_"):
+            >>> #     CONF.my_service.<option_name>
+            >>> my_service_group = cfg.OptGroup(name="my-service",
+            >>>                                 title="My service options")
+            >>>
+            >>> MyServiceGroup = [<list of options>]
+            >>> # (...) More groups and options...
+            >>>
+            >>> # Plugin is implemented in a plugin.py module
+            >>> from my_plugin import config as my_config
+            >>>
+            >>> def register_opts(self, conf):
+            >>>    conf.register_opt(my_config.service_option,
+            >>>                      group='service_available')
+            >>>    conf.register_group(my_config.my_service_group)
+            >>>    conf.register_opts(my_config.MyService +
+            >>>                       my_config.my_service_group)
+            >>>
+            >>>    conf.register_group(my_config.my_service_feature_group)
+            >>>    conf.register_opts(my_config.MyServiceFeaturesGroup,
+            >>>                       my_config.my_service_feature_group)
         """
         return
 
@@ -71,11 +102,10 @@
         in any ServiceClients object instantiated by tests.
         The default implementation returns an empty list.
 
-        :return list of dictionaries. Each element of the list represents
-            the service client for an API. Each dict must define all
-            parameters required for the invocation of
-            `service_clients.ServiceClients.register_service_client_module`.
-        :rtype: list
+        :returns: Each element of the list represents the service client for an
+          API. Each dict must define all parameters required for the invocation
+          of `service_clients.ServiceClients.register_service_client_module`.
+        :rtype: list of dictionaries
 
         Example:
 
@@ -124,7 +154,6 @@
             'tempest.test_plugins', invoke_on_load=True,
             propagate_map_exceptions=True,
             on_load_failure_callback=self.failure_hook)
-        self._register_service_clients()
 
     @staticmethod
     def failure_hook(_, ep, err):
diff --git a/tempest/tests/negative/__init__.py b/tempest/tests/api/__init__.py
similarity index 100%
rename from tempest/tests/negative/__init__.py
rename to tempest/tests/api/__init__.py
diff --git a/tempest/tests/negative/__init__.py b/tempest/tests/api/compute/__init__.py
similarity index 100%
copy from tempest/tests/negative/__init__.py
copy to 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..6345728
--- /dev/null
+++ b/tempest/tests/api/compute/test_base.py
@@ -0,0 +1,173 @@
+# 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,
+                         servers_client=mock.DEFAULT,
+                         images=[], create=True)
+    @mock.patch.object(waiters, 'wait_for_image_status')
+    @mock.patch.object(waiters, 'wait_for_server_status')
+    def test_create_image_from_server_wait_until_active(self,
+                                                        wait_for_server_status,
+                                                        wait_for_image_status,
+                                                        servers_client,
+                                                        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')
+        wait_for_server_status.assert_called_once_with(
+            servers_client, mock.sentinel.server_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')
+    @mock.patch.object(waiters, 'wait_for_server_status')
+    def test_create_image_from_server_wait_until_active_no_server_wait(
+            self, wait_for_server_status, wait_for_image_status,
+            servers_client, 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',
+            wait_for_server=False)
+        self.assertEqual(fake_image, image)
+        # make our assertions
+        wait_for_image_status.assert_called_once_with(
+            compute_images_client, image_id, 'ACTIVE')
+        self.assertEqual(0, wait_for_server_status.call_count)
+        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/cmd/test_subunit_describe_calls.py b/tempest/tests/cmd/test_subunit_describe_calls.py
index 1c24c37..5f3d770 100644
--- a/tempest/tests/cmd/test_subunit_describe_calls.py
+++ b/tempest/tests/cmd/test_subunit_describe_calls.py
@@ -33,6 +33,16 @@
         p.communicate()
         self.assertEqual(0, p.returncode)
 
+    def test_return_code_no_output(self):
+        subunit_file = os.path.join(
+            os.path.dirname(os.path.abspath(__file__)),
+            'sample_streams/calls.subunit')
+        p = subprocess.Popen([
+            'subunit-describe-calls', '-s', subunit_file],
+            stdin=subprocess.PIPE)
+        p.communicate()
+        self.assertEqual(0, p.returncode)
+
     def test_parse(self):
         subunit_file = os.path.join(
             os.path.dirname(os.path.abspath(__file__)),
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 1af0d95..98bf145 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -192,7 +192,7 @@
         self.useFixture(mockpatch.PatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
-        fake_resp = {'versions': [{'id': 'v1.0'}, {'id': 'v2.0'}]}
+        fake_resp = {'versions': [{'id': 'v2.0'}]}
         fake_resp = json.dumps(fake_resp)
         mock_request.return_value = (None, fake_resp)
         fake_os = mock.MagicMock()
@@ -206,7 +206,7 @@
         self.useFixture(mockpatch.PatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
-        fake_resp = {'versions': [{'id': 'v1.0'}, {'id': 'v3.0'}]}
+        fake_resp = {'versions': [{'id': 'v3.0'}]}
         fake_resp = json.dumps(fake_resp)
         mock_request.return_value = (None, fake_resp)
         fake_os = mock.MagicMock()
@@ -231,11 +231,9 @@
         with mock.patch.object(verify_tempest_config,
                                'print_and_or_update') as print_mock:
             verify_tempest_config.verify_cinder_api_versions(fake_os, True)
-        print_mock.assert_any_call('api_v1', 'volume-feature-enabled',
-                                   False, True)
         print_mock.assert_any_call('api_v3', 'volume-feature-enabled',
                                    True, True)
-        self.assertEqual(2, print_mock.call_count)
+        self.assertEqual(1, print_mock.call_count)
 
     def test_verify_glance_version_no_v2_with_v1_1(self):
         def fake_get_versions():
diff --git a/tempest/tests/common/test_preprov_creds.py b/tempest/tests/common/test_preprov_creds.py
index f824b6c..2fd375d 100644
--- a/tempest/tests/common/test_preprov_creds.py
+++ b/tempest/tests/common/test_preprov_creds.py
@@ -14,14 +14,15 @@
 
 import hashlib
 import os
-import testtools
+import shutil
 
 import mock
+import six
+import testtools
+
 from oslo_concurrency.fixture import lockutils as lockutils_fixtures
 from oslo_config import cfg
 from oslotest import mockpatch
-import shutil
-import six
 
 from tempest.common import preprov_creds
 from tempest import config
@@ -101,7 +102,7 @@
             preprov_creds.PreProvisionedCredentialProvider.HASH_CRED_FIELDS)
         for account in accounts_list:
             hash = hashlib.md5()
-            account_for_hash = dict((k, v) for (k, v) in six.iteritems(account)
+            account_for_hash = dict((k, v) for (k, v) in account.items()
                                     if k in hash_fields)
             hash.update(six.text_type(account_for_hash).encode('utf-8'))
             temp_hash = hash.hexdigest()
diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py
index 46f9526..c2f622c 100644
--- a/tempest/tests/common/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -66,7 +66,7 @@
         client.show_volume = mock_show
         volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa'
         self.assertRaises(exceptions.VolumeRestoreErrorException,
-                          waiters.wait_for_volume_status,
+                          waiters.wait_for_volume_resource_status,
                           client, volume_id, 'available')
         mock_show.assert_has_calls([mock.call(volume_id),
                                     mock.call(volume_id)])
diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
index e4f4c04..ecb8e64 100644
--- a/tempest/tests/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -12,9 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import fixtures
 import time
 
+import fixtures
 from oslo_config import cfg
 from oslotest import mockpatch
 
@@ -67,16 +67,6 @@
         self.ssh_mock = self.useFixture(mockpatch.PatchObject(self.conn,
                                                               'ssh_client'))
 
-    def test_get_hostname(self):
-        self.ssh_mock.mock.exec_command.return_value = 'fake_hostname'
-        self.assertEqual(self.conn.get_hostname(), 'fake_hostname')
-
-    def test_get_ram_size(self):
-        free_output = "Mem:         48294      45738       2555          0" \
-                      "402      40346"
-        self.ssh_mock.mock.exec_command.return_value = free_output
-        self.assertEqual(self.conn.get_ram_size_in_mb(), '48294')
-
     def test_write_to_console_regular_str(self):
         self.conn.write_to_console('test')
         self._assert_exec_called_with(
@@ -102,11 +92,6 @@
         cmd = "set -eu -o pipefail; PATH=$PATH:/sbin; " + cmd
         self.ssh_mock.mock.exec_command.assert_called_with(cmd)
 
-    def test_get_number_of_vcpus(self):
-        self.ssh_mock.mock.exec_command.return_value = '16'
-        self.assertEqual(self.conn.get_number_of_vcpus(), 16)
-        self._assert_exec_called_with('grep -c ^processor /proc/cpuinfo')
-
     def test_get_disks(self):
         output_lsblk = """\
 NAME       MAJ:MIN    RM          SIZE RO TYPE MOUNTPOINT
@@ -154,40 +139,6 @@
         self._assert_exec_called_with(
             "ip addr | awk '/ether/ {print $2}'")
 
-    def test_get_ip_list(self):
-        ips = """1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue
-    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
-    inet 127.0.0.1/8 scope host lo
-    inet6 ::1/128 scope host
-       valid_lft forever preferred_lft forever
-2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
-    link/ether fa:16:3e:6e:26:3b brd ff:ff:ff:ff:ff:ff
-    inet 10.0.0.4/24 brd 10.0.0.255 scope global eth0
-    inet6 fd55:faaf:e1ab:3d9:f816:3eff:fe6e:263b/64 scope global dynamic
-       valid_lft 2591936sec preferred_lft 604736sec
-    inet6 fe80::f816:3eff:fe6e:263b/64 scope link
-       valid_lft forever preferred_lft forever"""
-        self.ssh_mock.mock.exec_command.return_value = ips
-        self.assertEqual(self.conn.get_ip_list(), ips)
-        self._assert_exec_called_with('ip address')
-
-    def test_assign_static_ip(self):
-        self.ssh_mock.mock.exec_command.return_value = ''
-        ip = '10.0.0.2'
-        nic = 'eth0'
-        self.assertEqual(self.conn.assign_static_ip(nic, ip), '')
-        self._assert_exec_called_with(
-            "sudo ip addr add %s/%s dev %s" % (ip, '28', nic))
-
-    def test_set_nic_state(self):
-        nic = 'eth0'
-        self.conn.set_nic_state(nic)
-        self._assert_exec_called_with(
-            'sudo ip link set %s up' % nic)
-        self.conn.set_nic_state(nic, "down")
-        self._assert_exec_called_with(
-            'sudo ip link set %s down' % nic)
-
 
 class TestRemoteClientWithServer(base.TestCase):
 
@@ -214,7 +165,7 @@
                                            user='user',
                                            password='pass')))
         self.log = self.useFixture(fixtures.FakeLogger(
-            name='tempest.common.utils.linux.remote_client',
+            name='tempest.lib.common.utils.linux.remote_client',
             level='DEBUG'))
 
     def test_validate_debug_ssh_console(self):
diff --git a/tempest/tests/lib/cli/test_execute.py b/tempest/tests/lib/cli/test_execute.py
index aaeb6f4..0130454 100644
--- a/tempest/tests/lib/cli/test_execute.py
+++ b/tempest/tests/lib/cli/test_execute.py
@@ -11,9 +11,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
 import subprocess
 
+import mock
+
 from tempest.lib.cli import base as cli_base
 from tempest.lib import exceptions
 from tempest.tests import base
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/negative/__init__.py b/tempest/tests/lib/common/utils/linux/__init__.py
similarity index 100%
copy from tempest/tests/negative/__init__.py
copy to tempest/tests/lib/common/utils/linux/__init__.py
diff --git a/tempest/tests/lib/common/utils/linux/test_remote_client.py b/tempest/tests/lib/common/utils/linux/test_remote_client.py
new file mode 100644
index 0000000..cf312f4
--- /dev/null
+++ b/tempest/tests/lib/common/utils/linux/test_remote_client.py
@@ -0,0 +1,67 @@
+# Copyright 2017 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 mock
+
+from tempest.lib.common import ssh
+from tempest.lib.common.utils.linux import remote_client
+from tempest.lib import exceptions as lib_exc
+from tempest.tests import base
+
+
+class FakeServersClient(object):
+
+    def get_console_output(self, server_id):
+        return {"output": "fake_output"}
+
+
+class TestRemoteClient(base.TestCase):
+
+    @mock.patch.object(ssh.Client, 'exec_command', return_value='success')
+    def test_exec_command(self, mock_ssh_exec_command):
+        client = remote_client.RemoteClient('192.168.1.10', 'username')
+        client.exec_command('ls')
+        mock_ssh_exec_command.assert_called_once_with(
+            'set -eu -o pipefail; PATH=$$PATH:/sbin; ls')
+
+    @mock.patch.object(ssh.Client, 'test_connection_auth')
+    def test_validate_authentication(self, mock_test_connection_auth):
+        client = remote_client.RemoteClient('192.168.1.10', 'username')
+        client.validate_authentication()
+        mock_test_connection_auth.assert_called_once_with()
+
+    @mock.patch.object(remote_client.LOG, 'debug')
+    @mock.patch.object(ssh.Client, 'exec_command')
+    def test_debug_ssh_without_console(self, mock_exec_command, mock_debug):
+        mock_exec_command.side_effect = lib_exc.SSHTimeout
+        server = {'id': 'fake_id'}
+        client = remote_client.RemoteClient('192.168.1.10', 'username',
+                                            server=server)
+        self.assertRaises(lib_exc.SSHTimeout, client.exec_command, 'ls')
+        mock_debug.assert_called_with(
+            'Caller: %s. Timeout trying to ssh to server %s',
+            'TestRemoteClient:test_debug_ssh_without_console', server)
+
+    @mock.patch.object(remote_client.LOG, 'debug')
+    @mock.patch.object(ssh.Client, 'exec_command')
+    def test_debug_ssh_with_console(self, mock_exec_command, mock_debug):
+        mock_exec_command.side_effect = lib_exc.SSHTimeout
+        server = {'id': 'fake_id'}
+        client = remote_client.RemoteClient('192.168.1.10', 'username',
+                                            server=server,
+                                            servers_client=FakeServersClient())
+        self.assertRaises(lib_exc.SSHTimeout, client.exec_command, 'ls')
+        mock_debug.assert_called_with(
+            'Console log for server %s: %s', server['id'], 'fake_output')
diff --git a/tempest/tests/lib/common/utils/test_data_utils.py b/tempest/tests/lib/common/utils/test_data_utils.py
index 4446e5c..8bdf70e 100644
--- a/tempest/tests/lib/common/utils/test_data_utils.py
+++ b/tempest/tests/lib/common/utils/test_data_utils.py
@@ -37,16 +37,20 @@
         actual2 = data_utils.rand_uuid_hex()
         self.assertNotEqual(actual, actual2)
 
-    def test_rand_name(self):
-        actual = data_utils.rand_name()
+    def test_rand_name_with_default_prefix(self):
+        actual = data_utils.rand_name('foo')
         self.assertIsInstance(actual, str)
-        actual2 = data_utils.rand_name()
+        self.assertTrue(actual.startswith('tempest-foo'))
+        actual2 = data_utils.rand_name('foo')
+        self.assertTrue(actual2.startswith('tempest-foo'))
         self.assertNotEqual(actual, actual2)
 
-        actual = data_utils.rand_name('foo')
+    def test_rand_name_with_none_prefix(self):
+        actual = data_utils.rand_name('foo', prefix=None)
+        self.assertIsInstance(actual, str)
         self.assertTrue(actual.startswith('foo'))
-        actual2 = data_utils.rand_name('foo')
-        self.assertTrue(actual.startswith('foo'))
+        actual2 = data_utils.rand_name('foo', prefix=None)
+        self.assertTrue(actual2.startswith('foo'))
         self.assertNotEqual(actual, actual2)
 
     def test_rand_name_with_prefix(self):
diff --git a/tempest/tests/lib/services/compute/test_quotas_client.py b/tempest/tests/lib/services/compute/test_quotas_client.py
index 4c49e8d..bbb8eb7 100644
--- a/tempest/tests/lib/services/compute/test_quotas_client.py
+++ b/tempest/tests/lib/services/compute/test_quotas_client.py
@@ -49,22 +49,35 @@
         self.client = quotas_client.QuotasClient(
             fake_auth, 'compute', 'regionOne')
 
-    def _test_show_quota_set(self, bytes_body=False, user_id=None):
+    def _get_quota_set(self, detail):
+        if not detail:
+            return self.FAKE_QUOTA_SET
+        fake_quota_set = {"quota_set": {}}
+        for key, val in self.FAKE_QUOTA_SET['quota_set'].items():
+            fake_quota_set['quota_set'][key] = \
+                {'limit': val, 'reserved': 0, 'in_use': 0}
+        fake_quota_set['quota_set']['id'] = "8421f7be61064f50b680465c07f334af"
+        return fake_quota_set
+
+    def _test_show_quota_set(self, bytes_body=False, detail=False,
+                             user_id=None):
         if user_id:
             self.check_service_client_function(
                 self.client.show_quota_set,
                 'tempest.lib.common.rest_client.RestClient.get',
-                self.FAKE_QUOTA_SET,
+                self._get_quota_set(detail),
                 to_utf=bytes_body,
                 tenant_id=self.project_id,
+                detail=detail,
                 user_id=user_id)
         else:
             self.check_service_client_function(
                 self.client.show_quota_set,
                 'tempest.lib.common.rest_client.RestClient.get',
-                self.FAKE_QUOTA_SET,
+                self._get_quota_set(detail),
                 to_utf=bytes_body,
-                tenant_id=self.project_id)
+                tenant_id=self.project_id,
+                detail=detail)
 
     def test_show_quota_set_with_str_body(self):
         self._test_show_quota_set()
@@ -78,6 +91,9 @@
     def test_show_quota_set_for_user_with_bytes_body(self):
         self._test_show_quota_set(bytes_body=True, user_id=self.fake_user_id)
 
+    def test_show_quota_set_with_details(self):
+        self._test_show_quota_set(detail=True)
+
     def _test_show_default_quota_set(self, bytes_body=False):
         self.check_service_client_function(
             self.client.show_default_quota_set,
diff --git a/tempest/tests/lib/services/compute/test_servers_client.py b/tempest/tests/lib/services/compute/test_servers_client.py
index 93550fd..a277dfe 100644
--- a/tempest/tests/lib/services/compute/test_servers_client.py
+++ b/tempest/tests/lib/services/compute/test_servers_client.py
@@ -1,4 +1,5 @@
 # Copyright 2015 IBM Corp.
+# Copyright 2017 AT&T 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
@@ -14,6 +15,9 @@
 
 import copy
 
+import mock
+
+from tempest.lib.services.compute import base_compute_client
 from tempest.lib.services.compute import servers_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
@@ -154,7 +158,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"
     }
@@ -164,20 +168,35 @@
         "url": "http://os.co/v2/616fb98f-46ca-475e-917e-2563e5a8cd19"
     }
 
+    FAKE_SERVER_PASSWORD = {
+        "adminPass": "fake-password",
+    }
+
     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"
     }
 
+    FAKE_SECURITY_GROUPS = [{
+        "description": "default",
+        "id": "3fb26eb3-581b-4420-9963-b0879a026506",
+        "name": "default",
+        "rules": [],
+        "tenant_id": "openstack"
+    }]
+
     FAKE_INSTANCE_WITH_EVENTS = copy.deepcopy(FAKE_INSTANCE_ACTIONS)
     FAKE_INSTANCE_WITH_EVENTS['events'] = [FAKE_INSTANCE_ACTION_EVENTS]
 
     FAKE_REBUILD_SERVER = copy.deepcopy(FAKE_SERVER_GET)
     FAKE_REBUILD_SERVER['server']['adminPass'] = 'fake-admin-pass'
 
+    FAKE_TAGS = ["foo", "bar"]
+    REPLACE_FAKE_TAGS = ["baz", "qux"]
+
     server_id = FAKE_SERVER_GET['server']['id']
     network_id = 'a6b0875b-6b5d-4a5a-81eb-0c3aa62e5fdb'
 
@@ -186,6 +205,7 @@
         fake_auth = fake_auth_provider.FakeAuthProvider()
         self.client = servers_client.ServersClient(
             fake_auth, 'compute', 'regionOne')
+        self.addCleanup(mock.patch.stopall)
 
     def test_list_servers_with_str_body(self):
         self._test_list_servers()
@@ -306,6 +326,21 @@
             name='fake-name'
             )
 
+    def test_evacuate_server_with_str_body(self):
+        self._test_evacuate_server()
+
+    def test_evacuate_server_with_bytes_body(self):
+        self._test_evacuate_server(bytes_body=True)
+
+    def _test_evacuate_server(self, bytes_body=False):
+        kwargs = {'server_id': self.server_id,
+                  'host': 'fake-target-host'}
+        self.check_service_client_function(
+            self.client.evacuate_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_SERVER_PASSWORD,
+            **kwargs)
+
     def test_change_password_with_str_body(self):
         self._test_change_password()
 
@@ -1009,3 +1044,127 @@
             server_id=self.server_id,
             type='fake-console-type'
             )
+
+    def test_list_security_groups_by_server_with_str_body(self):
+        self._test_list_security_groups_by_server()
+
+    def test_list_security_groups_by_server_with_bytes_body(self):
+        self._test_list_security_groups_by_server(True)
+
+    def _test_list_security_groups_by_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_security_groups_by_server,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {'security_groups': self.FAKE_SECURITY_GROUPS},
+            server_id=self.server_id,
+            )
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.26'))
+    def test_list_tags_str_body(self, _):
+        self._test_list_tags()
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.26'))
+    def test_list_tags_byte_body(self, _):
+        self._test_list_tags(bytes_body=True)
+
+    def _test_list_tags(self, bytes_body=False):
+        expected = {"tags": self.FAKE_TAGS}
+        self.check_service_client_function(
+            self.client.list_tags,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected,
+            server_id=self.server_id,
+            to_utf=bytes_body)
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.26'))
+    def test_update_all_tags_str_body(self, _):
+        self._test_update_all_tags()
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.26'))
+    def test_update_all_tags_byte_body(self, _):
+        self._test_update_all_tags(bytes_body=True)
+
+    def _test_update_all_tags(self, bytes_body=False):
+        expected = {"tags": self.REPLACE_FAKE_TAGS}
+        self.check_service_client_function(
+            self.client.update_all_tags,
+            'tempest.lib.common.rest_client.RestClient.put',
+            expected,
+            server_id=self.server_id,
+            tags=self.REPLACE_FAKE_TAGS,
+            to_utf=bytes_body)
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.26'))
+    def test_delete_all_tags(self, _):
+        self.check_service_client_function(
+            self.client.delete_all_tags,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            server_id=self.server_id,
+            status=204)
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.26'))
+    def test_check_tag_existence_str_body(self, _):
+        self._test_check_tag_existence()
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.26'))
+    def test_check_tag_existence_byte_body(self, _):
+        self._test_check_tag_existence(bytes_body=True)
+
+    def _test_check_tag_existence(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.check_tag_existence,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {},
+            server_id=self.server_id,
+            tag=self.FAKE_TAGS[0],
+            status=204,
+            to_utf=bytes_body)
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.26'))
+    def test_update_tag_str_body(self, _):
+        self._test_update_tag()
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.26'))
+    def test_update_tag_byte_body(self, _):
+        self._test_update_tag(bytes_body=True)
+
+    def _test_update_tag(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_tag,
+            'tempest.lib.common.rest_client.RestClient.put',
+            {},
+            server_id=self.server_id,
+            tag=self.FAKE_TAGS[0],
+            status=201,
+            headers={'location': 'fake_location'},
+            to_utf=bytes_body)
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.26'))
+    def test_delete_tag_str_body(self, _):
+        self._test_delete_tag()
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.26'))
+    def test_delete_tag_byte_body(self, _):
+        self._test_delete_tag(bytes_body=True)
+
+    def _test_delete_tag(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.delete_tag,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            server_id=self.server_id,
+            tag=self.FAKE_TAGS[0],
+            status=204,
+            to_utf=bytes_body)
diff --git a/tempest/tests/lib/services/compute/test_versions_client.py b/tempest/tests/lib/services/compute/test_versions_client.py
index 06ecdc3..255a0a3 100644
--- a/tempest/tests/lib/services/compute/test_versions_client.py
+++ b/tempest/tests/lib/services/compute/test_versions_client.py
@@ -13,6 +13,7 @@
 #    under the License.
 
 import copy
+
 from oslotest import mockpatch
 
 from tempest.lib.services.compute import versions_client
diff --git a/tempest/tests/lib/services/identity/v3/test_identity_client.py b/tempest/tests/lib/services/identity/v3/test_identity_client.py
index 9eaaaaf..e435fe2 100644
--- a/tempest/tests/lib/services/identity/v3/test_identity_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_identity_client.py
@@ -32,6 +32,34 @@
         "description": "test_description"
     }
 
+    FAKE_AUTH_PROJECTS = {
+        "projects": [
+            {
+                "domain_id": "1789d1",
+                "enabled": True,
+                "id": "263fd9",
+                "links": {
+                    "self": "https://example.com/identity/v3/projects/263fd9"
+                },
+                "name": "Test Group"
+            },
+            {
+                "domain_id": "1789d1",
+                "enabled": True,
+                "id": "50ef01",
+                "links": {
+                    "self": "https://example.com/identity/v3/projects/50ef01"
+                },
+                "name": "Build Group"
+            }
+        ],
+        "links": {
+            "self": "https://example.com/identity/v3/auth/projects",
+            "previous": None,
+            "next": None
+        }
+    }
+
     def setUp(self):
         super(TestIdentityClient, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -54,6 +82,13 @@
             bytes_body,
             resp_token="cbc36478b0bd8e67e89")
 
+    def _test_list_auth_projects(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_auth_projects,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_AUTH_PROJECTS,
+            bytes_body)
+
     def test_show_api_description_with_str_body(self):
         self._test_show_api_description()
 
@@ -73,3 +108,9 @@
             {},
             resp_token="cbc36478b0bd8e67e89",
             status=204)
+
+    def test_list_auth_projects_with_str_body(self):
+        self._test_list_auth_projects()
+
+    def test_list_auth_projects_with_bytes_body(self):
+        self._test_list_auth_projects(bytes_body=True)
diff --git a/tempest/tests/lib/services/identity/v3/test_oauth_consumers_client.py b/tempest/tests/lib/services/identity/v3/test_oauth_consumers_client.py
new file mode 100644
index 0000000..8d53792
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_oauth_consumers_client.py
@@ -0,0 +1,160 @@
+# Copyright 2017 AT&T 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.services.identity.v3 import oauth_consumers_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestOAUTHConsumerClient(base.BaseServiceTest):
+    FAKE_CREATE_CONSUMER = {
+        "consumer": {
+            'description': 'A fake description 1'
+        }
+
+    }
+
+    FAKE_CONSUMER_INFO = {
+        "consumer": {
+            'id': '6392c7d3b7a2062e09a07aa377',
+            'links': {
+                'self': 'http://example.com/identity/v3/' +
+                        'OS-OAUTH1/consumers/g6f2l9'
+            },
+            'description': 'A description that is fake'
+        }
+
+    }
+
+    FAKE_LIST_CONSUMERS = {
+        'links': {
+            'self': 'http://example.com/identity/v3/OS-OAUTH1/consumers/',
+            'next': None,
+            'previous': None
+        },
+        'consumers': [
+            {
+                'id': '6392c7d3b7a2062e09a07aa377',
+                'links': {
+                    'self': 'http://example.com/identity/v3/' +
+                            'OS-OAUTH1/consumers/6b9f2g5'
+                },
+                'description': 'A description that is fake'
+            },
+            {
+                'id': '677a855c9e3eb3a3954b36aca6',
+                'links': {
+                    'self': 'http://example.com/identity/v3/' +
+                            'OS-OAUTH1/consumers/6a9f2366'
+                },
+                'description': 'A very fake description 2'
+            },
+            {
+                'id': '9d3ac57b08d65e07826b5e506',
+                'links': {
+                    'self': 'http://example.com/identity/v3/' +
+                            'OS-OAUTH1/consumers/626b5e506'
+                },
+                'description': 'A very fake description 3'
+            },
+            {
+                'id': 'b522d163b1a18e928aca9y426',
+                'links': {
+                    'self': 'http://example.com/identity/v3/' +
+                            'OS-OAUTH1/consumers/g7ca9426'
+                },
+                'description': 'A very fake description 4'
+            },
+            {
+                'id': 'b7e47321b5ef9051f93c2049e',
+                'links': {
+                    'self': 'http://example.com/identity/v3/' +
+                            'OS-OAUTH1/consumers/23d82049e'
+                },
+                'description': 'A very fake description 5'
+            }
+        ]
+    }
+
+    def setUp(self):
+        super(TestOAUTHConsumerClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = oauth_consumers_client.OAUTHConsumerClient(fake_auth,
+                                                                 'identity',
+                                                                 'regionOne')
+
+    def _test_create_consumer(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_consumer,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_CREATE_CONSUMER,
+            bytes_body,
+            description=self.FAKE_CREATE_CONSUMER["consumer"]["description"],
+            status=201)
+
+    def _test_show_consumer(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_consumer,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_CONSUMER_INFO,
+            bytes_body,
+            consumer_id="6392c7d3b7a2062e09a07aa377")
+
+    def _test_list_consumers(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_consumers,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_LIST_CONSUMERS,
+            bytes_body)
+
+    def _test_update_consumer(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_consumer,
+            'tempest.lib.common.rest_client.RestClient.patch',
+            self.FAKE_CONSUMER_INFO,
+            bytes_body,
+            consumer_id="6392c7d3b7a2062e09a07aa377")
+
+    def test_create_consumer_with_str_body(self):
+        self._test_create_consumer()
+
+    def test_create_consumer_with_bytes_body(self):
+        self._test_create_consumer(bytes_body=True)
+
+    def test_show_consumer_with_str_body(self):
+        self._test_show_consumer()
+
+    def test_show_consumer_with_bytes_body(self):
+        self._test_show_consumer(bytes_body=True)
+
+    def test_list_consumers_with_str_body(self):
+        self._test_list_consumers()
+
+    def test_list_consumers_with_bytes_body(self):
+        self._test_list_consumers(bytes_body=True)
+
+    def test_update_consumer_with_str_body(self):
+        self._test_update_consumer()
+
+    def test_update_consumer_with_bytes_body(self):
+        self._test_update_consumer(bytes_body=True)
+
+    def test_delete_consumer(self):
+        self.check_service_client_function(
+            self.client.delete_consumer,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            consumer_id="6392c7d3b7a2062e09a07aa377",
+            status=204)
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 bad1ef9..8d6bb42 100644
--- a/tempest/tests/lib/services/identity/v3/test_roles_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_roles_client.py
@@ -18,30 +18,149 @@
 
 
 class TestRolesClient(base.BaseServiceTest):
+
+    FAKE_ROLE_ID = "1"
+    FAKE_ROLE_NAME = "test"
+    FAKE_DOMAIN_ID = "1"
+
+    FAKE_ROLE_ID_2 = "2"
+    FAKE_ROLE_NAME_2 = "test2"
+
+    FAKE_ROLE_ID_3 = "3"
+    FAKE_ROLE_NAME_3 = "test3"
+
+    FAKE_ROLE_ID_4 = "4"
+    FAKE_ROLE_NAME_4 = "test4"
+
+    FAKE_ROLE_ID_5 = "5"
+    FAKE_ROLE_NAME_5 = "test5"
+
+    FAKE_ROLE_ID_6 = "6"
+    FAKE_ROLE_NAME_6 = "test6"
+
     FAKE_ROLE_INFO = {
         "role": {
-            "domain_id": "1",
-            "id": "1",
-            "name": "test",
-            "links": "example.com"
+            "domain_id": FAKE_DOMAIN_ID,
+            "id": FAKE_ROLE_ID,
+            "name": FAKE_ROLE_NAME,
+            "links": {
+                "self": "http://example.com/identity/v3/roles/%s" % (
+                    FAKE_ROLE_ID)
+            }
         }
     }
 
-    FAKE_LIST_ROLES = {
-        "roles": [
-            {
-                "domain_id": "1",
-                "id": "1",
-                "name": "test",
-                "links": "example.com"
-            },
-            {
-                "domain_id": "2",
-                "id": "2",
-                "name": "test2",
-                "links": "example.com"
+    FAKE_ROLE_INFO_2 = {
+        "role": {
+            "domain_id": FAKE_DOMAIN_ID,
+            "id": FAKE_ROLE_ID_2,
+            "name": FAKE_ROLE_NAME_2,
+            "links": {
+                "self": "http://example.com/identity/v3/roles/%s" % (
+                    FAKE_ROLE_ID_2)
             }
-        ]
+        }
+    }
+
+    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)
+        }
+    }
+
+    COMMON_FAKE_LIST_ROLE_INFERENCE_RULES = [
+        {
+            "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": FAKE_ROLE_ID_3,
+                    "name": FAKE_ROLE_NAME_3,
+                    "links": {
+                        "self": "http://example.com/identity/v3/roles/%s" % (
+                            FAKE_ROLE_ID_3)
+                    }
+                }
+            ]
+        },
+        {
+            "prior_role": {
+                "id": FAKE_ROLE_ID_4,
+                "name": FAKE_ROLE_NAME_4,
+                "links": {
+                    "self": "http://example.com/identity/v3/roles/%s" % (
+                        FAKE_ROLE_ID_4)
+                }
+            },
+            "implies": [
+                {
+                    "id": FAKE_ROLE_ID_5,
+                    "name": FAKE_ROLE_NAME_5,
+                    "links": {
+                        "self": "http://example.com/identity/v3/roles/%s" % (
+                            FAKE_ROLE_ID_5)
+                    }
+                },
+                {
+                    "id": FAKE_ROLE_ID_6,
+                    "name": FAKE_ROLE_NAME_6,
+                    "links": {
+                        "self": "http://example.com/identity/v3/roles/%s" % (
+                            FAKE_ROLE_ID_6)
+                    }
+                }
+            ]
+        }
+    ]
+
+    FAKE_LIST_ROLE_INFERENCE_RULES = {
+        "role_inference": COMMON_FAKE_LIST_ROLE_INFERENCE_RULES[0],
+        "links": {
+            "self": "http://example.com/identity/v3/roles/"
+                    "%s/implies" % FAKE_ROLE_ID
+        }
+    }
+
+    FAKE_LIST_ALL_ROLE_INFERENCE_RULES = {
+        "role_inferences": COMMON_FAKE_LIST_ROLE_INFERENCE_RULES,
+        "links": {
+            "self": "http://example.com/identity/v3/role_inferences"
+        }
     }
 
     def setUp(self):
@@ -56,8 +175,8 @@
             'tempest.lib.common.rest_client.RestClient.post',
             self.FAKE_ROLE_INFO,
             bytes_body,
-            domain_id="1",
-            name="test",
+            domain_id=self.FAKE_DOMAIN_ID,
+            name=self.FAKE_ROLE_NAME,
             status=201)
 
     def _test_show_role(self, bytes_body=False):
@@ -66,7 +185,7 @@
             'tempest.lib.common.rest_client.RestClient.get',
             self.FAKE_ROLE_INFO,
             bytes_body,
-            role_id="1")
+            role_id=self.FAKE_ROLE_ID)
 
     def _test_list_roles(self, bytes_body=False):
         self.check_service_client_function(
@@ -81,8 +200,8 @@
             'tempest.lib.common.rest_client.RestClient.patch',
             self.FAKE_ROLE_INFO,
             bytes_body,
-            role_id="1",
-            name="test")
+            role_id=self.FAKE_ROLE_ID,
+            name=self.FAKE_ROLE_NAME)
 
     def _test_create_user_role_on_project(self, bytes_body=False):
         self.check_service_client_function(
@@ -164,6 +283,40 @@
             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_INFERENCE_RULES,
+            bytes_body,
+            prior_role=self.FAKE_ROLE_ID)
+
+    def _test_list_all_role_inference_rules(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_all_role_inference_rules,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_LIST_ALL_ROLE_INFERENCE_RULES,
+            bytes_body)
+
     def test_create_role_with_str_body(self):
         self._test_create_role()
 
@@ -193,7 +346,7 @@
             self.client.delete_role,
             'tempest.lib.common.rest_client.RestClient.delete',
             {},
-            role_id="1",
+            role_id=self.FAKE_ROLE_ID,
             status=204)
 
     def test_create_user_role_on_project_with_str_body(self):
@@ -311,3 +464,45 @@
             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)
+
+    def test_list_all_role_inference_rules_with_str_body(self):
+        self._test_list_all_role_inference_rules()
+
+    def test_list_all_role_inference_rules_with_bytes_body(self):
+        self._test_list_all_role_inference_rules(bytes_body=True)
diff --git a/tempest/tests/lib/services/identity/v3/test_versions_client.py b/tempest/tests/lib/services/identity/v3/test_versions_client.py
new file mode 100644
index 0000000..3bfaf1e
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_versions_client.py
@@ -0,0 +1,70 @@
+# Copyright 2017 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.services.identity.v3 import versions_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestIdentityClient(base.BaseServiceTest):
+
+    FAKE_VERSIONS_INFO = {
+        "versions": {
+            "values": [
+                {"status": "stable", "updated": "2017-02-22T00:00:00Z",
+                 "media-types": [
+                     {"base": "application/json", "type":
+                      "application/vnd.openstack.identity-v3+json"}
+                 ],
+                 "id": "v3.8",
+                 "links": [
+                     {"href": "https://15.184.67.226/identity_admin/v3/",
+                      "rel": "self"}
+                 ]},
+                {"status": "deprecated", "updated": "2016-08-04T00:00:00Z",
+                 "media-types": [
+                     {"base": "application/json",
+                      "type": "application/vnd.openstack.identity-v2.0+json"}
+                 ],
+                 "id": "v2.0",
+                 "links": [
+                     {"href": "https://15.184.67.226/identity_admin/v2.0/",
+                      "rel": "self"},
+                     {"href": "https://docs.openstack.org/",
+                      "type": "text/html", "rel": "describedby"}
+                 ]}
+            ]
+        }
+    }
+
+    def setUp(self):
+        super(TestIdentityClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = versions_client.VersionsClient(fake_auth,
+                                                     'identity',
+                                                     'regionOne')
+
+    def _test_list_versions(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_versions,
+            'tempest.lib.common.rest_client.RestClient.raw_request',
+            self.FAKE_VERSIONS_INFO,
+            bytes_body,
+            300)
+
+    def test_list_versions_with_str_body(self):
+        self._test_list_versions()
+
+    def test_list_versions_with_bytes_body(self):
+        self._test_list_versions(bytes_body=True)
diff --git a/tempest/tests/lib/services/image/v2/test_namespace_object_client.py b/tempest/tests/lib/services/image/v2/test_namespace_object_client.py
new file mode 100644
index 0000000..8d29660
--- /dev/null
+++ b/tempest/tests/lib/services/image/v2/test_namespace_object_client.py
@@ -0,0 +1,210 @@
+# Copyright 2016 EasyStack. 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.services.image.v2 import namespace_objects_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestNamespaceObjectClient(base.BaseServiceTest):
+    FAKE_CREATE_SHOW_OBJECTS = {
+        "created_at": "2016-09-19T18:20:56Z",
+        "description": "You can configure the CPU limits.",
+        "name": "CPU Limits",
+        "properties": {
+            "quota:cpu_period": {
+                "description": "Specifies the enforcement interval",
+                "maximum": 1000000,
+                "minimum": 1000,
+                "title": "Quota: CPU Period",
+                "type": "integer"
+            },
+            "quota:cpu_quota": {
+                "description": "Specifies the maximum allowed bandwidth ",
+                "title": "Quota: CPU Quota",
+                "type": "integer"
+            },
+            "quota:cpu_shares": {
+                "description": "Specifies the proportional weighted share.",
+                "title": "Quota: CPU Shares",
+                "type": "integer"
+            }
+        },
+        "required": [],
+        "schema": "/v2/schemas/metadefs/object",
+        "self": "/v2/metadefs/namespaces/OS::Compute::Quota/objects/CPU",
+        "updated_at": "2016-09-19T18:20:56Z"
+    }
+
+    FAKE_LIST_OBJECTS = {
+        "objects": [
+            {
+                "created_at": "2016-09-18T18:16:35Z",
+                "description": "You can configure the CPU limits.",
+                "name": "CPU Limits",
+                "properties": {
+                    "quota:cpu_period": {
+                        "description": "Specifies the enforcement interval ",
+                        "maximum": 1000000,
+                        "minimum": 1000,
+                        "title": "Quota: CPU Period",
+                        "type": "integer"
+                    },
+                    "quota:cpu_quota": {
+                        "description": "Specifies the maximum.",
+                        "title": "Quota: CPU Quota",
+                        "type": "integer"
+                    },
+                    "quota:cpu_shares": {
+                        "description": " Desc.",
+                        "title": "Quota: CPU Shares",
+                        "type": "integer"
+                    }
+                },
+                "required": [],
+                "schema": "/v2/schemas/metadefs/object",
+                "self":
+                    "/v2/metadefs/namespaces/OS::Compute::Quota/objects/CPU"
+            },
+            {
+                "created_at": "2016-09-18T18:16:35Z",
+                "description": "Using disk I/O quotas.",
+                "name": "Disk QoS",
+                "properties": {
+                    "quota:disk_read_bytes_sec": {
+                        "description": "Sets disk I/O quota.",
+                        "title": "Quota: Disk read bytes / sec",
+                        "type": "integer"
+                    },
+                    "quota:disk_read_iops_sec": {
+                        "description": "Sets disk I/O quota",
+                        "title": "Quota: Disk read IOPS / sec",
+                        "type": "integer"
+                    },
+                    "quota:disk_total_bytes_sec": {
+                        "description": "Sets disk I/O quota.",
+                        "title": "Quota: Disk Total Bytes / sec",
+                        "type": "integer"
+                    },
+                    "quota:disk_total_iops_sec": {
+                        "description": "Sets disk I/O quota.",
+                        "title": "Quota: Disk Total IOPS / sec",
+                        "type": "integer"
+                    },
+                    "quota:disk_write_bytes_sec": {
+                        "description": "Sets disk I/O quota.",
+                        "title": "Quota: Disk Write Bytes / sec",
+                        "type": "integer"
+                    },
+                    "quota:disk_write_iops_sec": {
+                        "description": "Sets disk I/O quota.",
+                        "title": "Quota: Disk Write IOPS / sec",
+                        "type": "integer"
+                    }
+                },
+                "required": [],
+                "schema": "/v2/schemas/metadefs/object",
+                "self":
+                "/v2/metadefs/namespaces/OS::Compute::Quota/objects/Disk QoS"
+            },
+        ],
+        "schema": "v2/schemas/metadefs/objects"
+    }
+
+    FAKE_UPDATE_OBJECTS = {
+        "description": "You can configure the CPU limits.",
+        "name": "CPU",
+        "properties": {
+            "quota:cpu_shares": {
+                "description": "Specify.",
+                "title": "Quota: CPU Shares",
+                "type": "integer"
+            }
+        },
+        "required": []
+    }
+
+    def setUp(self):
+        super(TestNamespaceObjectClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = namespace_objects_client.NamespaceObjectsClient(
+            fake_auth, 'image', 'regionOne')
+
+    def _test_create_namespace_objects(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_namespace_object,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_CREATE_SHOW_OBJECTS,
+            bytes_body, status=201,
+            namespace="OS::Compute::Hypervisor",
+            object_name="OS::Glance::Image")
+
+    def _test_list_namespace_objects(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_namespace_objects,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_LIST_OBJECTS,
+            bytes_body,
+            namespace="OS::Compute::Hypervisor")
+
+    def _test_show_namespace_objects(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_namespace_object,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_CREATE_SHOW_OBJECTS,
+            bytes_body,
+            namespace="OS::Compute::Hypervisor",
+            object_name="OS::Glance::Image")
+
+    def _test_update_namespace_objects(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_namespace_object,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_UPDATE_OBJECTS,
+            bytes_body,
+            namespace="OS::Compute::Hypervisor",
+            object_name="OS::Glance::Image",
+            name="CPU")
+
+    def test_create_namespace_object_with_str_body(self):
+        self._test_create_namespace_objects()
+
+    def test_create_namespace_object_with_bytes_body(self):
+        self._test_create_namespace_objects(bytes_body=True)
+
+    def test_list_namespace_object_with_str_body(self):
+        self._test_list_namespace_objects()
+
+    def test_list_namespace_object_with_bytes_body(self):
+        self._test_list_namespace_objects(bytes_body=True)
+
+    def test_show_namespace_object_with_str_body(self):
+        self._test_show_namespace_objects()
+
+    def test_show_namespace_object_with_bytes_body(self):
+        self._test_show_namespace_objects(bytes_body=True)
+
+    def test_update_namespace_object_with_str_body(self):
+        self._test_update_namespace_objects()
+
+    def test_update_namespace_object_with_bytes_body(self):
+        self._test_update_namespace_objects(bytes_body=True)
+
+    def test_delete_namespace_objects(self):
+        self.check_service_client_function(
+            self.client.delete_namespace_object,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, namespace="OS::Compute::Hypervisor",
+            object_name="OS::Glance::Image",
+            status=204)
diff --git a/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py b/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py
new file mode 100644
index 0000000..2faa5be
--- /dev/null
+++ b/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py
@@ -0,0 +1,126 @@
+# Copyright 2016 EasyStack. 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.services.image.v2 import namespace_tags_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestNamespaceTagsClient(base.BaseServiceTest):
+    FAKE_CREATE_SHOW_TAGS = {
+        "created_at": "2015-05-09T01:12:31Z",
+        "name": "added-sample-tag",
+        "updated_at": "2015-05-09T01:12:31Z"
+    }
+
+    FAKE_LIST_TAGS = {
+        "tags": [
+            {
+                "name": "sample-tag1"
+            },
+            {
+                "name": "sample-tag2"
+            },
+            {
+                "name": "sample-tag3"
+            }
+        ]
+    }
+
+    FAKE_UPDATE_TAGS = {"name": "new-tag-name"}
+
+    def setUp(self):
+        super(TestNamespaceTagsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = namespace_tags_client.NamespaceTagsClient(
+            fake_auth, 'image', 'regionOne')
+
+    def _test_create_namespace_tags(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_namespace_tags,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_CREATE_SHOW_TAGS,
+            bytes_body, status=201,
+            namespace="OS::Compute::Hypervisor",
+            tags=[{"name": "sample-tag1"},
+                  {"name": "sample-tag2"},
+                  {"name": "sample-tag3"}])
+
+    def _test_list_namespace_tags(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_namespace_tags,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_LIST_TAGS,
+            bytes_body,
+            namespace="OS::Compute::Hypervisor")
+
+    def _test_create_namespace_tag_definition(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_namespace_tag,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_CREATE_SHOW_TAGS,
+            bytes_body,
+            status=201,
+            namespace="OS::Compute::Hypervisor",
+            tag_name="added-sample-tag")
+
+    def _test_show_namespace_tag_definition(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_namespace_tag,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_CREATE_SHOW_TAGS,
+            bytes_body,
+            namespace="OS::Compute::Hypervisor",
+            tag_name="added-sample-tag")
+
+    def _test_update_namespace_tag_definition(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_namespace_tag,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_UPDATE_OBJECTS,
+            bytes_body,
+            namespace="OS::Compute::Hypervisor",
+            tag_name="added-sample-tag",
+            name="new-tag-name")
+
+    def test_create_namespace_tags_with_str_body(self):
+        self._test_create_namespace_tags()
+
+    def test_create_namespace_tags_with_bytes_body(self):
+        self._test_create_namespace_tags(bytes_body=True)
+
+    def test_list_namespace_tags_with_str_body(self):
+        self._test_list_namespace_tags()
+
+    def test_list_namespace_tags_with_bytes_body(self):
+        self._test_list_namespace_tags(bytes_body=True)
+
+    def test_create_namespace_tag_with_str_body(self):
+        self._test_create_namespace_tag_definition()
+
+    def test_create_namespace_tag_with_bytes_body(self):
+        self._test_create_namespace_tag_definition(bytes_body=True)
+
+    def test_show_namespace_tag_with_str_body(self):
+        self._test_show_namespace_tag_definition()
+
+    def test_show_namespace_tag_with_bytes_body(self):
+        self._test_show_namespace_tag_definition(bytes_body=True)
+
+    def test_delete_all_namespace_tags(self):
+        self.check_service_client_function(
+            self.client.delete_namespace_tags,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=200,
+            namespace="OS::Compute::Hypervisor")
diff --git a/tempest/tests/lib/services/image/v2/test_versions_client.py b/tempest/tests/lib/services/image/v2/test_versions_client.py
new file mode 100644
index 0000000..6234b06
--- /dev/null
+++ b/tempest/tests/lib/services/image/v2/test_versions_client.py
@@ -0,0 +1,94 @@
+# Copyright 2017 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.services.image.v2 import versions_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestVersionsClient(base.BaseServiceTest):
+
+    FAKE_VERSIONS_INFO = {
+        "versions": [
+            {
+                "status": "CURRENT", "id": "v2.5",
+                "links": [
+                    {"href": "https://10.220.1.21:9292/v2/", "rel": "self"}
+                ]
+            },
+            {
+                "status": "SUPPORTED", "id": "v2.4",
+                "links": [
+                    {"href": "https://10.220.1.21:9292/v2/", "rel": "self"}
+                ]
+            },
+            {
+                "status": "SUPPORTED", "id": "v2.3",
+                "links": [
+                    {"href": "https://10.220.1.21:9292/v2/", "rel": "self"}
+                ]
+            },
+            {
+                "status": "SUPPORTED", "id": "v2.2",
+                "links": [
+                    {"href": "https://10.220.1.21:9292/v2/", "rel": "self"}
+                ]
+            },
+            {
+                "status": "SUPPORTED", "id": "v2.1",
+                "links": [
+                    {"href": "https://10.220.1.21:9292/v2/", "rel": "self"}
+                ]
+            },
+            {
+                "status": "SUPPORTED", "id": "v2.0",
+                "links": [
+                    {"href": "https://10.220.1.21:9292/v2/", "rel": "self"}
+                ]
+            },
+            {
+                "status": "DEPRECATED", "id": "v1.1",
+                "links": [
+                    {"href": "https://10.220.1.21:9292/v1/", "rel": "self"}
+                ]
+            },
+            {
+                "status": "DEPRECATED", "id": "v1.0",
+                "links": [
+                    {"href": "https://10.220.1.21:9292/v1/", "rel": "self"}
+                ]
+            }
+        ]
+    }
+
+    def setUp(self):
+        super(TestVersionsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = versions_client.VersionsClient(fake_auth,
+                                                     'image',
+                                                     'regionOne')
+
+    def _test_list_versions(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_versions,
+            'tempest.lib.common.rest_client.RestClient.raw_request',
+            self.FAKE_VERSIONS_INFO,
+            bytes_body,
+            300)
+
+    def test_list_versions_with_str_body(self):
+        self._test_list_versions()
+
+    def test_list_versions_with_bytes_body(self):
+        self._test_list_versions(bytes_body=True)
diff --git a/tempest/tests/lib/services/test_clients.py b/tempest/tests/lib/services/test_clients.py
index 5db932c..a837199 100644
--- a/tempest/tests/lib/services/test_clients.py
+++ b/tempest/tests/lib/services/test_clients.py
@@ -12,10 +12,11 @@
 # License for the specific language governing permissions and limitations under
 # the License.
 
+import types
+
 import fixtures
 import mock
 import testtools
-import types
 
 from tempest.lib import auth
 from tempest.lib import exceptions
@@ -99,9 +100,8 @@
     def test___init___no_module(self):
         auth_provider = fake_auth_provider.FakeAuthProvider()
         class_names = ['FakeServiceClient1', 'FakeServiceClient2']
-        with testtools.ExpectedException(ImportError, '.*fake_module.*'):
-            clients.ClientsFactory('fake_module', class_names,
-                                   auth_provider)
+        self.assertRaises(ImportError, clients.ClientsFactory,
+                          'fake_module', class_names, auth_provider)
 
     def test___init___not_a_class(self):
         class_names = ['FakeServiceClient1', 'FakeServiceClient2']
diff --git a/tempest/tests/lib/services/volume/v3/test_versions_client.py b/tempest/tests/lib/services/volume/v3/test_versions_client.py
new file mode 100644
index 0000000..9627b9a
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v3/test_versions_client.py
@@ -0,0 +1,91 @@
+# Copyright 2017 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.services.volume.v3 import versions_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestVersionsClient(base.BaseServiceTest):
+
+    FAKE_VERSIONS_INFO = {
+        "versions": [
+            {
+                "status": "DEPRECATED", "updated": "2016-05-02T20:25:19Z",
+                "links": [
+                    {"href": "http://docs.openstack.org/", "type": "text/html",
+                     "rel": "describedby"},
+                    {"href": "https://10.30.197.39:8776/v1/", "rel": "self"}
+                ],
+                "min_version": "",
+                "version": "",
+                "media-types": [
+                    {"base": "application/json",
+                     "type": "application/vnd.openstack.volume+json;version=1"}
+                ],
+                "id": "v1.0"
+            },
+            {
+                "status": "DEPRECATED", "updated": "2017-02-25T12:00:00Z",
+                "links": [
+                    {"href": "http://docs.openstack.org/", "type": "text/html",
+                     "rel": "describedby"},
+                    {"href": "https://10.30.197.39:8776/v2/", "rel": "self"}
+                ],
+                "min_version": "",
+                "version": "",
+                "media-types": [
+                    {"base": "application/json",
+                     "type": "application/vnd.openstack.volume+json;version=1"}
+                ],
+                "id": "v2.0"
+            },
+            {
+                "status": "CURRENT", "updated": "2016-02-08T12:20:21Z",
+                "links": [
+                    {"href": "http://docs.openstack.org/", "type": "text/html",
+                     "rel": "describedby"},
+                    {"href": "https://10.30.197.39:8776/v3/", "rel": "self"}
+                ],
+                "min_version": "3.0",
+                "version": "3.28",
+                "media-types": [
+                    {"base": "application/json",
+                     "type": "application/vnd.openstack.volume+json;version=1"}
+                ],
+                "id": "v3.0"
+            }
+        ]
+    }
+
+    def setUp(self):
+        super(TestVersionsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = versions_client.VersionsClient(fake_auth,
+                                                     'volume',
+                                                     'regionOne')
+
+    def _test_list_versions(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_versions,
+            'tempest.lib.common.rest_client.RestClient.raw_request',
+            self.FAKE_VERSIONS_INFO,
+            bytes_body,
+            300)
+
+    def test_list_versions_with_str_body(self):
+        self._test_list_versions()
+
+    def test_list_versions_with_bytes_body(self):
+        self._test_list_versions(bytes_body=True)
diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py
index 2f975d2..ac13a13 100644
--- a/tempest/tests/lib/test_auth.py
+++ b/tempest/tests/lib/test_auth.py
@@ -15,9 +15,9 @@
 
 import copy
 import datetime
-import testtools
 
 from oslotest import mockpatch
+import testtools
 
 from tempest.lib import auth
 from tempest.lib import exceptions
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)
diff --git a/tempest/tests/lib/test_tempest_lib.py b/tempest/tests/lib/test_tempest_lib.py
index d70e53d..4d9f099 100644
--- a/tempest/tests/lib/test_tempest_lib.py
+++ b/tempest/tests/lib/test_tempest_lib.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 # 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
diff --git a/tempest/tests/services/object_storage/test_object_client.py b/tempest/tests/services/object_storage/test_object_client.py
index cc1dc1a..748614c 100644
--- a/tempest/tests/services/object_storage/test_object_client.py
+++ b/tempest/tests/services/object_storage/test_object_client.py
@@ -15,7 +15,6 @@
 
 
 import mock
-import six
 
 from tempest.lib import exceptions
 from tempest.services.object_storage import object_client
@@ -85,7 +84,7 @@
         # Verify that headers were written, including "Expect:100-continue"
         calls = []
 
-        for header, value in six.iteritems(expected_hdrs):
+        for header, value in expected_hdrs.items():
             calls.append(mock.call(header, value))
 
         mock_poc.return_value.putheader.assert_has_calls(calls, False)
diff --git a/tempest/tests/test_list_tests.py b/tempest/tests/test_list_tests.py
index 38d4c5c..a238879 100644
--- a/tempest/tests/test_list_tests.py
+++ b/tempest/tests/test_list_tests.py
@@ -14,9 +14,10 @@
 
 import os
 import re
-import six
 import subprocess
 
+import six
+
 from tempest.tests import base
 
 
diff --git a/tempest/tests/test_wrappers.py b/tempest/tests/test_wrappers.py
deleted file mode 100644
index a4ef699..0000000
--- a/tempest/tests/test_wrappers.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# Copyright 2013 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 os
-import shutil
-import subprocess
-import tempfile
-
-import six
-
-from tempest.tests import base
-
-DEVNULL = open(os.devnull, 'wb')
-
-
-class TestWrappers(base.TestCase):
-    def setUp(self):
-        super(TestWrappers, self).setUp()
-        # Setup test dirs
-        self.directory = tempfile.mkdtemp(prefix='tempest-unit')
-        self.addCleanup(shutil.rmtree, self.directory)
-        self.test_dir = os.path.join(self.directory, 'tests')
-        os.mkdir(self.test_dir)
-        # Setup Test files
-        self.testr_conf_file = os.path.join(self.directory, '.testr.conf')
-        self.setup_cfg_file = os.path.join(self.directory, 'setup.cfg')
-        self.passing_file = os.path.join(self.test_dir, 'test_passing.py')
-        self.failing_file = os.path.join(self.test_dir, 'test_failing.py')
-        self.init_file = os.path.join(self.test_dir, '__init__.py')
-        self.setup_py = os.path.join(self.directory, 'setup.py')
-        shutil.copy('tempest/tests/files/testr-conf', self.testr_conf_file)
-        shutil.copy('tempest/tests/files/passing-tests', self.passing_file)
-        shutil.copy('tempest/tests/files/failing-tests', self.failing_file)
-        shutil.copy('setup.py', self.setup_py)
-        shutil.copy('tempest/tests/files/setup.cfg', self.setup_cfg_file)
-        shutil.copy('tempest/tests/files/__init__.py', self.init_file)
-        # copy over the pretty_tox scripts
-        shutil.copy('tools/pretty_tox.sh',
-                    os.path.join(self.directory, 'pretty_tox.sh'))
-        shutil.copy('tools/pretty_tox_serial.sh',
-                    os.path.join(self.directory, 'pretty_tox_serial.sh'))
-
-        self.stdout = six.StringIO()
-        self.stderr = six.StringIO()
-        # Change directory, run wrapper and check result
-        self.addCleanup(os.chdir, os.path.abspath(os.curdir))
-        os.chdir(self.directory)
-
-    def assertRunExit(self, cmd, expected):
-        p = subprocess.Popen(
-            "bash %s" % cmd, shell=True,
-            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        out, err = p.communicate()
-
-        self.assertEqual(
-            p.returncode, expected,
-            "Stdout: %s; Stderr: %s" % (out, err))
-
-    def test_pretty_tox(self):
-        # Git init is required for the pbr testr command. pbr requires a git
-        # version or an sdist to work. so make the test directory a git repo
-        # too.
-        subprocess.call(['git', 'init'], stderr=DEVNULL)
-        self.assertRunExit('pretty_tox.sh passing', 0)
-
-    def test_pretty_tox_fails(self):
-        # Git init is required for the pbr testr command. pbr requires a git
-        # version or an sdist to work. so make the test directory a git repo
-        # too.
-        subprocess.call(['git', 'init'], stderr=DEVNULL)
-        self.assertRunExit('pretty_tox.sh', 1)
-
-    def test_pretty_tox_serial(self):
-        self.assertRunExit('pretty_tox_serial.sh passing', 0)
-
-    def test_pretty_tox_serial_fails(self):
-        self.assertRunExit('pretty_tox_serial.sh', 1)
diff --git a/test-requirements.txt b/test-requirements.txt
index 475fb16..13950bd 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,11 +1,12 @@
 # The order of packages is significant, because pip processes them in the order
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
-hacking<0.13,>=0.12.0 # Apache-2.0
+hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
 # needed for doc build
-sphinx!=1.3b1,<1.4,>=1.2.1 # BSD
+sphinx>=1.5.1 # BSD
 oslosphinx>=4.7.0 # Apache-2.0
 reno>=1.8.0 # Apache-2.0
 mock>=2.0 # BSD
 coverage>=4.0 # Apache-2.0
 oslotest>=1.10.0 # Apache-2.0
+flake8-import-order==0.11 # LGPLv3
diff --git a/tools/check_logs.py b/tools/check_logs.py
index caad85c..f82b387 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -19,10 +19,10 @@
 import gzip
 import os
 import re
-import six
-import six.moves.urllib.request as urlreq
 import sys
 
+import six
+import six.moves.urllib.request as urlreq
 import yaml
 
 
diff --git a/tools/find_stack_traces.py b/tools/find_stack_traces.py
index f2da27a..2ba8b16 100755
--- a/tools/find_stack_traces.py
+++ b/tools/find_stack_traces.py
@@ -18,9 +18,10 @@
 import gzip
 import pprint
 import re
+import sys
+
 import six
 import six.moves.urllib.request as urlreq
-import sys
 
 
 pp = pprint.PrettyPrinter()
diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py
index 03e838e..acb29af 100644
--- a/tools/generate-tempest-plugins-list.py
+++ b/tools/generate-tempest-plugins-list.py
@@ -25,6 +25,7 @@
 
 import json
 import re
+
 import requests
 
 url = 'https://review.openstack.org/projects/'
diff --git a/tools/pretty_tox.sh b/tools/pretty_tox.sh
deleted file mode 100755
index 0b83b91..0000000
--- a/tools/pretty_tox.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env bash
-
-echo "WARNING: This script is deprecated and will be removed in the near future. Please migrate to tempest run or another method of launching a test runner"
-
-set -o pipefail
-
-TESTRARGS=$1
-python setup.py testr --testr-args="--subunit $TESTRARGS" | subunit-trace --no-failure-debug -f
-retval=$?
-# NOTE(mtreinish) The pipe above would eat the slowest display from pbr's testr
-# wrapper so just manually print the slowest tests.
-echo -e "\nSlowest Tests:\n"
-testr slowest
-exit $retval
diff --git a/tools/pretty_tox_serial.sh b/tools/pretty_tox_serial.sh
deleted file mode 100755
index 1f8204e..0000000
--- a/tools/pretty_tox_serial.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-
-echo "WARNING: This script is deprecated and will be removed in the near future. Please migrate to tempest run or another method of launching a test runner"
-
-set -o pipefail
-
-TESTRARGS=$@
-
-if [ ! -d .testrepository ]; then
-    testr init
-fi
-testr run --subunit $TESTRARGS | subunit-trace -f -n
-retval=$?
-testr slowest
-
-exit $retval
diff --git a/tools/skip_tracker.py b/tools/skip_tracker.py
index 55f41a6..9735f77 100755
--- a/tools/skip_tracker.py
+++ b/tools/skip_tracker.py
@@ -20,23 +20,25 @@
 is fixed but a skip is still in the Tempest test code
 """
 
-import logging
 import os
 import re
 
 from launchpadlib import launchpad
+from oslo_log import log as logging
 
 BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
 TESTDIR = os.path.join(BASEDIR, 'tempest')
 LPCACHEDIR = os.path.expanduser('~/.launchpadlib/cache')
 
+LOG = logging.getLogger(__name__)
+
 
 def info(msg, *args, **kwargs):
-    logging.info(msg, *args, **kwargs)
+    LOG.info(msg, *args, **kwargs)
 
 
 def debug(msg, *args, **kwargs):
-    logging.debug(msg, *args, **kwargs)
+    LOG.debug(msg, *args, **kwargs)
 
 
 def find_skips(start=TESTDIR):
@@ -102,8 +104,6 @@
 
 
 if __name__ == '__main__':
-    logging.basicConfig(format='%(levelname)s: %(message)s',
-                        level=logging.INFO)
     results = find_skips()
     unique_bugs = sorted(set([bug for (method, bug) in get_results(results)]))
     unskips = []
diff --git a/tools/tox_install.sh b/tools/tox_install.sh
new file mode 100755
index 0000000..43468e4
--- /dev/null
+++ b/tools/tox_install.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Client constraint file contains this client version pin that is in conflict
+# with installing the client from source. We should remove the version pin in
+# the constraints file before applying it for from-source installation.
+
+CONSTRAINTS_FILE=$1
+shift 1
+
+set -e
+
+# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
+# published to logs.openstack.org for easy debugging.
+localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
+
+if [[ $CONSTRAINTS_FILE != http* ]]; then
+    CONSTRAINTS_FILE=file://$CONSTRAINTS_FILE
+fi
+# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
+curl $CONSTRAINTS_FILE --insecure --progress-bar --output $localfile
+
+pip install -c$localfile openstack-requirements
+
+# This is the main purpose of the script: Allow local installation of
+# the current repo. It is listed in constraints file and thus any
+# install will be constrained and we need to unconstrain it.
+edit-constraints $localfile -- $CLIENT_NAME
+
+pip install -c$localfile -U $*
+exit $?
diff --git a/tox.ini b/tox.ini
index 46823d8..892f834 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = pep8,py35,py34,py27,pip-check-reqs
+envlist = pep8,py35,py27,pip-check-reqs
 minversion = 2.3.1
 skipsdist = True
 
@@ -8,8 +8,9 @@
 setenv =
     VIRTUAL_ENV={envdir}
     OS_TEST_PATH=./tempest/test_discover
+    BRANCH_NAME=master
+    CLIENT_NAME=tempest
 deps =
-    setuptools
     -r{toxinidir}/requirements.txt
 
 [testenv]
@@ -17,9 +18,12 @@
     VIRTUAL_ENV={envdir}
     OS_TEST_PATH=./tempest/tests
     PYTHONWARNINGS=default::DeprecationWarning
-passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH OS_TEST_PATH TEMPEST_CONFIG TEMPEST_CONFIG_DIR http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
+    BRANCH_NAME=master
+    CLIENT_NAME=tempest
+passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH OS_TEST_PATH TEMPEST_CONFIG TEMPEST_CONFIG_DIR http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY ZUUL_CACHE_DIR REQUIREMENTS_PIP_LOCATION
 usedevelop = True
-install_command = pip install -U {opts} {packages}
+install_command =
+    {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
 whitelist_externals = *
 deps =
     -r{toxinidir}/requirements.txt
@@ -32,7 +36,6 @@
 commands = oslo-config-generator --config-file tempest/cmd/config-generator.tempest.conf
 
 [testenv:cover]
-setenv = OS_TEST_PATH=./tempest/tests
 commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}'
 
 [testenv:all]
@@ -78,7 +81,8 @@
 # See the testrepository bug: https://bugs.launchpad.net/testrepository/+bug/1208610
 commands =
     find . -type f -name "*.pyc" -delete
-    tempest run --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))' {posargs}
+    tempest run --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.api)' {posargs}
+    tempest run --combine --serial --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.scenario)' {posargs}
 
 [testenv:full-serial]
 envdir = .tox/tempest
@@ -91,6 +95,16 @@
     find . -type f -name "*.pyc" -delete
     tempest run --serial --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))' {posargs}
 
+[testenv:scenario]
+envdir = .tox/tempest
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+deps = {[tempestenv]deps}
+# The regex below is used to select all scenario tests
+commands =
+    find . -type f -name "*.pyc" -delete
+    tempest run --serial --regex '(^tempest\.scenario)' {posargs}
+
 [testenv:smoke]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
@@ -147,6 +161,7 @@
 show-source = True
 exclude = .git,.venv,.tox,dist,doc,*egg
 enable-extensions = H106,H203,H904
+import-order-style = pep8
 
 [testenv:releasenotes]
 commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html