Merge "Get NIC name by "ip -o link""
diff --git a/.gitignore b/.gitignore
index d58b162..5b87cec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,6 @@
 !.coveragerc
 cover/
 doc/source/_static/tempest.conf.sample
+
+# Files created by releasenotes build
+releasenotes/build
diff --git a/README.rst b/README.rst
index 71e185f..c859ddd 100644
--- a/README.rst
+++ b/README.rst
@@ -94,6 +94,45 @@
 .. _testr: https://testrepository.readthedocs.org/en/latest/MANUAL.html
 .. _ostestr: http://docs.openstack.org/developer/os-testr/
 
+Library
+-------
+Tempest exposes a library interface. This interface is a stable interface and
+should be backwards compatible (including backwards compatibility with the
+old tempest-lib package, with the exception of the import). If you plan to
+directly consume tempest in your project you should only import code from the
+tempest library interface, other pieces of tempest do not have the same
+stable interface and there are no guarantees on the Python API unless otherwise
+stated.
+
+For more details refer to the library documentation here: :ref:`library`
+
+Release Versioning
+------------------
+Tempest's released versions are broken into 2 sets of information. Depending on
+how you intend to consume tempest you might need
+
+The version is a set of 3 numbers:
+
+X.Y.Z
+
+While this is almost `semver`_ like, the way versioning is handled is slightly
+different:
+
+X is used to represent the supported OpenStack releases for tempest tests
+in-tree, and to signify major feature changes to tempest. It's a monotonically
+increasing integer where each version either indicates a new supported OpenStack
+release, the drop of support for an OpenStack release (which will coincide with
+the upstream stable branch going EOL), or a major feature lands (or is removed)
+from tempest.
+
+Y.Z is used to represent library interface changes. This is treated the same
+way as minor and patch versions from `semver`_ but only for the library
+interface. When Y is incremented we've added functionality to the library
+interface and when Z is incremented it's a bug fix release for the library.
+Also note that both Y and Z are reset to 0 at each increment of X.
+
+.. _semver: http://semver.org/
+
 Configuration
 -------------
 
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index e428592..524c0fa 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -139,6 +139,11 @@
  #. ``alt_password``
  #. ``alt_tenant_name``
 
+If using Identity API v3, use the ``domain_name`` option to specify a
+domain other than the default domain.  The ``auth_version`` setting is
+used to switch between v2 (``v2``) or v3 (``v3``) versions of the Identity
+API.
+
 And in the ``auth`` section:
 
  #. ``use_dynamic_credentials = False``
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 32e6e51..17def1c 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -11,6 +11,7 @@
    HACKING
    REVIEWING
    plugin
+   library
 
 ------------
 Field Guides
diff --git a/doc/source/library.rst b/doc/source/library.rst
new file mode 100644
index 0000000..8b263f2
--- /dev/null
+++ b/doc/source/library.rst
@@ -0,0 +1,68 @@
+.. _library:
+
+Tempest Library Documentation
+=============================
+
+Tempest provides a stable library interface that provides external tools or
+test suites an interface for reusing pieces of tempest code. Any public
+interface that lives in tempest/lib in the tempest repo is treated as a stable
+public interface and it should be safe to external consume that. Every effort
+goes into maintaining backwards compatibility with any change. Just as with
+tempest-lib the library is self contained and doesn't have any dependency on
+other tempest internals outside of lib. (including no usage of tempest
+configuration)
+
+Stability
+---------
+Just as tempest-lib before it any code that lives in tempest/lib will be treated
+as a stable interface, nothing has changed in regards to interface stability.
+This means that any public interface under the tempest/lib directory is
+expected to be a stable interface suitable for public consumption. However, for
+any interfaces outside of tempest/lib in the tempest tree (unless otherwise
+noted) or any private interfaces the same stability guarantees don't apply.
+
+Adding Interfaces
+'''''''''''''''''
+When adding an interface to tempest/lib we have to make sure there are no
+dependencies on any pieces of tempest outside of tempest/lib. This means if
+for example there is a dependency on the configuration file we need remove that.
+The other aspect when adding an interface is to make sure it's really an
+interface ready for external consumption and something we want to commit to
+supporting.
+
+Making changes
+''''''''''''''
+When making changes to tempest/lib you have to be conscious of the effect of
+any changes on external consumers. If your proposed changeset will change the
+default behaviour of any interface, or make something which previously worked
+not after your change, then it is not acceptable. Every effort needs to go into
+preserving backwards compatibility in changes.
+
+Reviewing
+'''''''''
+When reviewing a proposed change to tempest/lib code we need to be careful to
+ensure that we don't break backwards compatibility. For patches that change
+existing interfaces we have to be careful to make sure we don't break any
+external consumers. Some common red flags are:
+
+ * a change to an existing API requires a change outside the library directory
+   where the interface is being consumed
+ * a unit test has to be significantly changed to make the proposed change pass
+
+Testing
+'''''''
+When adding a new interface to the library we need to at a minimum have unit
+test coverage. A proposed change to add an interface to tempest/lib that
+doesn't have unit tests shouldn't be accepted. Ideally these unit tests will
+provide sufficient coverage to ensure a stable interface moving forward.
+
+Current Library APIs
+--------------------
+
+.. toctree::
+   :maxdepth: 2
+
+   library/cli
+   library/decorators
+   library/rest_client
+   library/utils
diff --git a/doc/source/library/cli.rst b/doc/source/library/cli.rst
new file mode 100644
index 0000000..6bd7881
--- /dev/null
+++ b/doc/source/library/cli.rst
@@ -0,0 +1,18 @@
+.. _cli:
+
+CLI Testing Framework Usage
+===========================
+
+-------------------
+The cli.base module
+-------------------
+
+.. automodule:: tempest.lib.cli.base
+   :members:
+
+----------------------------
+The cli.output_parser module
+----------------------------
+
+.. automodule:: tempest.lib.cli.output_parser
+   :members:
diff --git a/doc/source/library/decorators.rst b/doc/source/library/decorators.rst
new file mode 100644
index 0000000..a173967
--- /dev/null
+++ b/doc/source/library/decorators.rst
@@ -0,0 +1,13 @@
+.. _decorators:
+
+Decorators Usage Guide
+======================
+
+---------------------
+The decorators module
+---------------------
+
+.. automodule:: tempest.lib.decorators
+   :members:
+
+
diff --git a/doc/source/library/rest_client.rst b/doc/source/library/rest_client.rst
new file mode 100644
index 0000000..3045694
--- /dev/null
+++ b/doc/source/library/rest_client.rst
@@ -0,0 +1,11 @@
+.. _rest_client:
+
+Rest Client Usage
+=================
+
+----------------------
+The rest_client module
+----------------------
+
+.. automodule:: tempest.lib.common.rest_client
+   :members:
diff --git a/doc/source/library/utils.rst b/doc/source/library/utils.rst
new file mode 100644
index 0000000..bc2f79b
--- /dev/null
+++ b/doc/source/library/utils.rst
@@ -0,0 +1,11 @@
+.. _utils:
+
+Utils Usage
+===========
+
+---------------
+The misc module
+---------------
+
+.. automodule:: tempest.lib.common.utils.misc
+   :members:
diff --git a/tempest/api/messaging/__init__.py b/releasenotes/notes/.placeholder
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to releasenotes/notes/.placeholder
diff --git a/releasenotes/notes/10.0-supported-openstack-releases-b88db468695348f6.yaml b/releasenotes/notes/10.0-supported-openstack-releases-b88db468695348f6.yaml
new file mode 100644
index 0000000..217c2f6
--- /dev/null
+++ b/releasenotes/notes/10.0-supported-openstack-releases-b88db468695348f6.yaml
@@ -0,0 +1,13 @@
+---
+other:
+    - OpenStack Releases Supported at this time are the same as in the
+      previous release 9,
+        **Kilo** and
+        **Liberty**.
+
+
+      The release under current development as of this tag is Mitaka,
+      meaning that every Tempest commit is also tested against master during
+      the Mitaka cycle. However, this does not necessarily mean that using
+      Tempest as of this tag will work against a Mitaka (or future releases)
+      cloud.
diff --git a/releasenotes/notes/Tempest-library-interface-0eb680b810139a50.yaml b/releasenotes/notes/Tempest-library-interface-0eb680b810139a50.yaml
new file mode 100644
index 0000000..0ed3130
--- /dev/null
+++ b/releasenotes/notes/Tempest-library-interface-0eb680b810139a50.yaml
@@ -0,0 +1,11 @@
+---
+prelude: |
+    This release includes the addition of the stable library interface for
+    tempest. This behaves just as tempest-lib did prior to this, but instead
+    it lives directly in the tempest project. For more information refer to
+    the `library docs`_.
+
+    .. _library docs: http://docs.openstack.org/developer/tempest/library.html#library
+
+features:
+  - Tempest library interface
diff --git a/releasenotes/notes/start-using-reno-ed9518126fd0e1a3.yaml b/releasenotes/notes/start-using-reno-ed9518126fd0e1a3.yaml
new file mode 100644
index 0000000..0bc9af5
--- /dev/null
+++ b/releasenotes/notes/start-using-reno-ed9518126fd0e1a3.yaml
@@ -0,0 +1,3 @@
+---
+other:
+  - Start using reno for managing release notes.
diff --git a/tempest/api/messaging/__init__.py b/releasenotes/source/_static/.placeholder
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to releasenotes/source/_static/.placeholder
diff --git a/tempest/api/messaging/__init__.py b/releasenotes/source/_templates/.placeholder
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to releasenotes/source/_templates/.placeholder
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
new file mode 100644
index 0000000..4522a17
--- /dev/null
+++ b/releasenotes/source/conf.py
@@ -0,0 +1,277 @@
+# -*- 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
+#
+#    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.
+
+# tempest Release Notes documentation build configuration file, created by
+# sphinx-quickstart on Tue Nov  3 17:40:50 2015.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+# sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+    'oslosphinx',
+    'reno.sphinxext',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+# source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'tempest Release Notes'
+copyright = u'2016, tempest Developers'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+from tempest.version import version_info as tempest_version
+# The full version, including alpha/beta/rc tags.
+release = tempest_version.version_string_with_vcs()
+# The short X.Y version.
+version = tempest_version.canonical_version_string()
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+# language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+# today = ''
+# Else, today_fmt is used as the format for a strftime call.
+# today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+# default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+# add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+# add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+# show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+# modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+# keep_warnings = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+# html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+# html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+# html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+# html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+# html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+# html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+# html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+# html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+# html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+# html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+# html_additional_pages = {}
+
+# If false, no module index is generated.
+# html_domain_indices = True
+
+# If false, no index is generated.
+# html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+# html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+# html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+# html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+# html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+# html_use_opensearch = ''
+
+# 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 = 'tempestReleaseNotesdoc'
+
+
+# -- 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, or own class]).
+latex_documents = [
+    ('index', 'olso.configReleaseNotes.tex',
+     u'olso.config Release Notes Documentation',
+     u'tempest Developers', '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', 'olso.configreleasenotes',
+     u'tempest Release Notes Documentation',
+     [u'tempest Developers'], 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', 'tempestReleaseNotes',
+     u'tempest Release Notes Documentation',
+     u'tempest Developers', 'olso.configReleaseNotes',
+     'An OpenStack library for parsing configuration options from the command'
+     ' line and configuration files.',
+     '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'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+# texinfo_no_detailmenu = False
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
new file mode 100644
index 0000000..584540b
--- /dev/null
+++ b/releasenotes/source/index.rst
@@ -0,0 +1,14 @@
+===========================
+ tempest Release Notes
+===========================
+
+ .. toctree::
+    :maxdepth: 1
+
+    unreleased
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst
new file mode 100644
index 0000000..5860a46
--- /dev/null
+++ b/releasenotes/source/unreleased.rst
@@ -0,0 +1,5 @@
+==========================
+ Unreleased Release Notes
+==========================
+
+.. release-notes::
diff --git a/requirements.txt b/requirements.txt
index 66e5696..9dd57a9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,7 +2,7 @@
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
 pbr>=1.6 # Apache-2.0
-cliff!=1.16.0,>=1.15.0 # Apache-2.0
+cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
 anyjson>=0.3.3 # BSD
 httplib2>=0.7.5 # MIT
 jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
@@ -11,17 +11,17 @@
 netaddr!=0.7.16,>=0.7.12 # BSD
 testrepository>=0.0.18 # Apache-2.0/BSD
 pyOpenSSL>=0.14 # Apache-2.0
-oslo.concurrency>=2.3.0 # Apache-2.0
-oslo.config>=3.4.0 # Apache-2.0
+oslo.concurrency>=3.5.0 # Apache-2.0
+oslo.config>=3.7.0 # Apache-2.0
 oslo.i18n>=2.1.0 # Apache-2.0
 oslo.log>=1.14.0 # Apache-2.0
 oslo.serialization>=1.10.0 # Apache-2.0
-oslo.utils>=3.4.0 # Apache-2.0
+oslo.utils>=3.5.0 # Apache-2.0
 six>=1.9.0 # MIT
 iso8601>=0.1.9 # MIT
 fixtures>=1.3.1 # Apache-2.0/BSD
 testscenarios>=0.4 # Apache-2.0/BSD
-tempest-lib>=0.14.0 # Apache-2.0
 PyYAML>=3.1.0 # MIT
 stevedore>=1.5.0 # Apache-2.0
 PrettyTable<0.8,>=0.7 # BSD
+os-testr>=0.4.1 # Apache-2.0
diff --git a/setup.cfg b/setup.cfg
index cc3a365..0ddb898 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -32,6 +32,8 @@
     tempest-cleanup = tempest.cmd.cleanup:main
     tempest-account-generator = tempest.cmd.account_generator:main
     tempest = tempest.cmd.main:main
+    skip-tracker = tempest.lib.cmd.skip_tracker:main
+    check-uuid = tempest.lib.cmd.check_uuid:run
 tempest.cm =
     account-generator = tempest.cmd.account_generator:TempestAccountGenerator
     init = tempest.cmd.init:TempestInit
diff --git a/tempest/api/baremetal/admin/base.py b/tempest/api/baremetal/admin/base.py
index 80b69b9..f7891dd 100644
--- a/tempest/api/baremetal/admin/base.py
+++ b/tempest/api/baremetal/admin/base.py
@@ -12,10 +12,9 @@
 
 import functools
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/baremetal/admin/test_chassis.py b/tempest/api/baremetal/admin/test_chassis.py
index 29fc64c..339aaea 100644
--- a/tempest/api/baremetal/admin/test_chassis.py
+++ b/tempest/api/baremetal/admin/test_chassis.py
@@ -12,10 +12,10 @@
 #    under the License.
 
 import six
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.baremetal.admin import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/baremetal/admin/test_nodes.py b/tempest/api/baremetal/admin/test_nodes.py
index b6dee18..8cc4d05 100644
--- a/tempest/api/baremetal/admin/test_nodes.py
+++ b/tempest/api/baremetal/admin/test_nodes.py
@@ -11,11 +11,11 @@
 #    under the License.
 
 import six
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.baremetal.admin import base
 from tempest.common.utils import data_utils
 from tempest.common import waiters
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/baremetal/admin/test_ports.py b/tempest/api/baremetal/admin/test_ports.py
index 180b848..ce519c1 100644
--- a/tempest/api/baremetal/admin/test_ports.py
+++ b/tempest/api/baremetal/admin/test_ports.py
@@ -11,10 +11,10 @@
 #    under the License.
 
 import six
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.baremetal.admin import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/baremetal/admin/test_ports_negative.py b/tempest/api/baremetal/admin/test_ports_negative.py
index 610758a..8f04db9 100644
--- a/tempest/api/baremetal/admin/test_ports_negative.py
+++ b/tempest/api/baremetal/admin/test_ports_negative.py
@@ -10,10 +10,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.baremetal.admin import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
index 9f7bbae..671b139 100644
--- a/tempest/api/compute/admin/test_agents.py
+++ b/tempest/api/compute/admin/test_agents.py
@@ -13,10 +13,10 @@
 #    under the License.
 
 from oslo_log import log
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 LOG = log.getLogger(__name__)
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 1d83fec..a2b1e2f 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -13,11 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
index 181533b..6b75aee 100644
--- a/tempest/api/compute/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -13,11 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/admin/test_availability_zone_negative.py b/tempest/api/compute/admin/test_availability_zone_negative.py
index fe979d4..c60de1e 100644
--- a/tempest/api/compute/admin/test_availability_zone_negative.py
+++ b/tempest/api/compute/admin/test_availability_zone_negative.py
@@ -12,9 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py
index 8d745c9..05bba21 100644
--- a/tempest/api/compute/admin/test_fixed_ips_negative.py
+++ b/tempest/api/compute/admin/test_fixed_ips_negative.py
@@ -12,10 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 1ef8f67..96dedcf 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -15,10 +15,9 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/admin/test_flavors_access_negative.py b/tempest/api/compute/admin/test_flavors_access_negative.py
index 5070fd7..3854973 100644
--- a/tempest/api/compute/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/admin/test_flavors_access_negative.py
@@ -15,10 +15,9 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
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 14646e8..b0ab9be 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
@@ -14,10 +14,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py
index 65ada4d..8366945 100644
--- a/tempest/api/compute/admin/test_hosts_negative.py
+++ b/tempest/api/compute/admin/test_hosts_negative.py
@@ -12,10 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index 0e8012a..f313f76 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -15,10 +15,9 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
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 eea3103..b908502 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
@@ -16,9 +16,9 @@
 import datetime
 
 from six.moves.urllib import parse as urllib
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.compute import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 653a3cd..ead6db3 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -19,6 +19,7 @@
 from tempest.api.compute import base
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -62,7 +63,7 @@
     def _get_host_for_server(self, server_id):
         return self._get_server_details(server_id)[self._host_key]
 
-    def _migrate_server_to(self, server_id, dest_host, volume_backed):
+    def _migrate_server_to(self, server_id, dest_host, volume_backed=False):
         block_migration = (CONF.compute_feature_enabled.
                            block_migration_for_live_migration and
                            not volume_backed)
@@ -76,9 +77,6 @@
             if host != target_host:
                 return target_host
 
-    def _get_server_status(self, server_id):
-        return self._get_server_details(server_id)['status']
-
     def _volume_clean_up(self, server_id, volume_id):
         body = self.volumes_client.show_volume(volume_id)['volume']
         if body['status'] == 'in-use':
@@ -129,13 +127,11 @@
     @test.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88')
     @testtools.skipUnless(CONF.compute_feature_enabled.pause,
                           'Pause is not available.')
-    @testtools.skipUnless(CONF.compute_feature_enabled
-                              .live_migrate_paused_instances,
-                          'Live migration of paused instances is not '
-                          'available.')
     def test_live_block_migration_paused(self):
         self._test_live_migration(state='PAUSED')
 
+    @decorators.skip_because(bug="1549511",
+                             condition=CONF.service_available.neutron)
     @test.idempotent_id('5071cf17-3004-4257-ae61-73a84e28badd')
     @test.services('volume')
     def test_volume_backed_live_migration(self):
diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py
index bdbfde4..d6aba5b 100644
--- a/tempest/api/compute/admin/test_quotas_negative.py
+++ b/tempest/api/compute/admin/test_quotas_negative.py
@@ -12,12 +12,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import decorators
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
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 74f3caa..ce350b6 100644
--- a/tempest/api/compute/admin/test_security_group_default_rules.py
+++ b/tempest/api/compute/admin/test_security_group_default_rules.py
@@ -12,11 +12,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
 import testtools
 
 from tempest.api.compute import base
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 49c7318..3eb6d94 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -12,13 +12,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import decorators
-
 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 import decorators
 from tempest import test
 
 
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index 23b8a6c..07a7a30 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -14,7 +14,6 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
 import testtools
 
 from tempest.api.compute import base
@@ -22,6 +21,7 @@
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
@@ -68,7 +68,11 @@
         flavor_id = self._get_unused_flavor_id()
         quota_set = (self.quotas_client.show_default_quota_set(self.tenant_id)
                      ['quota_set'])
-        ram = int(quota_set['ram']) + 1
+        ram = int(quota_set['ram'])
+        if ram == -1:
+            raise self.skipException("default ram quota set is -1,"
+                                     " cannot test overlimit")
+        ram += 1
         vcpus = 8
         disk = 10
         flavor_ref = self.flavors_client.create_flavor(name=flavor_name,
@@ -93,7 +97,11 @@
         ram = 512
         quota_set = (self.quotas_client.show_default_quota_set(self.tenant_id)
                      ['quota_set'])
-        vcpus = int(quota_set['cores']) + 1
+        vcpus = int(quota_set['cores'])
+        if vcpus == -1:
+            raise self.skipException("default cores quota set is -1,"
+                                     " cannot test overlimit")
+        vcpus += 1
         disk = 10
         flavor_ref = self.flavors_client.create_flavor(name=flavor_name,
                                                        ram=ram, vcpus=vcpus,
diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py
index e57401a..710cac4 100644
--- a/tempest/api/compute/admin/test_services_negative.py
+++ b/tempest/api/compute/admin/test_services_negative.py
@@ -12,9 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py
index e5c17ca..8986db8 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage.py
@@ -16,8 +16,8 @@
 import datetime
 
 from tempest.api.compute import base
+from tempest.lib import exceptions as e
 from tempest import test
-from tempest_lib import exceptions as e
 
 # Time that waits for until returning valid response
 # TODO(takmatsu): Ideally this value would come from configuration.
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 e9b4ad4..315116e 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
@@ -14,9 +14,9 @@
 #    under the License.
 
 import datetime
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.compute import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/api_microversion_fixture.py b/tempest/api/compute/api_microversion_fixture.py
new file mode 100644
index 0000000..bf4de3e
--- /dev/null
+++ b/tempest/api/compute/api_microversion_fixture.py
@@ -0,0 +1,31 @@
+# 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 fixtures
+
+from tempest.services.compute.json import base_compute_client
+
+
+class APIMicroversionFixture(fixtures.Fixture):
+
+    def __init__(self, compute_microversion):
+        self.compute_microversion = compute_microversion
+
+    def _setUp(self):
+        super(APIMicroversionFixture, self)._setUp()
+        base_compute_client.COMPUTE_MICROVERSION = self.compute_microversion
+        self.addCleanup(self._reset_compute_microversion)
+
+    def _reset_compute_microversion(self):
+        base_compute_client.COMPUTE_MICROVERSION = None
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 0856983..ee21284 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -16,14 +16,15 @@
 import time
 
 from oslo_log import log as logging
-from tempest_lib import exceptions as lib_exc
 
+from tempest.api.compute import api_microversion_fixture
 from tempest.common import api_version_utils
 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 import exceptions as lib_exc
 import tempest.test
 
 CONF = config.CONF
@@ -56,13 +57,6 @@
     @classmethod
     def setup_credentials(cls):
         cls.set_network_resources()
-        cls.request_microversion = (
-            api_version_utils.select_request_microversion(
-                cls.min_microversion,
-                CONF.compute_feature_enabled.min_microversion))
-        if cls.request_microversion:
-            cls.services_microversion = {
-                CONF.compute.catalog_type: cls.request_microversion}
         super(BaseV2ComputeTest, cls).setup_credentials()
 
     @classmethod
@@ -108,6 +102,10 @@
     @classmethod
     def resource_setup(cls):
         super(BaseV2ComputeTest, cls).resource_setup()
+        cls.request_microversion = (
+            api_version_utils.select_request_microversion(
+                cls.min_microversion,
+                CONF.compute_feature_enabled.min_microversion))
         cls.build_interval = CONF.compute.build_interval
         cls.build_timeout = CONF.compute.build_timeout
         cls.image_ref = CONF.compute.image_ref
@@ -371,6 +369,11 @@
         else:
             raise exceptions.InvalidConfiguration()
 
+    def setUp(self):
+        super(BaseV2ComputeTest, self).setUp()
+        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+            self.request_microversion))
+
 
 class BaseV2ComputeAdminTest(BaseV2ComputeTest):
     """Base test case class for Compute Admin API tests."""
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 5b90641..85fd4ab 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -13,11 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute.floating_ips import base
 from tempest.common.utils import data_utils
 from tempest.common import waiters
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
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 0223c0d..105c4e3 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
@@ -15,11 +15,10 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute.floating_ips import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
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 75b6b55..c6c7347 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
@@ -15,11 +15,10 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/images/test_image_metadata_negative.py b/tempest/api/compute/images/test_image_metadata_negative.py
index 85d137b..9cb9e03 100644
--- a/tempest/api/compute/images/test_image_metadata_negative.py
+++ b/tempest/api/compute/images/test_image_metadata_negative.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index 8706566..e91944f 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -12,12 +12,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 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 import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
@@ -68,7 +67,7 @@
         resp = {}
         resp['status'] = None
         self.assertRaises(lib_exc.NotFound, self.create_image_from_server,
-                          '!@$%^&*()', name=name, meta=meta)
+                          '!@$^&*()', name=name, meta=meta)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('ec176029-73dc-4037-8d72-2e4ff60cf538')
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index 2fc9ef8..d9b80e1 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -15,12 +15,12 @@
 #    under the License.
 
 from oslo_log import log as logging
-from tempest_lib import exceptions as lib_exc
 
 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 import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
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 34d26e2..2689f88 100644
--- a/tempest/api/compute/images/test_list_image_filters_negative.py
+++ b/tempest/api/compute/images/test_list_image_filters_negative.py
@@ -12,11 +12,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py
index 0ab78fb..2a6139b 100644
--- a/tempest/api/compute/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/keypairs/test_keypairs_negative.py
@@ -14,10 +14,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute.keypairs import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/limits/test_absolute_limits_negative.py b/tempest/api/compute/limits/test_absolute_limits_negative.py
index 73e852f..66bc241 100644
--- a/tempest/api/compute/limits/test_absolute_limits_negative.py
+++ b/tempest/api/compute/limits/test_absolute_limits_negative.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
@@ -31,7 +30,6 @@
     def setup_clients(cls):
         super(AbsoluteLimitsNegativeTestJSON, cls).setup_clients()
         cls.client = cls.limits_client
-        cls.server_client = cls.servers_client
 
     @test.attr(type=['negative'])
     @test.idempotent_id('215cd465-d8ae-49c9-bf33-9c911913a5c8')
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 816038a..853ef31 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
@@ -13,11 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute.security_groups import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index 81a02be..f6353c8 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -13,11 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute.security_groups import base
 from tempest.common.utils import data_utils
 from tempest.common import waiters
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
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 120d327..5125e2b 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -13,13 +13,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import decorators
-from tempest_lib import exceptions as lib_exc
 import testtools
 
 from tempest.api.compute.security_groups import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index a6ccdd3..4fb4e9a 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -15,11 +15,10 @@
 
 import time
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest import config
 from tempest import exceptions
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
@@ -45,6 +44,7 @@
     def setup_clients(cls):
         super(AttachInterfacesTestJSON, cls).setup_clients()
         cls.client = cls.os.interfaces_client
+        cls.ports_client = cls.os.ports_client
 
     def wait_for_interface_status(self, server, port_id, status):
         """Waits for an interface to reach a given status."""
@@ -108,6 +108,18 @@
         self._check_interface(iface, network_id=network_id)
         return iface
 
+    def _test_create_interface_by_port_id(self, server, ifs):
+        network_id = ifs[0]['net_id']
+        port = self.ports_client.create_port(network_id=network_id)
+        port_id = port['port']['id']
+        self.addCleanup(self.ports_client.delete_port, port_id)
+        iface = self.client.create_interface(
+            server['id'], port_id=port_id)['interfaceAttachment']
+        iface = self.wait_for_interface_status(
+            server['id'], iface['port_id'], 'ACTIVE')
+        self._check_interface(iface, port_id=port_id)
+        return iface
+
     def _test_show_interface(self, server, ifs):
         iface = ifs[0]
         _iface = self.client.show_interface(
@@ -167,6 +179,9 @@
         iface = self._test_create_interface_by_network_id(server, ifs)
         ifs.append(iface)
 
+        iface = self._test_create_interface_by_port_id(server, ifs)
+        ifs.append(iface)
+
         _ifs = (self.client.list_interfaces(server['id'])
                 ['interfaceAttachments'])
         self._compare_iface_list(ifs, _ifs)
diff --git a/tempest/api/compute/servers/test_instance_actions_negative.py b/tempest/api/compute/servers/test_instance_actions_negative.py
index ac66d05..54ec6aa 100644
--- a/tempest/api/compute/servers/test_instance_actions_negative.py
+++ b/tempest/api/compute/servers/test_instance_actions_negative.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 37f322f..0b33d66 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -13,15 +13,14 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import decorators
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.api import utils
 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 import decorators
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index f205ddf..b18789e 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -14,10 +14,10 @@
 #    under the License.
 
 from six import moves
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.compute import base
 from tempest.common import waiters
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/servers/test_multiple_create_negative.py b/tempest/api/compute/servers/test_multiple_create_negative.py
index 3d8a732..e5b4f46 100644
--- a/tempest/api/compute/servers/test_multiple_create_negative.py
+++ b/tempest/api/compute/servers/test_multiple_create_negative.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 66e85a6..5b4417a 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -16,8 +16,6 @@
 import logging
 
 from six.moves.urllib import parse as urlparse
-from tempest_lib import decorators
-from tempest_lib import exceptions as lib_exc
 import testtools
 
 from tempest.api.compute import base
@@ -25,6 +23,8 @@
 from tempest.common.utils.linux import remote_client
 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
diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py
index 3503dc2..b4753e1 100644
--- a/tempest/api/compute/servers/test_server_addresses_negative.py
+++ b/tempest/api/compute/servers/test_server_addresses_negative.py
@@ -13,9 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/servers/test_server_group.py b/tempest/api/compute/servers/test_server_group.py
index c23b365..e32f6b0 100644
--- a/tempest/api/compute/servers/test_server_group.py
+++ b/tempest/api/compute/servers/test_server_group.py
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import decorators
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import test
@@ -81,13 +79,6 @@
         policy = ['anti-affinity']
         self._create_delete_server_group(policy)
 
-    @decorators.skip_because(bug="1324348")
-    @test.idempotent_id('6d9bae05-eb32-425d-a673-e14e1b1c6306')
-    def test_create_delete_server_group_with_multiple_policies(self):
-        # Create and Delete the server-group with multiple policies
-        policies = ['affinity', 'affinity']
-        self._create_delete_server_group(policies)
-
     @test.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
diff --git a/tempest/api/compute/servers/test_server_metadata_negative.py b/tempest/api/compute/servers/test_server_metadata_negative.py
index 18d80be..cbe70e2 100644
--- a/tempest/api/compute/servers/test_server_metadata_negative.py
+++ b/tempest/api/compute/servers/test_server_metadata_negative.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index dad8e90..74d34a2 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -14,13 +14,13 @@
 #    under the License.
 
 import base64
-from tempest_lib.common.utils import data_utils
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.compute import base
 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 exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index 5afb4d1..8d63b6b 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -13,13 +13,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
 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 import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 681b5db..0df6ead 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -15,13 +15,13 @@
 
 import sys
 
-from tempest_lib import exceptions as lib_exc
 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 import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 7aa6d34..b3e138f 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -14,10 +14,10 @@
 #    under the License.
 
 import netaddr
-from tempest_lib import decorators
 
 from tempest.api.compute import base
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/servers/test_virtual_interfaces_negative.py b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
index 577a673..e038b82 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces_negative.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
@@ -15,9 +15,8 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index bf4396d..133502c 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -16,11 +16,11 @@
 import six
 
 from oslo_log import log as logging
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
index 2cd85f2..dc57396 100644
--- a/tempest/api/compute/test_live_block_migration_negative.py
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -13,12 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 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 import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
index 01a0baf..d1c48c4 100644
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -15,11 +15,10 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/data_processing/base.py b/tempest/api/data_processing/base.py
index b6d0c48..164caaf 100644
--- a/tempest/api/data_processing/base.py
+++ b/tempest/api/data_processing/base.py
@@ -16,10 +16,10 @@
 import copy
 
 import six
-from tempest_lib import exceptions as lib_exc
 
 from tempest import config
 from tempest import exceptions
+from tempest.lib import exceptions as lib_exc
 import tempest.test
 
 
@@ -183,27 +183,6 @@
         ('5.3.0', copy.deepcopy(BASE_CDH_DESC)),
         ('5', copy.deepcopy(BASE_CDH_DESC))
     ]),
-    'mapr': OrderedDict([
-        ('4.0.1.mrv2', {
-            'NODES': {
-                'master1': {
-                    'count': 1,
-                    'node_processes': ['CLDB', 'FileServer', 'ZooKeeper',
-                                       'NodeManager', 'ResourceManager',
-                                       'HistoryServer', 'Oozie']
-                },
-                'worker1': {
-                    'count': 1,
-                    'node_processes': ['FileServer', 'NodeManager', 'Pig']
-                }
-            },
-            'cluster_configs': {
-                'Hive': {
-                    'Hive Version': '0.13',
-                }
-            }
-        })
-    ]),
 }
 
 
diff --git a/tempest/api/database/flavors/test_flavors_negative.py b/tempest/api/database/flavors/test_flavors_negative.py
index 3dee96f..cd2981b 100644
--- a/tempest/api/database/flavors/test_flavors_negative.py
+++ b/tempest/api/database/flavors/test_flavors_negative.py
@@ -13,9 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.database import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/identity/admin/v2/test_roles_negative.py b/tempest/api/identity/admin/v2/test_roles_negative.py
index 23a1958..14f4306 100644
--- a/tempest/api/identity/admin/v2/test_roles_negative.py
+++ b/tempest/api/identity/admin/v2/test_roles_negative.py
@@ -15,10 +15,9 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/identity/admin/v2/test_services.py b/tempest/api/identity/admin/v2/test_services.py
index 5685922..fe83759 100644
--- a/tempest/api/identity/admin/v2/test_services.py
+++ b/tempest/api/identity/admin/v2/test_services.py
@@ -14,10 +14,10 @@
 #    under the License.
 
 from six import moves
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/identity/admin/v2/test_tenant_negative.py b/tempest/api/identity/admin/v2/test_tenant_negative.py
index a02dbc1..a4c1afc 100644
--- a/tempest/api/identity/admin/v2/test_tenant_negative.py
+++ b/tempest/api/identity/admin/v2/test_tenant_negative.py
@@ -15,10 +15,9 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/identity/admin/v2/test_users_negative.py b/tempest/api/identity/admin/v2/test_users_negative.py
index 0a5d0c9..dee42b7 100644
--- a/tempest/api/identity/admin/v2/test_users_negative.py
+++ b/tempest/api/identity/admin/v2/test_users_negative.py
@@ -15,10 +15,9 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py
index 0e76d37..7c2e8e0 100644
--- a/tempest/api/identity/admin/v3/test_credentials.py
+++ b/tempest/api/identity/admin/v3/test_credentials.py
@@ -36,13 +36,13 @@
                 description=data_utils.rand_name('project-desc'))['project']
             cls.projects.append(cls.project['id'])
 
-        cls.user_body = cls.client.create_user(
+        cls.user_body = cls.users_client.create_user(
             u_name, description=u_desc, password=u_password,
             email=u_email, project_id=cls.projects[0])['user']
 
     @classmethod
     def resource_cleanup(cls):
-        cls.client.delete_user(cls.user_body['id'])
+        cls.users_client.delete_user(cls.user_body['id'])
         for p in cls.projects:
             cls.projects_client.delete_project(p)
         super(CredentialsTestJSON, cls).resource_cleanup()
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 661adb8..18a50d0 100644
--- a/tempest/api/identity/admin/v3/test_default_project_id.py
+++ b/tempest/api/identity/admin/v3/test_default_project_id.py
@@ -10,12 +10,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import auth
-
 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 manager
 from tempest import test
 
@@ -32,14 +31,14 @@
     def _delete_domain(self, domain_id):
         # It is necessary to disable the domain before deleting,
         # or else it would result in unauthorized error
-        self.client.update_domain(domain_id, enabled=False)
-        self.client.delete_domain(domain_id)
+        self.domains_client.update_domain(domain_id, enabled=False)
+        self.domains_client.delete_domain(domain_id)
 
     @test.idempotent_id('d6110661-6a71-49a7-a453-b5e26640ff6d')
     def test_default_project_id(self):
         # create a domain
         dom_name = data_utils.rand_name('dom')
-        domain_body = self.client.create_domain(dom_name)['domain']
+        domain_body = self.domains_client.create_domain(dom_name)['domain']
         dom_id = domain_body['id']
         self.addCleanup(self._delete_domain, dom_id)
 
@@ -56,11 +55,13 @@
         # create a user in the domain, with the previous project as his
         # default project
         user_name = data_utils.rand_name('user')
-        user_body = self.client.create_user(user_name, password=user_name,
-                                            domain_id=dom_id,
-                                            default_project_id=proj_id)['user']
+        user_body = self.users_client.create_user(
+            user_name,
+            password=user_name,
+            domain_id=dom_id,
+            default_project_id=proj_id)['user']
         user_id = user_body['id']
-        self.addCleanup(self.client.delete_user, user_id)
+        self.addCleanup(self.users_client.delete_user, user_id)
         self.assertEqual(user_body['domain_id'], dom_id,
                          "user " + user_name +
                          "doesn't have domain id " + dom_id)
@@ -70,8 +71,8 @@
         admin_role_id = admin_role['id']
 
         # grant the admin role to the user on his project
-        self.client.assign_user_role_on_project(proj_id, user_id,
-                                                admin_role_id)
+        self.roles_client.assign_user_role_on_project(proj_id, user_id,
+                                                      admin_role_id)
 
         # create a new client with user's credentials (NOTE: unscoped token!)
         creds = auth.KeystoneV3Credentials(username=user_name,
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index 1729dc9..27ff15d 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -26,11 +26,11 @@
     def _delete_domain(self, domain_id):
         # It is necessary to disable the domain before deleting,
         # or else it would result in unauthorized error
-        self.client.update_domain(domain_id, enabled=False)
-        self.client.delete_domain(domain_id)
+        self.domains_client.update_domain(domain_id, enabled=False)
+        self.domains_client.delete_domain(domain_id)
         # Asserting that the domain is not found in the list
         # after deletion
-        body = self.client.list_domains()['domains']
+        body = self.domains_client.list_domains()['domains']
         domains_list = [d['id'] for d in body]
         self.assertNotIn(domain_id, domains_list)
 
@@ -40,14 +40,14 @@
         domain_ids = list()
         fetched_ids = list()
         for _ in range(3):
-            domain = self.client.create_domain(
+            domain = self.domains_client.create_domain(
                 data_utils.rand_name('domain'),
                 description=data_utils.rand_name('domain-desc'))['domain']
             # Delete the domain at the end of this method
             self.addCleanup(self._delete_domain, domain['id'])
             domain_ids.append(domain['id'])
         # List and Verify Domains
-        body = self.client.list_domains()['domains']
+        body = self.domains_client.list_domains()['domains']
         for d in body:
             fetched_ids.append(d['id'])
         missing_doms = [d for d in domain_ids if d not in fetched_ids]
@@ -58,7 +58,7 @@
     def test_create_update_delete_domain(self):
         d_name = data_utils.rand_name('domain')
         d_desc = data_utils.rand_name('domain-desc')
-        domain = self.client.create_domain(
+        domain = self.domains_client.create_domain(
             d_name, description=d_desc)['domain']
         self.addCleanup(self._delete_domain, domain['id'])
         self.assertIn('id', domain)
@@ -73,7 +73,7 @@
         new_desc = data_utils.rand_name('new-desc')
         new_name = data_utils.rand_name('new-name')
 
-        updated_domain = self.client.update_domain(
+        updated_domain = self.domains_client.update_domain(
             domain['id'], name=new_name, description=new_desc)['domain']
         self.assertIn('id', updated_domain)
         self.assertIn('description', updated_domain)
@@ -85,7 +85,8 @@
         self.assertEqual(new_desc, updated_domain['description'])
         self.assertEqual(True, updated_domain['enabled'])
 
-        fetched_domain = self.client.show_domain(domain['id'])['domain']
+        fetched_domain = self.domains_client.show_domain(
+            domain['id'])['domain']
         self.assertEqual(new_name, fetched_domain['name'])
         self.assertEqual(new_desc, fetched_domain['description'])
         self.assertEqual(True, fetched_domain['enabled'])
@@ -95,9 +96,9 @@
         # Create domain with enabled status as false
         d_name = data_utils.rand_name('domain')
         d_desc = data_utils.rand_name('domain-desc')
-        domain = self.client.create_domain(
+        domain = self.domains_client.create_domain(
             d_name, description=d_desc, enabled=False)['domain']
-        self.addCleanup(self.client.delete_domain, domain['id'])
+        self.addCleanup(self.domains_client.delete_domain, domain['id'])
         self.assertEqual(d_name, domain['name'])
         self.assertFalse(domain['enabled'])
         self.assertEqual(d_desc, domain['description'])
@@ -106,7 +107,7 @@
     def test_create_domain_without_description(self):
         # Create domain only with name
         d_name = data_utils.rand_name('domain')
-        domain = self.client.create_domain(d_name)['domain']
+        domain = self.domains_client.create_domain(d_name)['domain']
         self.addCleanup(self._delete_domain, domain['id'])
         self.assertIn('id', domain)
         expected_data = {'name': d_name, 'enabled': True}
@@ -124,6 +125,6 @@
     @test.attr(type='smoke')
     @test.idempotent_id('17a5de24-e6a0-4e4a-a9ee-d85b6e5612b5')
     def test_default_domain_exists(self):
-        domain = self.client.show_domain(self.domain_id)['domain']
+        domain = self.domains_client.show_domain(self.domain_id)['domain']
 
         self.assertTrue(domain['enabled'])
diff --git a/tempest/api/identity/admin/v3/test_domains_negative.py b/tempest/api/identity/admin/v3/test_domains_negative.py
index 9eb3149..4330cab 100644
--- a/tempest/api/identity/admin/v3/test_domains_negative.py
+++ b/tempest/api/identity/admin/v3/test_domains_negative.py
@@ -14,11 +14,10 @@
 #    under the License.
 
 from tempest.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
-from tempest_lib.common.utils import data_utils
-from tempest_lib import exceptions as lib_exc
-
 
 class DomainsNegativeTestJSON(base.BaseIdentityV3AdminTest):
     _interface = 'json'
@@ -28,45 +27,46 @@
     def test_delete_active_domain(self):
         d_name = data_utils.rand_name('domain')
         d_desc = data_utils.rand_name('domain-desc')
-        domain = self.client.create_domain(d_name,
-                                           description=d_desc)['domain']
+        domain = self.domains_client.create_domain(
+            d_name,
+            description=d_desc)['domain']
         domain_id = domain['id']
 
         self.addCleanup(self.delete_domain, domain_id)
 
         # domain need to be disabled before deleting
-        self.assertRaises(lib_exc.Forbidden, self.client.delete_domain,
+        self.assertRaises(lib_exc.Forbidden, self.domains_client.delete_domain,
                           domain_id)
 
     @test.attr(type=['negative'])
     @test.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.client.create_domain,
-                          name='')
+        self.assertRaises(lib_exc.BadRequest,
+                          self.domains_client.create_domain, name='')
 
     @test.attr(type=['negative'])
     @test.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
-        self.assertRaises(lib_exc.BadRequest, self.client.create_domain,
-                          d_name)
+        self.assertRaises(lib_exc.BadRequest,
+                          self.domains_client.create_domain, d_name)
 
     @test.attr(type=['negative'])
     @test.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.client.delete_domain,
+        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')
     def test_domain_create_duplicate(self):
         domain_name = data_utils.rand_name('domain-dup')
-        domain = self.client.create_domain(domain_name)['domain']
+        domain = self.domains_client.create_domain(domain_name)['domain']
         domain_id = domain['id']
         self.addCleanup(self.delete_domain, domain_id)
         # Domain name should be unique
         self.assertRaises(
-            lib_exc.Conflict, self.client.create_domain, domain_name)
+            lib_exc.Conflict, self.domains_client.create_domain, domain_name)
diff --git a/tempest/api/identity/admin/v3/test_endpoints_negative.py b/tempest/api/identity/admin/v3/test_endpoints_negative.py
index 372254f..b16605e 100644
--- a/tempest/api/identity/admin/v3/test_endpoints_negative.py
+++ b/tempest/api/identity/admin/v3/test_endpoints_negative.py
@@ -14,10 +14,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py
index 03b8b29..010e4a0 100644
--- a/tempest/api/identity/admin/v3/test_groups.py
+++ b/tempest/api/identity/admin/v3/test_groups.py
@@ -68,9 +68,9 @@
         for i in range(3):
             name = data_utils.rand_name('User')
             password = data_utils.rand_password()
-            user = self.client.create_user(name, password)['user']
+            user = self.users_client.create_user(name, password)['user']
             users.append(user)
-            self.addCleanup(self.client.delete_user, user['id'])
+            self.addCleanup(self.users_client.delete_user, user['id'])
             self.groups_client.add_group_user(group['id'], user['id'])
 
         # list users in group
@@ -87,9 +87,9 @@
     @test.idempotent_id('64573281-d26a-4a52-b899-503cb0f4e4ec')
     def test_list_user_groups(self):
         # create a user
-        user = self.client.create_user(
+        user = self.users_client.create_user(
             data_utils.rand_name('User'), data_utils.rand_password())['user']
-        self.addCleanup(self.client.delete_user, user['id'])
+        self.addCleanup(self.users_client.delete_user, user['id'])
         # create two groups, and add user into them
         groups = []
         for i in range(2):
@@ -99,7 +99,7 @@
             self.addCleanup(self.groups_client.delete_group, group['id'])
             self.groups_client.add_group_user(group['id'], user['id'])
         # list groups which user belongs to
-        user_groups = self.client.list_user_groups(user['id'])['groups']
+        user_groups = self.users_client.list_user_groups(user['id'])['groups']
         self.assertEqual(sorted(groups), sorted(user_groups))
         self.assertEqual(2, len(user_groups))
 
diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py
new file mode 100644
index 0000000..fe20349
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -0,0 +1,147 @@
+#    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 import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class BaseInheritsV3Test(base.BaseIdentityV3AdminTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(BaseInheritsV3Test, cls).skip_checks()
+        if not test.is_extension_enabled('OS-INHERIT', 'identity'):
+            raise cls.skipException("Inherits aren't enabled")
+
+    @classmethod
+    def resource_setup(cls):
+        super(BaseInheritsV3Test, cls).resource_setup()
+        u_name = data_utils.rand_name('user-')
+        u_desc = '%s description' % u_name
+        u_email = '%s@testmail.tm' % u_name
+        u_password = data_utils.rand_name('pass-')
+        cls.domain = cls.domains_client.create_domain(
+            data_utils.rand_name('domain-'),
+            description=data_utils.rand_name('domain-desc-'))['domain']
+        cls.project = cls.projects_client.create_project(
+            data_utils.rand_name('project-'),
+            description=data_utils.rand_name('project-desc-'),
+            domain_id=cls.domain['id'])['project']
+        cls.group = cls.groups_client.create_group(
+            name=data_utils.rand_name('group-'), project_id=cls.project['id'],
+            domain_id=cls.domain['id'])['group']
+        cls.user = cls.users_client.create_user(
+            u_name, description=u_desc, password=u_password,
+            email=u_email, project_id=cls.project['id'],
+            domain_id=cls.domain['id'])['user']
+
+    @classmethod
+    def resource_cleanup(cls):
+        cls.groups_client.delete_group(cls.group['id'])
+        cls.users_client.delete_user(cls.user['id'])
+        cls.projects_client.delete_project(cls.project['id'])
+        cls.domains_client.update_domain(cls.domain['id'], enabled=False)
+        cls.domains_client.delete_domain(cls.domain['id'])
+        super(BaseInheritsV3Test, cls).resource_cleanup()
+
+    def _list_assertions(self, body, fetched_role_ids, role_id):
+        self.assertEqual(len(body), 1)
+        self.assertIn(role_id, fetched_role_ids)
+
+
+class InheritsV3TestJSON(BaseInheritsV3Test):
+
+    @test.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(
+            name=data_utils.rand_name('Role'))['role']
+        self.addCleanup(self.roles_client.delete_role, src_role['id'])
+        # Assign role on domains user
+        self.roles_client.assign_inherited_role_on_domains_user(
+            self.domain['id'], self.user['id'], src_role['id'])
+        # list role on domains user
+        roles = self.roles_client.\
+            list_inherited_project_role_for_user_on_domain(
+                self.domain['id'], self.user['id'])['roles']
+
+        fetched_role_ids = [i['id'] for i in roles]
+        self._list_assertions(roles, fetched_role_ids,
+                              src_role['id'])
+
+        # Check role on domains user
+        self.roles_client.check_user_inherited_project_role_on_domain(
+            self.domain['id'], self.user['id'], src_role['id'])
+        # Revoke role from domains user.
+        self.roles_client.revoke_inherited_role_from_user_on_domain(
+            self.domain['id'], self.user['id'], src_role['id'])
+
+    @test.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(
+            name=data_utils.rand_name('Role'))['role']
+        self.addCleanup(self.roles_client.delete_role, src_role['id'])
+        # Assign role on domains group
+        self.roles_client.assign_inherited_role_on_domains_group(
+            self.domain['id'], self.group['id'], src_role['id'])
+        # List role on domains group
+        roles = self.roles_client.\
+            list_inherited_project_role_for_group_on_domain(
+                self.domain['id'], self.group['id'])['roles']
+
+        fetched_role_ids = [i['id'] for i in roles]
+        self._list_assertions(roles, fetched_role_ids,
+                              src_role['id'])
+
+        # Check role on domains group
+        self.roles_client.check_group_inherited_project_role_on_domain(
+            self.domain['id'], self.group['id'], src_role['id'])
+        # Revoke role from domains group
+        self.roles_client.revoke_inherited_role_from_group_on_domain(
+            self.domain['id'], self.group['id'], src_role['id'])
+
+    @test.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(
+            name=data_utils.rand_name('Role'))['role']
+        self.addCleanup(self.roles_client.delete_role, src_role['id'])
+        # Assign role on projects user
+        self.roles_client.assign_inherited_role_on_projects_user(
+            self.project['id'], self.user['id'], src_role['id'])
+        # Check role on projects user
+        self.roles_client.check_user_has_flag_on_inherited_to_project(
+            self.project['id'], self.user['id'], src_role['id'])
+        # Revoke role from projects user
+        self.roles_client.revoke_inherited_role_from_user_on_project(
+            self.project['id'], self.user['id'], src_role['id'])
+
+    @test.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(
+            name=data_utils.rand_name('Role'))['role']
+        self.addCleanup(self.roles_client.delete_role, src_role['id'])
+        # Assign role on projects group
+        self.roles_client.assign_inherited_role_on_projects_group(
+            self.project['id'], self.group['id'], src_role['id'])
+        # Check role on projects group
+        self.roles_client.check_group_has_flag_on_inherited_to_project(
+            self.project['id'], self.group['id'], src_role['id'])
+        # Revoke role from projects group
+        self.roles_client.revoke_inherited_role_from_group_on_project(
+            self.project['id'], self.group['id'], src_role['id'])
diff --git a/tempest/api/identity/admin/v3/test_list_users.py b/tempest/api/identity/admin/v3/test_list_users.py
index 4921c00..5b27ab1 100644
--- a/tempest/api/identity/admin/v3/test_list_users.py
+++ b/tempest/api/identity/admin/v3/test_list_users.py
@@ -25,7 +25,7 @@
         # assert the response based on expected and not_expected
         # expected: user expected in the list response
         # not_expected: user, which should not be present in list response
-        body = self.client.list_users(params)['users']
+        body = self.users_client.list_users(params)['users']
         self.assertIn(expected[key], map(lambda x: x[key], body))
         self.assertNotIn(not_expected[key],
                          map(lambda x: x[key], body))
@@ -39,13 +39,13 @@
         cls.data.setup_test_domain()
         # Create user with Domain
         u1_name = data_utils.rand_name('test_user')
-        cls.domain_enabled_user = cls.client.create_user(
+        cls.domain_enabled_user = cls.users_client.create_user(
             u1_name, password=alt_password,
             email=cls.alt_email, domain_id=cls.data.domain['id'])['user']
         cls.data.users.append(cls.domain_enabled_user)
         # Create default not enabled user
         u2_name = data_utils.rand_name('test_user')
-        cls.non_domain_enabled_user = cls.client.create_user(
+        cls.non_domain_enabled_user = cls.users_client.create_user(
             u2_name, password=alt_password,
             email=cls.alt_email, enabled=False)['user']
         cls.data.users.append(cls.non_domain_enabled_user)
@@ -77,7 +77,7 @@
     @test.idempotent_id('b30d4651-a2ea-4666-8551-0c0e49692635')
     def test_list_users(self):
         # List users
-        body = self.client.list_users()['users']
+        body = self.users_client.list_users()['users']
         fetched_ids = [u['id'] for u in body]
         missing_users = [u['id'] for u in self.data.users
                          if u['id'] not in fetched_ids]
@@ -88,7 +88,7 @@
     @test.idempotent_id('b4baa3ae-ac00-4b4e-9e27-80deaad7771f')
     def test_get_user(self):
         # Get a user detail
-        user = self.client.show_user(self.data.users[0]['id'])['user']
+        user = self.users_client.show_user(self.data.users[0]['id'])['user']
         self.assertEqual(self.data.users[0]['id'], user['id'])
         self.assertEqual(self.data.users[0]['name'], user['name'])
         self.assertEqual(self.alt_email, user['email'])
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index 92f5a40..607bebe 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -163,14 +163,14 @@
         u_desc = u_name + 'description'
         u_email = u_name + '@testmail.tm'
         u_password = data_utils.rand_password()
-        user = self.client.create_user(
+        user = self.users_client.create_user(
             u_name, description=u_desc, password=u_password,
             email=u_email, project_id=project['id'])['user']
         # Delete the User at the end of this method
-        self.addCleanup(self.client.delete_user, user['id'])
+        self.addCleanup(self.users_client.delete_user, user['id'])
 
         # Get User To validate the user details
-        new_user_get = self.client.show_user(user['id'])['user']
+        new_user_get = self.users_client.show_user(user['id'])['user']
         # Assert response body of GET
         self.assertEqual(u_name, new_user_get['name'])
         self.assertEqual(u_desc, new_user_get['description'])
diff --git a/tempest/api/identity/admin/v3/test_projects_negative.py b/tempest/api/identity/admin/v3/test_projects_negative.py
index 79cfc91..fb4a8cf 100644
--- a/tempest/api/identity/admin/v3/test_projects_negative.py
+++ b/tempest/api/identity/admin/v3/test_projects_negative.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/identity/admin/v3/test_regions.py b/tempest/api/identity/admin/v3/test_regions.py
index 8bba3cb..ece36b9 100644
--- a/tempest/api/identity/admin/v3/test_regions.py
+++ b/tempest/api/identity/admin/v3/test_regions.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index f3cdd96..12ef369 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -25,14 +25,14 @@
         super(RolesV3TestJSON, cls).resource_setup()
         for _ in range(3):
             role_name = data_utils.rand_name(name='role')
-            role = cls.client.create_role(name=role_name)['role']
+            role = cls.roles_client.create_role(name=role_name)['role']
             cls.data.roles.append(role)
         cls.fetched_role_ids = list()
         u_name = data_utils.rand_name('user')
         u_desc = '%s description' % u_name
         u_email = '%s@testmail.tm' % u_name
         cls.u_password = data_utils.rand_password()
-        cls.domain = cls.client.create_domain(
+        cls.domain = cls.domains_client.create_domain(
             data_utils.rand_name('domain'),
             description=data_utils.rand_name('domain-desc'))['domain']
         cls.project = cls.projects_client.create_project(
@@ -42,23 +42,23 @@
         cls.group_body = cls.groups_client.create_group(
             name=data_utils.rand_name('Group'), project_id=cls.project['id'],
             domain_id=cls.domain['id'])['group']
-        cls.user_body = cls.client.create_user(
+        cls.user_body = cls.users_client.create_user(
             u_name, description=u_desc, password=cls.u_password,
             email=u_email, project_id=cls.project['id'],
             domain_id=cls.domain['id'])['user']
-        cls.role = cls.client.create_role(
+        cls.role = cls.roles_client.create_role(
             name=data_utils.rand_name('Role'))['role']
 
     @classmethod
     def resource_cleanup(cls):
-        cls.client.delete_role(cls.role['id'])
+        cls.roles_client.delete_role(cls.role['id'])
         cls.groups_client.delete_group(cls.group_body['id'])
-        cls.client.delete_user(cls.user_body['id'])
+        cls.users_client.delete_user(cls.user_body['id'])
         cls.projects_client.delete_project(cls.project['id'])
         # NOTE(harika-vakadi): It is necessary to disable the domain
         # before deleting,or else it would result in unauthorized error
-        cls.client.update_domain(cls.domain['id'], enabled=False)
-        cls.client.delete_domain(cls.domain['id'])
+        cls.domains_client.update_domain(cls.domain['id'], enabled=False)
+        cls.domains_client.delete_domain(cls.domain['id'])
         super(RolesV3TestJSON, cls).resource_cleanup()
 
     def _list_assertions(self, body, fetched_role_ids, role_id):
@@ -67,34 +67,35 @@
 
     @test.attr(type='smoke')
     @test.idempotent_id('18afc6c0-46cf-4911-824e-9989cc056c3a')
-    def test_role_create_update_get_list(self):
+    def test_role_create_update_show_list(self):
         r_name = data_utils.rand_name('Role')
-        role = self.client.create_role(name=r_name)['role']
-        self.addCleanup(self.client.delete_role, role['id'])
+        role = self.roles_client.create_role(name=r_name)['role']
+        self.addCleanup(self.roles_client.delete_role, role['id'])
         self.assertIn('name', role)
         self.assertEqual(role['name'], r_name)
 
         new_name = data_utils.rand_name('NewRole')
-        updated_role = self.client.update_role(role['id'],
-                                               name=new_name)['role']
+        updated_role = self.roles_client.update_role(role['id'],
+                                                     name=new_name)['role']
         self.assertIn('name', updated_role)
         self.assertIn('id', updated_role)
         self.assertIn('links', updated_role)
         self.assertNotEqual(r_name, updated_role['name'])
 
-        new_role = self.client.show_role(role['id'])['role']
+        new_role = self.roles_client.show_role(role['id'])['role']
         self.assertEqual(new_name, new_role['name'])
         self.assertEqual(updated_role['id'], new_role['id'])
 
-        roles = self.client.list_roles()['roles']
+        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')
     def test_grant_list_revoke_role_to_user_on_project(self):
-        self.client.assign_user_role_on_project(
-            self.project['id'], self.user_body['id'], self.role['id'])
+        self.roles_client.assign_user_role_on_project(self.project['id'],
+                                                      self.user_body['id'],
+                                                      self.role['id'])
 
-        roles = self.client.list_user_roles_on_project(
+        roles = self.roles_client.list_user_roles_on_project(
             self.project['id'], self.user_body['id'])['roles']
 
         for i in roles:
@@ -103,18 +104,18 @@
         self._list_assertions(roles, self.fetched_role_ids,
                               self.role['id'])
 
-        self.client.check_user_role_existence_on_project(
+        self.roles_client.check_user_role_existence_on_project(
             self.project['id'], self.user_body['id'], self.role['id'])
 
-        self.client.delete_role_from_user_on_project(
+        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')
     def test_grant_list_revoke_role_to_user_on_domain(self):
-        self.client.assign_user_role_on_domain(
+        self.roles_client.assign_user_role_on_domain(
             self.domain['id'], self.user_body['id'], self.role['id'])
 
-        roles = self.client.list_user_roles_on_domain(
+        roles = self.roles_client.list_user_roles_on_domain(
             self.domain['id'], self.user_body['id'])['roles']
 
         for i in roles:
@@ -123,19 +124,19 @@
         self._list_assertions(roles, self.fetched_role_ids,
                               self.role['id'])
 
-        self.client.check_user_role_existence_on_domain(
+        self.roles_client.check_user_role_existence_on_domain(
             self.domain['id'], self.user_body['id'], self.role['id'])
 
-        self.client.delete_role_from_user_on_domain(
+        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')
     def test_grant_list_revoke_role_to_group_on_project(self):
         # Grant role to group on project
-        self.client.assign_group_role_on_project(
+        self.roles_client.assign_group_role_on_project(
             self.project['id'], self.group_body['id'], self.role['id'])
         # List group roles on project
-        roles = self.client.list_group_roles_on_project(
+        roles = self.roles_client.list_group_roles_on_project(
             self.project['id'], self.group_body['id'])['roles']
 
         for i in roles:
@@ -157,19 +158,19 @@
         self.assertEqual(len(roles), 1)
         self.assertEqual(roles[0]['id'], self.role['id'])
 
-        self.client.check_role_from_group_on_project_existence(
+        self.roles_client.check_role_from_group_on_project_existence(
             self.project['id'], self.group_body['id'], self.role['id'])
 
         # Revoke role to group on project
-        self.client.delete_role_from_group_on_project(
+        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')
     def test_grant_list_revoke_role_to_group_on_domain(self):
-        self.client.assign_group_role_on_domain(
+        self.roles_client.assign_group_role_on_domain(
             self.domain['id'], self.group_body['id'], self.role['id'])
 
-        roles = self.client.list_group_roles_on_domain(
+        roles = self.roles_client.list_group_roles_on_domain(
             self.domain['id'], self.group_body['id'])['roles']
 
         for i in roles:
@@ -178,15 +179,15 @@
         self._list_assertions(roles, self.fetched_role_ids,
                               self.role['id'])
 
-        self.client.check_role_from_group_on_domain_existence(
+        self.roles_client.check_role_from_group_on_domain_existence(
             self.domain['id'], self.group_body['id'], self.role['id'])
 
-        self.client.delete_role_from_group_on_domain(
+        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')
     def test_list_roles(self):
         # Return a list of all roles
-        body = self.client.list_roles()['roles']
+        body = self.roles_client.list_roles()['roles']
         found = [role for role in body if role in self.data.roles]
         self.assertEqual(len(found), len(self.data.roles))
diff --git a/tempest/api/identity/admin/v3/test_services.py b/tempest/api/identity/admin/v3/test_services.py
index c6e3df4..2c3cae5 100644
--- a/tempest/api/identity/admin/v3/test_services.py
+++ b/tempest/api/identity/admin/v3/test_services.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index 3452d95..6f12939 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
@@ -30,10 +29,10 @@
         u_desc = '%s-description' % u_name
         u_email = '%s@testmail.tm' % u_name
         u_password = data_utils.rand_password()
-        user = self.client.create_user(
+        user = self.users_client.create_user(
             u_name, description=u_desc, password=u_password,
             email=u_email)['user']
-        self.addCleanup(self.client.delete_user, user['id'])
+        self.addCleanup(self.users_client.delete_user, user['id'])
         # Perform Authentication
         resp = self.token.auth(user_id=user['id'],
                                password=u_password).response
@@ -61,9 +60,9 @@
         # Create a user.
         user_name = data_utils.rand_name(name='user')
         user_password = data_utils.rand_password()
-        user = self.client.create_user(user_name,
-                                       password=user_password)['user']
-        self.addCleanup(self.client.delete_user, user['id'])
+        user = self.users_client.create_user(user_name,
+                                             password=user_password)['user']
+        self.addCleanup(self.users_client.delete_user, user['id'])
 
         # Create a couple projects
         project1_name = data_utils.rand_name(name='project')
@@ -78,15 +77,17 @@
 
         # Create a role
         role_name = data_utils.rand_name(name='role')
-        role = self.client.create_role(name=role_name)['role']
-        self.addCleanup(self.client.delete_role, role['id'])
+        role = self.roles_client.create_role(name=role_name)['role']
+        self.addCleanup(self.roles_client.delete_role, role['id'])
 
         # Grant the user the role on both projects.
-        self.client.assign_user_role(project1['id'], user['id'],
-                                     role['id'])
+        self.roles_client.assign_user_role_on_project(project1['id'],
+                                                      user['id'],
+                                                      role['id'])
 
-        self.client.assign_user_role(project2['id'], user['id'],
-                                     role['id'])
+        self.roles_client.assign_user_role_on_project(project2['id'],
+                                                      user['id'],
+                                                      role['id'])
 
         # Get an unscoped token.
         token_auth = self.token.auth(user_id=user['id'],
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index 5f44b8e..09ae468 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -14,13 +14,13 @@
 import re
 
 from oslo_utils import timeutils
-from tempest_lib import exceptions as lib_exc
 
 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 import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
@@ -56,7 +56,7 @@
         u_desc = self.trustor_username + 'description'
         u_email = self.trustor_username + '@testmail.xx'
         self.trustor_password = data_utils.rand_password()
-        user = self.client.create_user(
+        user = self.users_client.create_user(
             self.trustor_username,
             description=u_desc,
             password=self.trustor_password,
@@ -69,19 +69,22 @@
         self.delegated_role = data_utils.rand_name('DelegatedRole')
         self.not_delegated_role = data_utils.rand_name('NotDelegatedRole')
 
-        role = self.client.create_role(name=self.delegated_role)['role']
+        role = self.roles_client.create_role(name=self.delegated_role)['role']
         self.delegated_role_id = role['id']
 
-        role = self.client.create_role(name=self.not_delegated_role)['role']
+        role = self.roles_client.create_role(
+            name=self.not_delegated_role)['role']
         self.not_delegated_role_id = role['id']
 
         # Assign roles to trustor
-        self.client.assign_user_role(self.trustor_project_id,
-                                     self.trustor_user_id,
-                                     self.delegated_role_id)
-        self.client.assign_user_role(self.trustor_project_id,
-                                     self.trustor_user_id,
-                                     self.not_delegated_role_id)
+        self.roles_client.assign_user_role_on_project(
+            self.trustor_project_id,
+            self.trustor_user_id,
+            self.delegated_role_id)
+        self.roles_client.assign_user_role_on_project(
+            self.trustor_project_id,
+            self.trustor_user_id,
+            self.not_delegated_role_id)
 
         # Get trustee user ID, use the demo user
         trustee_username = self.non_admin_client.user
@@ -97,17 +100,17 @@
             tenant_name=self.trustor_project_name,
             project_domain_id='default')
         os = clients.Manager(credentials=creds)
-        self.trustor_client = os.identity_v3_client
+        self.trustor_client = os.trusts_client
 
     def cleanup_user_and_roles(self):
         if self.trustor_user_id:
-            self.client.delete_user(self.trustor_user_id)
+            self.users_client.delete_user(self.trustor_user_id)
         if self.trustor_project_id:
             self.projects_client.delete_project(self.trustor_project_id)
         if self.delegated_role_id:
-            self.client.delete_role(self.delegated_role_id)
+            self.roles_client.delete_role(self.delegated_role_id)
         if self.not_delegated_role_id:
-            self.client.delete_role(self.not_delegated_role_id)
+            self.roles_client.delete_role(self.not_delegated_role_id)
 
     def create_trust(self, impersonate=True, expires=None):
 
@@ -264,7 +267,7 @@
     @test.idempotent_id('4773ebd5-ecbf-4255-b8d8-b63e6f72b65d')
     def test_get_trusts_all(self):
         self.create_trust()
-        trusts_get = self.client.list_trusts()['trusts']
+        trusts_get = self.trusts_client.list_trusts()['trusts']
         trusts = [t for t in trusts_get
                   if t['id'] == self.trust_id]
         self.assertEqual(1, len(trusts))
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index 75c8ca5..e26624a 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -30,11 +30,11 @@
         u_desc = u_name + 'description'
         u_email = u_name + '@testmail.tm'
         u_password = data_utils.rand_password()
-        user = self.client.create_user(
+        user = self.users_client.create_user(
             u_name, description=u_desc, password=u_password,
             email=u_email, enabled=False)['user']
         # Delete the User at the end of this method
-        self.addCleanup(self.client.delete_user, user['id'])
+        self.addCleanup(self.users_client.delete_user, user['id'])
         # Creating second project for updation
         project = self.projects_client.create_project(
             data_utils.rand_name('project'),
@@ -45,7 +45,7 @@
         u_name2 = data_utils.rand_name('user2')
         u_email2 = u_name2 + '@testmail.tm'
         u_description2 = u_name2 + ' description'
-        update_user = self.client.update_user(
+        update_user = self.users_client.update_user(
             user['id'], name=u_name2, description=u_description2,
             project_id=project['id'],
             email=u_email2, enabled=False)['user']
@@ -56,7 +56,7 @@
         self.assertEqual(u_email2, update_user['email'])
         self.assertEqual(False, update_user['enabled'])
         # GET by id after updation
-        new_user_get = self.client.show_user(user['id'])['user']
+        new_user_get = self.users_client.show_user(user['id'])['user']
         # Assert response body of GET after updation
         self.assertEqual(u_name2, new_user_get['name'])
         self.assertEqual(u_description2, new_user_get['description'])
@@ -70,14 +70,15 @@
         # Creating User to check password updation
         u_name = data_utils.rand_name('user')
         original_password = data_utils.rand_password()
-        user = self.client.create_user(
+        user = self.users_client.create_user(
             u_name, password=original_password)['user']
         # Delete the User at the end all test methods
-        self.addCleanup(self.client.delete_user, user['id'])
+        self.addCleanup(self.users_client.delete_user, user['id'])
         # Update user with new password
         new_password = data_utils.rand_password()
-        self.client.update_user_password(user['id'], password=new_password,
-                                         original_password=original_password)
+        self.users_client.update_user_password(
+            user['id'], password=new_password,
+            original_password=original_password)
         # TODO(lbragstad): Sleeping after the response status has been checked
         # and the body loaded as JSON allows requests to fail-fast. The sleep
         # is necessary because keystone will err on the side of security and
@@ -110,19 +111,19 @@
         u_desc = u_name + 'description'
         u_email = u_name + '@testmail.tm'
         u_password = data_utils.rand_password()
-        user_body = self.client.create_user(
+        user_body = self.users_client.create_user(
             u_name, description=u_desc, password=u_password,
             email=u_email, enabled=False, project_id=u_project['id'])['user']
         # Delete the User at the end of this method
-        self.addCleanup(self.client.delete_user, user_body['id'])
+        self.addCleanup(self.users_client.delete_user, user_body['id'])
         # Creating Role
-        role_body = self.client.create_role(
+        role_body = self.roles_client.create_role(
             name=data_utils.rand_name('role'))['role']
         # Delete the Role at the end of this method
-        self.addCleanup(self.client.delete_role, role_body['id'])
+        self.addCleanup(self.roles_client.delete_role, role_body['id'])
 
-        user = self.client.show_user(user_body['id'])['user']
-        role = self.client.show_role(role_body['id'])['role']
+        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):
             # Creating project so as to assign role
             project_body = self.projects_client.create_project(
@@ -134,11 +135,11 @@
             self.addCleanup(
                 self.projects_client.delete_project, project_body['id'])
             # Assigning roles to user on project
-            self.client.assign_user_role(project['id'],
-                                         user['id'],
-                                         role['id'])
+            self.roles_client.assign_user_role_on_project(project['id'],
+                                                          user['id'],
+                                                          role['id'])
             assigned_project_ids.append(project['id'])
-        body = self.client.list_user_projects(user['id'])['projects']
+        body = self.users_client.list_user_projects(user['id'])['projects']
         for i in body:
             fetched_project_ids.append(i['id'])
         # verifying the project ids in list
@@ -154,5 +155,5 @@
     def test_get_user(self):
         # Get a user detail
         self.data.setup_test_user()
-        user = self.client.show_user(self.data.user['id'])['user']
+        user = self.users_client.show_user(self.data.user['id'])['user']
         self.assertEqual(self.data.user['id'], 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 39c89a5..1375db1 100644
--- a/tempest/api/identity/admin/v3/test_users_negative.py
+++ b/tempest/api/identity/admin/v3/test_users_negative.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
@@ -29,7 +28,7 @@
         u_name = data_utils.rand_name('user')
         u_email = u_name + '@testmail.tm'
         u_password = data_utils.rand_password()
-        self.assertRaises(lib_exc.NotFound, self.client.create_user,
+        self.assertRaises(lib_exc.NotFound, self.users_client.create_user,
                           u_name, u_password,
                           email=u_email,
                           domain_id=data_utils.rand_uuid_hex())
@@ -39,7 +38,7 @@
     def test_authentication_for_disabled_user(self):
         # Attempt to authenticate for disabled user should fail
         self.data.setup_test_user()
-        self.disable_user(self.data.user['name'])
+        self.disable_user(self.data.user['name'], self.data.user['domain_id'])
         self.assertRaises(lib_exc.Unauthorized, self.token.auth,
                           username=self.data.user['name'],
                           password=self.data.user_password,
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 455a2c6..3bcae17 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -14,10 +14,10 @@
 #    under the License.
 
 from oslo_log import log as logging
-from tempest_lib import exceptions as lib_exc
 
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 import tempest.test
 
 CONF = config.CONF
@@ -37,8 +37,12 @@
         cls.tenants_client.update_tenant(tenant['id'], enabled=False)
 
     @classmethod
-    def get_user_by_name(cls, name):
-        users = cls.users_client.list_users()['users']
+    def get_user_by_name(cls, name, domain_id=None):
+        if domain_id:
+            params = {'domain_id': domain_id}
+            users = cls.users_client.list_users(params)['users']
+        else:
+            users = cls.users_client.list_users()['users']
         user = [u for u in users if u['name'] == name]
         if len(user) > 0:
             return user[0]
@@ -102,14 +106,14 @@
         cls.non_admin_roles_client = cls.os.roles_client
         cls.users_client = cls.os_adm.users_client
         cls.non_admin_users_client = cls.os.users_client
-        cls.services_client = cls.os_adm.services_v2_client
-        cls.endpoints_client = cls.os_adm.endpoints_v2_client
+        cls.services_client = cls.os_adm.identity_services_client
+        cls.endpoints_client = cls.os_adm.endpoints_client
 
     @classmethod
     def resource_setup(cls):
         super(BaseIdentityV2AdminTest, cls).resource_setup()
-        cls.data = DataGeneratorV2(cls.client, cls.tenants_client,
-                                   cls.users_client, cls.roles_client)
+        cls.data = DataGeneratorV2(cls.tenants_client, cls.users_client,
+                                   cls.roles_client)
 
     @classmethod
     def resource_cleanup(cls):
@@ -129,6 +133,7 @@
     def setup_clients(cls):
         super(BaseIdentityV3Test, cls).setup_clients()
         cls.non_admin_client = cls.os.identity_v3_client
+        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
 
@@ -145,10 +150,14 @@
     def setup_clients(cls):
         super(BaseIdentityV3AdminTest, cls).setup_clients()
         cls.client = cls.os_adm.identity_v3_client
+        cls.domains_client = cls.os_adm.domains_client
+        cls.users_client = cls.os_adm.users_v3_client
+        cls.trusts_client = cls.os_adm.trusts_client
+        cls.roles_client = cls.os_adm.roles_v3_client
         cls.token = cls.os_adm.token_v3_client
-        cls.endpoints_client = cls.os_adm.endpoints_client
+        cls.endpoints_client = cls.os_adm.endpoints_v3_client
         cls.regions_client = cls.os_adm.regions_client
-        cls.services_client = cls.os_adm.identity_services_client
+        cls.services_client = cls.os_adm.identity_services_v3_client
         cls.policies_client = cls.os_adm.policies_client
         cls.creds_client = cls.os_adm.credentials_client
         cls.groups_client = cls.os_adm.groups_client
@@ -157,7 +166,8 @@
     @classmethod
     def resource_setup(cls):
         super(BaseIdentityV3AdminTest, cls).resource_setup()
-        cls.data = DataGeneratorV3(cls.client, cls.projects_client)
+        cls.data = DataGeneratorV3(cls.projects_client, cls.users_client,
+                                   cls.roles_client, cls.domains_client)
 
     @classmethod
     def resource_cleanup(cls):
@@ -165,39 +175,25 @@
         super(BaseIdentityV3AdminTest, cls).resource_cleanup()
 
     @classmethod
-    def get_user_by_name(cls, name):
-        users = cls.client.list_users()['users']
-        user = [u for u in users if u['name'] == name]
-        if len(user) > 0:
-            return user[0]
-
-    @classmethod
-    def get_role_by_name(cls, name):
-        roles = cls.client.list_roles()['roles']
-        role = [r for r in roles if r['name'] == name]
-        if len(role) > 0:
-            return role[0]
-
-    @classmethod
-    def disable_user(cls, user_name):
-        user = cls.get_user_by_name(user_name)
-        cls.client.update_user(user['id'], user_name, enabled=False)
+    def disable_user(cls, user_name, domain_id=None):
+        user = cls.get_user_by_name(user_name, domain_id)
+        cls.users_client.update_user(user['id'], user_name, enabled=False)
 
     def delete_domain(self, domain_id):
         # NOTE(mpavlase) It is necessary to disable the domain before deleting
         # otherwise it raises Forbidden exception
-        self.client.update_domain(domain_id, enabled=False)
-        self.client.delete_domain(domain_id)
+        self.domains_client.update_domain(domain_id, enabled=False)
+        self.domains_client.delete_domain(domain_id)
 
 
 class BaseDataGenerator(object):
 
-    def __init__(self, client, projects_client,
-                 users_client=None, roles_client=None):
-        self.client = client
+    def __init__(self, projects_client, users_client, roles_client,
+                 domains_client=None):
         self.projects_client = projects_client
-        self.users_client = users_client or client
-        self.roles_client = roles_client or client
+        self.users_client = users_client
+        self.roles_client = roles_client
+        self.domains_client = domains_client
 
         self.user_password = None
         self.user = None
@@ -246,8 +242,9 @@
         for role in self.roles:
             self._try_wrapper(self.roles_client.delete_role, role)
         for domain in self.domains:
-            self._try_wrapper(self.client.update_domain, domain, enabled=False)
-            self._try_wrapper(self.client.delete_domain, domain)
+            self._try_wrapper(self.domains_client.update_domain, domain,
+                              enabled=False)
+            self._try_wrapper(self.domains_client.delete_domain, domain)
 
 
 class DataGeneratorV2(BaseDataGenerator):
@@ -281,7 +278,7 @@
 
     def setup_test_domain(self):
         """Set up a test domain."""
-        self.domain = self.client.create_domain(
+        self.domain = self.domains_client.create_domain(
             name=data_utils.rand_name('test_domain'),
             description=data_utils.rand_name('desc'))['domain']
         self.domains.append(self.domain)
diff --git a/tempest/api/identity/v2/test_ec2_credentials.py b/tempest/api/identity/v2/test_ec2_credentials.py
index bd49326..8600980 100644
--- a/tempest/api/identity/v2/test_ec2_credentials.py
+++ b/tempest/api/identity/v2/test_ec2_credentials.py
@@ -13,9 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.identity import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/identity/v2/test_tenants.py b/tempest/api/identity/v2/test_tenants.py
index 4e31557..b742e69 100644
--- a/tempest/api/identity/v2/test_tenants.py
+++ b/tempest/api/identity/v2/test_tenants.py
@@ -13,9 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.identity import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/identity/v2/test_users.py b/tempest/api/identity/v2/test_users.py
index a59a1a0..ce4ee69 100644
--- a/tempest/api/identity/v2/test_users.py
+++ b/tempest/api/identity/v2/test_users.py
@@ -16,10 +16,9 @@
 import copy
 import time
 
-from tempest_lib.common.utils import data_utils
-from tempest_lib import exceptions
-
 from tempest.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
 from tempest import manager
 from tempest import test
 
diff --git a/tempest/api/identity/v3/test_projects.py b/tempest/api/identity/v3/test_projects.py
index a547b06..995b77e 100644
--- a/tempest/api/identity/v3/test_projects.py
+++ b/tempest/api/identity/v3/test_projects.py
@@ -13,9 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.identity import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
@@ -27,17 +26,21 @@
     def test_list_projects_returns_only_authorized_projects(self):
         alt_project_name =\
             self.alt_manager.credentials.credentials.project_name
-        resp = self.non_admin_client.list_user_projects(
+        resp = self.non_admin_users_client.list_user_projects(
             self.os.credentials.user_id)
 
         # check that user can see only that projects that he presents in so
         # user can successfully authenticate using his credentials and
         # project name from received projects list
         for project in resp['projects']:
+            # 'user_domain_id' needs to be specified otherwise tempest_lib
+            # assumes it to be 'default'
             token_id, body = self.non_admin_token.get_token(
                 username=self.os.credentials.username,
+                user_domain_id=self.os.credentials.user_domain_id,
                 password=self.os.credentials.password,
                 project_name=project['name'],
+                project_domain_id=project['domain_id'],
                 auth_data=True)
             self.assertNotEmpty(token_id)
             self.assertEqual(body['project']['id'], project['id'])
@@ -49,5 +52,7 @@
             lib_exc.Unauthorized,
             self.non_admin_token.get_token,
             username=self.os.credentials.username,
+            user_domain_id=self.os.credentials.user_domain_id,
             password=self.os.credentials.password,
-            project_name=alt_project_name)
+            project_name=alt_project_name,
+            project_domain_id=project['domain_id'])
diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py
index 3151763..593bf2a 100644
--- a/tempest/api/identity/v3/test_tokens.py
+++ b/tempest/api/identity/v3/test_tokens.py
@@ -28,10 +28,15 @@
         user_id = creds.user_id
         username = creds.username
         password = creds.password
+        user_domain_id = creds.user_domain_id
 
-        token_id, resp = self.non_admin_token.get_token(user_id=user_id,
-                                                        password=password,
-                                                        auth_data=True)
+        # 'user_domain_id' needs to be specified otherwise tempest_lib assumes
+        # it to be 'default'
+        token_id, resp = self.non_admin_token.get_token(
+            user_id=user_id,
+            user_domain_id=user_domain_id,
+            password=password,
+            auth_data=True)
 
         self.assertNotEmpty(token_id)
         self.assertIsInstance(token_id, six.string_types)
diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py
index 93814d3..ab48c07 100644
--- a/tempest/api/identity/v3/test_users.py
+++ b/tempest/api/identity/v3/test_users.py
@@ -16,10 +16,9 @@
 import copy
 import time
 
-from tempest_lib.common.utils import data_utils
-from tempest_lib import exceptions
-
 from tempest.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
 from tempest import manager
 from tempest import test
 
@@ -39,23 +38,24 @@
         self.new_creds = copy.copy(self.creds.credentials)
         self.new_creds.password = data_utils.rand_password()
         # we need new non-admin Identity V3 Client with new credentials, since
-        # current non_admin_client token will be revoked after updating
+        # current non_admin_users_client token will be revoked after updating
         # password
-        self.non_admin_client_for_cleanup = copy.copy(self.non_admin_client)
-        self.non_admin_client_for_cleanup.auth_provider = (
+        self.non_admin_users_client_for_cleanup = (
+            copy.copy(self.non_admin_users_client))
+        self.non_admin_users_client_for_cleanup.auth_provider = (
             manager.get_auth_provider(self.new_creds))
         user_id = self.creds.credentials.user_id
         old_pass = self.creds.credentials.password
         new_pass = self.new_creds.password
         # to change password back. important for allow_tenant_isolation = false
         self.addCleanup(
-            self.non_admin_client_for_cleanup.update_user_password,
+            self.non_admin_users_client_for_cleanup.update_user_password,
             user_id,
             password=old_pass,
             original_password=new_pass)
 
         # user updates own password
-        self.non_admin_client.update_user_password(
+        self.non_admin_users_client.update_user_password(
             user_id, password=new_pass, original_password=old_pass)
 
         # TODO(lbragstad): Sleeping after the response status has been checked
diff --git a/tempest/api/image/admin/v2/test_images.py b/tempest/api/image/admin/v2/test_images.py
index b171da3..80da7a1 100644
--- a/tempest/api/image/admin/v2/test_images.py
+++ b/tempest/api/image/admin/v2/test_images.py
@@ -14,13 +14,13 @@
 #    under the License.
 
 from six import moves
-from tempest_lib.common.utils import data_utils
 import testtools
 
 from tempest.api.image import base
 from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 
 CONF = config.CONF
 
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index ade7b67..0683936 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -13,10 +13,10 @@
 #    under the License.
 
 from six import moves
-from tempest_lib import exceptions as lib_exc
 
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 import tempest.test
 
 CONF = config.CONF
diff --git a/tempest/api/image/v1/test_image_members_negative.py b/tempest/api/image/v1/test_image_members_negative.py
index 50f5048..16a4ba6 100644
--- a/tempest/api/image/v1/test_image_members_negative.py
+++ b/tempest/api/image/v1/test_image_members_negative.py
@@ -12,10 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.image import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/image/v1/test_images_negative.py b/tempest/api/image/v1/test_images_negative.py
index f16b80e..babee74 100644
--- a/tempest/api/image/v1/test_images_negative.py
+++ b/tempest/api/image/v1/test_images_negative.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.image import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/image/v2/test_images_member_negative.py b/tempest/api/image/v2/test_images_member_negative.py
index eb90719..388eb08 100644
--- a/tempest/api/image/v2/test_images_member_negative.py
+++ b/tempest/api/image/v2/test_images_member_negative.py
@@ -10,9 +10,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.image import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/image/v2/test_images_metadefs_namespaces.py b/tempest/api/image/v2/test_images_metadefs_namespaces.py
index efb7b8b..de8299e 100644
--- a/tempest/api/image/v2/test_images_metadefs_namespaces.py
+++ b/tempest/api/image/v2/test_images_metadefs_namespaces.py
@@ -15,8 +15,8 @@
 
 from tempest.api.image import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 
 
 class MetadataNamespacesTest(base.BaseV2ImageTest):
diff --git a/tempest/api/image/v2/test_images_negative.py b/tempest/api/image/v2/test_images_negative.py
index 485942e..fc74326 100644
--- a/tempest/api/image/v2/test_images_negative.py
+++ b/tempest/api/image/v2/test_images_negative.py
@@ -16,9 +16,8 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.image import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/image/v2/test_images_tags_negative.py b/tempest/api/image/v2/test_images_tags_negative.py
index a3f4ca8..1aa2d11 100644
--- a/tempest/api/image/v2/test_images_tags_negative.py
+++ b/tempest/api/image/v2/test_images_tags_negative.py
@@ -14,10 +14,9 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.image import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/messaging/base.py b/tempest/api/messaging/base.py
deleted file mode 100644
index a324c37..0000000
--- a/tempest/api/messaging/base.py
+++ /dev/null
@@ -1,161 +0,0 @@
-# Copyright (c) 2014 Rackspace, Inc.
-#
-# 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.common.utils import data_utils
-from tempest import config
-from tempest import test
-
-CONF = config.CONF
-
-
-class BaseMessagingTest(test.BaseTestCase):
-
-    """Base class for the Messaging (Zaqar) tests
-
-    It is assumed that the following option is defined in the
-    [service_available] section of etc/tempest.conf
-
-        messaging as True
-    """
-
-    credentials = ['primary']
-
-    @classmethod
-    def skip_checks(cls):
-        super(BaseMessagingTest, cls).skip_checks()
-        if not CONF.service_available.zaqar:
-            raise cls.skipException("Zaqar support is required")
-
-    @classmethod
-    def setup_clients(cls):
-        super(BaseMessagingTest, cls).setup_clients()
-        cls.client = cls.os.messaging_client
-
-    @classmethod
-    def resource_setup(cls):
-        super(BaseMessagingTest, cls).resource_setup()
-        cls.messaging_cfg = CONF.messaging
-
-    @classmethod
-    def create_queue(cls, queue_name):
-        """Wrapper utility that returns a test queue."""
-        resp, body = cls.client.create_queue(queue_name)
-        return resp, body
-
-    @classmethod
-    def delete_queue(cls, queue_name):
-        """Wrapper utility that deletes a test queue."""
-        resp, body = cls.client.delete_queue(queue_name)
-        return resp, body
-
-    @classmethod
-    def check_queue_exists(cls, queue_name):
-        """Wrapper utility that checks the existence of a test queue."""
-        resp, body = cls.client.show_queue(queue_name)
-        return resp, body
-
-    @classmethod
-    def check_queue_exists_head(cls, queue_name):
-        """Wrapper utility checks the head of a queue via http HEAD."""
-        resp, body = cls.client.head_queue(queue_name)
-        return resp, body
-
-    @classmethod
-    def list_queues(cls):
-        """Wrapper utility that lists queues."""
-        resp, body = cls.client.list_queues()
-        return resp, body
-
-    @classmethod
-    def get_queue_stats(cls, queue_name):
-        """Wrapper utility that returns the queue stats."""
-        resp, body = cls.client.show_queue_stats(queue_name)
-        return resp, body
-
-    @classmethod
-    def get_queue_metadata(cls, queue_name):
-        """Wrapper utility that gets a queue metadata."""
-        resp, body = cls.client.show_queue_metadata(queue_name)
-        return resp, body
-
-    @classmethod
-    def set_queue_metadata(cls, queue_name, rbody):
-        """Wrapper utility that sets the metadata of a queue."""
-        resp, body = cls.client.set_queue_metadata(queue_name, rbody)
-        return resp, body
-
-    @classmethod
-    def post_messages(cls, queue_name, rbody):
-        """Wrapper utility that posts messages to a queue."""
-        resp, body = cls.client.post_messages(queue_name, rbody)
-
-        return resp, body
-
-    @classmethod
-    def list_messages(cls, queue_name):
-        """Wrapper utility that lists the messages in a queue."""
-        resp, body = cls.client.list_messages(queue_name)
-
-        return resp, body
-
-    @classmethod
-    def delete_messages(cls, message_uri):
-        """Wrapper utility that deletes messages."""
-        resp, body = cls.client.delete_messages(message_uri)
-
-        return resp, body
-
-    @classmethod
-    def post_claims(cls, queue_name, rbody, url_params=False):
-        """Wrapper utility that claims messages."""
-        resp, body = cls.client.post_claims(
-            queue_name, rbody, url_params=False)
-
-        return resp, body
-
-    @classmethod
-    def query_claim(cls, claim_uri):
-        """Wrapper utility that gets a claim."""
-        resp, body = cls.client.query_claim(claim_uri)
-
-        return resp, body
-
-    @classmethod
-    def update_claim(cls, claim_uri, rbody):
-        """Wrapper utility that updates a claim."""
-        resp, body = cls.client.update_claim(claim_uri, rbody)
-
-        return resp, body
-
-    @classmethod
-    def release_claim(cls, claim_uri):
-        """Wrapper utility that deletes a claim."""
-        resp, body = cls.client.delete_claim(claim_uri)
-
-        return resp, body
-
-    @classmethod
-    def generate_message_body(cls, repeat=1):
-        """Wrapper utility that sets the metadata of a queue."""
-        message_ttl = data_utils.\
-            rand_int_id(start=60, end=CONF.messaging.max_message_ttl)
-
-        key = data_utils.arbitrary_string(size=20, base_text='MessagingKey')
-        value = data_utils.arbitrary_string(size=20,
-                                            base_text='MessagingValue')
-        message_body = {key: value}
-
-        rbody = ([{'body': message_body, 'ttl': message_ttl}] * repeat)
-        return rbody
diff --git a/tempest/api/messaging/test_claims.py b/tempest/api/messaging/test_claims.py
deleted file mode 100644
index 99edde1..0000000
--- a/tempest/api/messaging/test_claims.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright (c) 2014 Rackspace, Inc.
-#
-# 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 six.moves.urllib import parse as urlparse
-from tempest_lib import decorators
-
-from tempest.api.messaging import base
-from tempest.common.utils import data_utils
-from tempest import config
-from tempest import test
-
-
-CONF = config.CONF
-
-
-class TestClaims(base.BaseMessagingTest):
-
-    @classmethod
-    def resource_setup(cls):
-        super(TestClaims, cls).resource_setup()
-        cls.queue_name = data_utils.rand_name('Queues-Test')
-        # Create Queue
-        cls.create_queue(cls.queue_name)
-
-    def _post_and_claim_messages(self, queue_name, repeat=1):
-        # Post Messages
-        message_body = self.generate_message_body(repeat=repeat)
-        self.client.post_messages(queue_name=self.queue_name,
-                                  rbody=message_body)
-
-        # Post Claim
-        claim_ttl = data_utils.rand_int_id(start=60,
-                                           end=CONF.messaging.max_claim_ttl)
-        claim_grace = data_utils.\
-            rand_int_id(start=60, end=CONF.messaging.max_claim_grace)
-        claim_body = {"ttl": claim_ttl, "grace": claim_grace}
-        resp, body = self.client.post_claims(queue_name=self.queue_name,
-                                             rbody=claim_body)
-
-        return resp, body
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('936cb1ca-b7af-44dd-a752-805e8c98156f')
-    def test_post_claim(self):
-        _, body = self._post_and_claim_messages(queue_name=self.queue_name)
-        claimed_message_uri = body[0]['href']
-
-        # Skipping this step till bug-1331517  is fixed
-        # Get posted claim
-        # self.client.query_claim(claimed_message_uri)
-
-        # Delete Claimed message
-        self.client.delete_messages(claimed_message_uri)
-
-    @decorators.skip_because(bug="1331517")
-    @test.attr(type='smoke')
-    @test.idempotent_id('84e491f4-68c6-451f-9846-b8f868eb27c5')
-    def test_query_claim(self):
-        # Post a Claim
-        resp, body = self._post_and_claim_messages(queue_name=self.queue_name)
-
-        # Query Claim
-        claim_uri = resp['location']
-        self.client.query_claim(claim_uri)
-
-        # Delete Claimed message
-        claimed_message_uri = body[0]['href']
-        self.delete_messages(claimed_message_uri)
-
-    @decorators.skip_because(bug="1328111")
-    @test.attr(type='smoke')
-    @test.idempotent_id('420ef0c5-9bd6-4b82-b06d-d9da330fefd3')
-    def test_update_claim(self):
-        # Post a Claim
-        resp, body = self._post_and_claim_messages(queue_name=self.queue_name)
-
-        claim_uri = resp['location']
-        claimed_message_uri = body[0]['href']
-
-        # Update Claim
-        claim_ttl = data_utils.rand_int_id(start=60,
-                                           end=CONF.messaging.max_claim_ttl)
-        update_rbody = {"ttl": claim_ttl}
-
-        self.client.update_claim(claim_uri, rbody=update_rbody)
-
-        # Verify claim ttl >= updated ttl value
-        _, body = self.client.query_claim(claim_uri)
-        updated_claim_ttl = body["ttl"]
-        self.assertTrue(updated_claim_ttl >= claim_ttl)
-
-        # Delete Claimed message
-        self.client.delete_messages(claimed_message_uri)
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('fd4c7921-cb3f-4ed8-9ac8-e8f1e74c44aa')
-    def test_release_claim(self):
-        # Post a Claim
-        resp, body = self._post_and_claim_messages(queue_name=self.queue_name)
-        claim_uri = resp['location']
-
-        # Release Claim
-        self.client.delete_claim(claim_uri)
-
-        # Delete Claimed message
-        # This will implicitly verify that the claim is deleted.
-        message_uri = urlparse.urlparse(claim_uri).path
-        self.client.delete_messages(message_uri)
-
-    @classmethod
-    def resource_cleanup(cls):
-        cls.delete_queue(cls.queue_name)
-        super(TestClaims, cls).resource_cleanup()
diff --git a/tempest/api/messaging/test_messages.py b/tempest/api/messaging/test_messages.py
deleted file mode 100644
index 7f4182a..0000000
--- a/tempest/api/messaging/test_messages.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright (c) 2014 Rackspace, Inc.
-#
-# 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.messaging import base
-from tempest.common.utils import data_utils
-from tempest import config
-from tempest import test
-
-
-CONF = config.CONF
-
-
-class TestMessages(base.BaseMessagingTest):
-
-    @classmethod
-    def resource_setup(cls):
-        super(TestMessages, cls).resource_setup()
-        cls.queue_name = data_utils.rand_name('Queues-Test')
-        # Create Queue
-        cls.client.create_queue(cls.queue_name)
-
-    def _post_messages(self, repeat=CONF.messaging.max_messages_per_page):
-        message_body = self.generate_message_body(repeat=repeat)
-        resp, body = self.post_messages(queue_name=self.queue_name,
-                                        rbody=message_body)
-        return resp, body
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('93867172-a414-4eb3-a639-96e943c516b4')
-    def test_post_messages(self):
-        # Post Messages
-        resp, _ = self._post_messages()
-
-        # Get on the posted messages
-        message_uri = resp['location']
-        resp, _ = self.client.show_multiple_messages(message_uri)
-        # The test has an assertion here, because the response cannot be 204
-        # in this case (the client allows 200 or 204 for this API call).
-        self.assertEqual('200', resp['status'])
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('c967d59a-e919-41cb-994b-1c4300452c80')
-    def test_list_messages(self):
-        # Post Messages
-        self._post_messages()
-
-        # List Messages
-        resp, _ = self.list_messages(queue_name=self.queue_name)
-        # The test has an assertion here, because the response cannot be 204
-        # in this case (the client allows 200 or 204 for this API call).
-        self.assertEqual('200', resp['status'])
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('2a68e3de-24df-47c3-9039-ec4156656bf8')
-    def test_get_message(self):
-        # Post Messages
-        _, body = self._post_messages()
-        message_uri = body['resources'][0]
-
-        # Get posted message
-        resp, _ = self.client.show_single_message(message_uri)
-        # The test has an assertion here, because the response cannot be 204
-        # in this case (the client allows 200 or 204 for this API call).
-        self.assertEqual('200', resp['status'])
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('c4b0a30b-efda-4b87-a395-0c43140df74d')
-    def test_get_multiple_messages(self):
-        # Post Messages
-        resp, _ = self._post_messages()
-        message_uri = resp['location']
-
-        # Get posted messages
-        resp, _ = self.client.show_multiple_messages(message_uri)
-        # The test has an assertion here, because the response cannot be 204
-        # in this case (the client allows 200 or 204 for this API call).
-        self.assertEqual('200', resp['status'])
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('fc0fca47-dd8b-4ecc-8522-d9c191f9bc9f')
-    def test_delete_single_message(self):
-        # Post Messages
-        _, body = self._post_messages()
-        message_uri = body['resources'][0]
-
-        # Delete posted message & verify the delete operration
-        self.client.delete_messages(message_uri)
-
-        message_uri = message_uri.replace('/messages/', '/messages?ids=')
-        resp, _ = self.client.show_multiple_messages(message_uri)
-        # The test has an assertion here, because the response has to be 204
-        # in this case (the client allows 200 or 204 for this API call).
-        self.assertEqual('204', resp['status'])
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('00cca069-5c8f-4b42-bff1-c577da2a4546')
-    def test_delete_multiple_messages(self):
-        # Post Messages
-        resp, _ = self._post_messages()
-        message_uri = resp['location']
-
-        # Delete multiple messages
-        self.client.delete_messages(message_uri)
-        resp, _ = self.client.show_multiple_messages(message_uri)
-        # The test has an assertion here, because the response has to be 204
-        # in this case (the client allows 200 or 204 for this API call).
-        self.assertEqual('204', resp['status'])
-
-    @classmethod
-    def resource_cleanup(cls):
-        cls.delete_queue(cls.queue_name)
-        super(TestMessages, cls).resource_cleanup()
diff --git a/tempest/api/messaging/test_queues.py b/tempest/api/messaging/test_queues.py
deleted file mode 100644
index dcb5450..0000000
--- a/tempest/api/messaging/test_queues.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# Copyright (c) 2014 Rackspace, Inc.
-#
-# 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 six import moves
-from tempest_lib import exceptions as lib_exc
-from testtools import matchers
-
-from tempest.api.messaging import base
-from tempest.common.utils import data_utils
-from tempest import test
-
-
-class TestQueues(base.BaseMessagingTest):
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('9f1c4c72-80c5-4dac-acf3-188cef42e36c')
-    def test_create_delete_queue(self):
-        # Create & Delete Queue
-        queue_name = data_utils.rand_name('test')
-        _, body = self.create_queue(queue_name)
-
-        self.addCleanup(self.client.delete_queue, queue_name)
-        # NOTE(gmann): create_queue returns response status code as 201
-        # so specifically checking the expected empty response body as
-        # this is not going to be checked in response_checker().
-        self.assertEqual('', body)
-
-        self.delete_queue(queue_name)
-        self.assertRaises(lib_exc.NotFound,
-                          self.client.show_queue,
-                          queue_name)
-
-
-class TestManageQueue(base.BaseMessagingTest):
-
-    @classmethod
-    def resource_setup(cls):
-        super(TestManageQueue, cls).resource_setup()
-        cls.queues = list()
-        for _ in moves.xrange(5):
-            queue_name = data_utils.rand_name('Queues-Test')
-            cls.queues.append(queue_name)
-            # Create Queue
-            cls.client.create_queue(queue_name)
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('ccd3d69e-f156-4c5f-8a12-b4f24bee44e1')
-    def test_check_queue_existence(self):
-        # Checking Queue Existence
-        for queue_name in self.queues:
-            self.check_queue_exists(queue_name)
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('e27634d8-9c8f-47d8-a677-655c47658d3e')
-    def test_check_queue_head(self):
-        # Checking Queue Existence by calling HEAD
-        for queue_name in self.queues:
-            self.check_queue_exists_head(queue_name)
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('0a0feeca-7768-4303-806d-82bbbb796ad3')
-    def test_list_queues(self):
-        # Listing queues
-        _, body = self.list_queues()
-        self.assertEqual(len(body['queues']), len(self.queues))
-        for item in body['queues']:
-            self.assertIn(item['name'], self.queues)
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('8fb66602-077d-49d6-ae1a-5f2091739178')
-    def test_get_queue_stats(self):
-        # Retrieve random queue
-        queue_name = self.queues[data_utils.rand_int_id(0,
-                                                        len(self.queues) - 1)]
-        # Get Queue Stats for a newly created Queue
-        _, body = self.get_queue_stats(queue_name)
-        msgs = body['messages']
-        for element in ('free', 'claimed', 'total'):
-            self.assertEqual(0, msgs[element])
-        for element in ('oldest', 'newest'):
-            self.assertNotIn(element, msgs)
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('0e2441e6-6593-4bdb-a3c0-20e66eeb3fff')
-    def test_set_and_get_queue_metadata(self):
-        # Retrieve random queue
-        queue_name = self.queues[data_utils.rand_int_id(0,
-                                                        len(self.queues) - 1)]
-        # Check the Queue has no metadata
-        _, body = self.get_queue_metadata(queue_name)
-        self.assertThat(body, matchers.HasLength(0))
-        # Create metadata
-        key3 = [0, 1, 2, 3, 4]
-        key2 = data_utils.rand_name('value')
-        req_body1 = dict()
-        req_body1[data_utils.rand_name('key3')] = key3
-        req_body1[data_utils.rand_name('key2')] = key2
-        req_body = dict()
-        req_body[data_utils.rand_name('key1')] = req_body1
-        # Set Queue Metadata
-        self.set_queue_metadata(queue_name, req_body)
-
-        # Get Queue Metadata
-        _, body = self.get_queue_metadata(queue_name)
-        self.assertThat(body, matchers.Equals(req_body))
-
-    @classmethod
-    def resource_cleanup(cls):
-        for queue_name in cls.queues:
-            cls.client.delete_queue(queue_name)
-        super(TestManageQueue, cls).resource_cleanup()
diff --git a/tempest/api/network/admin/test_external_networks_negative.py b/tempest/api/network/admin/test_external_networks_negative.py
index d031108..57b144a 100644
--- a/tempest/api/network/admin/test_external_networks_negative.py
+++ b/tempest/api/network/admin/test_external_networks_negative.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.network import base
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index 78d6aea..7a4547a 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -74,14 +74,14 @@
         # query and setup steps are only required if the extension is available
         # and only if the router's default type is distributed.
         if test.is_extension_enabled('dvr', 'network'):
-            cls.is_dvr_router = cls.admin_client.show_router(
+            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.client.add_router_interface(cls.router['id'],
-                                                port_id=cls.port['id'])
+                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
@@ -92,15 +92,15 @@
                 external_gateway_info = {
                     'network_id': CONF.network.public_network_id,
                     'enable_snat': True}
-                cls.admin_client.update_router_with_snat_gw_info(
+                cls.admin_routers_client.update_router_with_snat_gw_info(
                     cls.router['id'],
                     external_gateway_info=external_gateway_info)
 
     @classmethod
     def resource_cleanup(cls):
         if cls.is_dvr_router:
-            cls.client.remove_router_interface(cls.router['id'],
-                                               port_id=cls.port['id'])
+            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')
@@ -114,7 +114,8 @@
             self.agent['id'],
             router_id=self.router['id'])
         body = (
-            self.admin_client.list_l3_agents_hosting_router(self.router['id']))
+            self.admin_routers_client.list_l3_agents_hosting_router(
+                self.router['id']))
         for agent in body['agents']:
             l3_agent_ids.append(agent['id'])
             self.assertIn('agent_type', agent)
diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py
index 47da08c..a1a881d 100644
--- a/tempest/api/network/admin/test_negative_quotas.py
+++ b/tempest/api/network/admin/test_negative_quotas.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest.api.network import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 
 
 class QuotasNegativeTest(base.BaseAdminNetworkTest):
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 8b32a94..d72e960 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -17,8 +17,8 @@
 
 from tempest.api.network import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 
 
 class QuotasTest(base.BaseAdminNetworkTest):
diff --git a/tempest/api/network/admin/test_routers_dvr.py b/tempest/api/network/admin/test_routers_dvr.py
index 3e787af..2bc86ad 100644
--- a/tempest/api/network/admin/test_routers_dvr.py
+++ b/tempest/api/network/admin/test_routers_dvr.py
@@ -34,8 +34,8 @@
         # has a distributed attribute.
         super(RoutersTestDVR, cls).resource_setup()
         name = data_utils.rand_name('pretest-check')
-        router = cls.admin_client.create_router(name)
-        cls.admin_client.delete_router(router['router']['id'])
+        router = cls.admin_routers_client.create_router(name)
+        cls.admin_routers_client.delete_router(router['router']['id'])
         if 'distributed' not in router['router']:
             msg = "'distributed' flag not found. DVR Possibly not enabled"
             raise cls.skipException(msg)
@@ -53,8 +53,9 @@
         set to True
         """
         name = data_utils.rand_name('router')
-        router = self.admin_client.create_router(name, distributed=True)
-        self.addCleanup(self.admin_client.delete_router,
+        router = self.admin_routers_client.create_router(name,
+                                                         distributed=True)
+        self.addCleanup(self.admin_routers_client.delete_router,
                         router['router']['id'])
         self.assertTrue(router['router']['distributed'])
 
@@ -72,8 +73,9 @@
         as opposed to a "Distributed Virtual Router"
         """
         name = data_utils.rand_name('router')
-        router = self.admin_client.create_router(name, distributed=False)
-        self.addCleanup(self.admin_client.delete_router,
+        router = self.admin_routers_client.create_router(name,
+                                                         distributed=False)
+        self.addCleanup(self.admin_routers_client.delete_router,
                         router['router']['id'])
         self.assertFalse(router['router']['distributed'])
 
@@ -93,11 +95,12 @@
         """
         name = data_utils.rand_name('router')
         # router needs to be in admin state down in order to be upgraded to DVR
-        router = self.admin_client.create_router(name, distributed=False,
-                                                 admin_state_up=False)
-        self.addCleanup(self.admin_client.delete_router,
+        router = self.admin_routers_client.create_router(name,
+                                                         distributed=False,
+                                                         admin_state_up=False)
+        self.addCleanup(self.admin_routers_client.delete_router,
                         router['router']['id'])
         self.assertFalse(router['router']['distributed'])
-        router = self.admin_client.update_router(router['router']['id'],
-                                                 distributed=True)
+        router = self.admin_routers_client.update_router(
+            router['router']['id'], distributed=True)
         self.assertTrue(router['router']['distributed'])
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index f209f89..8e0c361 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -14,11 +14,11 @@
 #    under the License.
 
 import netaddr
-from tempest_lib import exceptions as lib_exc
 
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
+from tempest.lib import exceptions as lib_exc
 import tempest.test
 
 CONF = config.CONF
@@ -71,6 +71,7 @@
         cls.agents_client = cls.os.network_agents_client
         cls.network_extensions_client = cls.os.network_extensions_client
         cls.networks_client = cls.os.networks_client
+        cls.routers_client = cls.os.routers_client
         cls.subnetpools_client = cls.os.subnetpools_client
         cls.subnets_client = cls.os.subnets_client
         cls.ports_client = cls.os.ports_client
@@ -231,7 +232,7 @@
             ext_gw_info['network_id'] = external_network_id
         if enable_snat is not None:
             ext_gw_info['enable_snat'] = enable_snat
-        body = cls.client.create_router(
+        body = cls.routers_client.create_router(
             router_name, external_gateway_info=ext_gw_info,
             admin_state_up=admin_state_up, **kwargs)
         router = body['router']
@@ -250,8 +251,8 @@
     @classmethod
     def create_router_interface(cls, router_id, subnet_id):
         """Wrapper utility that returns a router interface."""
-        interface = cls.client.add_router_interface(router_id,
-                                                    subnet_id=subnet_id)
+        interface = cls.routers_client.add_router_interface(
+            router_id, subnet_id=subnet_id)
         return interface
 
     @classmethod
@@ -260,12 +261,12 @@
         interfaces = body['ports']
         for i in interfaces:
             try:
-                cls.client.remove_router_interface(
+                cls.routers_client.remove_router_interface(
                     router['id'],
                     subnet_id=i['fixed_ips'][0]['subnet_id'])
             except lib_exc.NotFound:
                 pass
-        cls.client.delete_router(router['id'])
+        cls.routers_client.delete_router(router['id'])
 
 
 class BaseAdminNetworkTest(BaseNetworkTest):
@@ -278,6 +279,7 @@
         cls.admin_client = cls.os_adm.network_client
         cls.admin_agents_client = cls.os_adm.network_agents_client
         cls.admin_networks_client = cls.os_adm.networks_client
+        cls.admin_routers_client = cls.os_adm.routers_client
         cls.admin_subnets_client = cls.os_adm.subnets_client
         cls.admin_ports_client = cls.os_adm.ports_client
         cls.admin_quotas_client = cls.os_adm.network_quotas_client
diff --git a/tempest/api/network/base_routers.py b/tempest/api/network/base_routers.py
index 3495b76f..807257f 100644
--- a/tempest/api/network/base_routers.py
+++ b/tempest/api/network/base_routers.py
@@ -33,31 +33,31 @@
         self.addCleanup(self._cleanup_router, router)
         return router
 
-    def _delete_router(self, router_id, network_client=None):
-        client = network_client or self.client
+    def _delete_router(self, router_id, routers_client=None):
+        client = routers_client or self.routers_client
         client.delete_router(router_id)
         # Asserting that the router is not found in the list
         # after deletion
-        list_body = self.client.list_routers()
+        list_body = self.routers_client.list_routers()
         routers_list = list()
         for router in list_body['routers']:
             routers_list.append(router['id'])
         self.assertNotIn(router_id, routers_list)
 
     def _add_router_interface_with_subnet_id(self, router_id, subnet_id):
-        interface = self.client.add_router_interface(router_id,
-                                                     subnet_id=subnet_id)
+        interface = self.routers_client.add_router_interface(
+            router_id, subnet_id=subnet_id)
         self.addCleanup(self._remove_router_interface_with_subnet_id,
                         router_id, subnet_id)
         self.assertEqual(subnet_id, interface['subnet_id'])
         return interface
 
     def _remove_router_interface_with_subnet_id(self, router_id, subnet_id):
-        body = self.client.remove_router_interface(router_id,
-                                                   subnet_id=subnet_id)
+        body = self.routers_client.remove_router_interface(router_id,
+                                                           subnet_id=subnet_id)
         self.assertEqual(subnet_id, body['subnet_id'])
 
     def _remove_router_interface_with_port_id(self, router_id, port_id):
-        body = self.client.remove_router_interface(router_id,
-                                                   port_id=port_id)
+        body = self.routers_client.remove_router_interface(router_id,
+                                                           port_id=port_id)
         self.assertEqual(port_id, body['port_id'])
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index dbb0d14..fbed5e8 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -17,11 +17,11 @@
 import random
 
 import six
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.network import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
@@ -66,10 +66,10 @@
         body = self.ports_client.list_ports()
         ports = body['ports']
         for port in ports:
-            if (port['device_owner'].startswith('network:router_interface')
-                and port['device_id'] in [r['id'] for r in self.routers]):
-                self.client.remove_router_interface(port['device_id'],
-                                                    port_id=port['id'])
+            if (port['device_owner'].startswith('network:router_interface') and
+                port['device_id'] in [r['id'] for r in self.routers]):
+                self.routers_client.remove_router_interface(port['device_id'],
+                                                            port_id=port['id'])
             else:
                 if port['id'] in [p['id'] for p in self.ports]:
                     self.ports_client.delete_port(port['id'])
@@ -80,11 +80,11 @@
             if subnet['id'] in [s['id'] for s in self.subnets]:
                 self.subnets_client.delete_subnet(subnet['id'])
                 self._remove_from_list_by_index(self.subnets, subnet)
-        body = self.client.list_routers()
+        body = self.routers_client.list_routers()
         routers = body['routers']
         for router in routers:
             if router['id'] in [r['id'] for r in self.routers]:
-                self.client.delete_router(router['id'])
+                self.routers_client.delete_router(router['id'])
                 self._remove_from_list_by_index(self.routers, router)
 
     def _get_ips_from_subnet(self, **kwargs):
diff --git a/tempest/api/network/test_floating_ips_negative.py b/tempest/api/network/test_floating_ips_negative.py
index f915615..963d99d 100644
--- a/tempest/api/network/test_floating_ips_negative.py
+++ b/tempest/api/network/test_floating_ips_negative.py
@@ -14,11 +14,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.network import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 1c446ef..a31a4f0 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -16,12 +16,12 @@
 
 import netaddr
 import six
-from tempest_lib import exceptions as lib_exc
 
 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 import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
@@ -451,7 +451,7 @@
         # Creates 2 networks in one request
         network_list = [{'name': data_utils.rand_name('network-')},
                         {'name': data_utils.rand_name('network-')}]
-        body = self.client.create_bulk_network(networks=network_list)
+        body = self.networks_client.create_bulk_networks(networks=network_list)
         created_networks = body['networks']
         self.addCleanup(self._delete_networks, created_networks)
         # Asserting that the networks are found in the list after creation
@@ -486,7 +486,7 @@
             }
             subnets_list.append(p1)
         del subnets_list[1]['name']
-        body = self.client.create_bulk_subnet(subnets=subnets_list)
+        body = self.subnets_client.create_bulk_subnets(subnets=subnets_list)
         created_subnets = body['subnets']
         self.addCleanup(self._delete_subnets, created_subnets)
         # Asserting that the subnets are found in the list after creation
@@ -512,7 +512,7 @@
             }
             port_list.append(p1)
         del port_list[1]['name']
-        body = self.client.create_bulk_port(ports=port_list)
+        body = self.ports_client.create_bulk_ports(ports=port_list)
         created_ports = body['ports']
         self.addCleanup(self._delete_ports, created_ports)
         # Asserting that the ports are found in the list after creation
diff --git a/tempest/api/network/test_networks_negative.py b/tempest/api/network/test_networks_negative.py
index 0ef96a6..d87c2b6 100644
--- a/tempest/api/network/test_networks_negative.py
+++ b/tempest/api/network/test_networks_negative.py
@@ -14,10 +14,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.network import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index d7b220b..5ff23c6 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -75,7 +75,7 @@
         network2 = self.create_network(network_name=name)
         network_list = [network1['id'], network2['id']]
         port_list = [{'network_id': net_id} for net_id in network_list]
-        body = self.client.create_bulk_port(ports=port_list)
+        body = self.ports_client.create_bulk_ports(ports=port_list)
         created_ports = body['ports']
         port1 = created_ports[0]
         port2 = created_ports[1]
@@ -197,13 +197,13 @@
         subnet = self.create_subnet(network)
         self.addCleanup(self.subnets_client.delete_subnet, subnet['id'])
         router = self.create_router(data_utils.rand_name('router-'))
-        self.addCleanup(self.client.delete_router, router['id'])
+        self.addCleanup(self.routers_client.delete_router, router['id'])
         port = self.ports_client.create_port(network_id=network['id'])
         # Add router interface to port created above
-        self.client.add_router_interface(router['id'],
-                                         port_id=port['port']['id'])
-        self.addCleanup(self.client.remove_router_interface, router['id'],
-                        port_id=port['port']['id'])
+        self.routers_client.add_router_interface(router['id'],
+                                                 port_id=port['port']['id'])
+        self.addCleanup(self.routers_client.remove_router_interface,
+                        router['id'], port_id=port['port']['id'])
         # List ports filtered by router_id
         port_list = self.ports_client.list_ports(device_id=router['id'])
         ports = port_list['ports']
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 0b64be4..01afc51 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -52,7 +52,7 @@
         # NOTE(salv-orlando): Do not invoke self.create_router
         # as we need to check the response code
         name = data_utils.rand_name('router-')
-        create_body = self.client.create_router(
+        create_body = self.routers_client.create_router(
             name, external_gateway_info={
                 "network_id": CONF.network.public_network_id},
             admin_state_up=False)
@@ -63,24 +63,25 @@
             CONF.network.public_network_id)
         self.assertEqual(create_body['router']['admin_state_up'], False)
         # Show details of the created router
-        show_body = self.client.show_router(create_body['router']['id'])
+        show_body = self.routers_client.show_router(
+            create_body['router']['id'])
         self.assertEqual(show_body['router']['name'], name)
         self.assertEqual(
             show_body['router']['external_gateway_info']['network_id'],
             CONF.network.public_network_id)
         self.assertEqual(show_body['router']['admin_state_up'], False)
         # List routers and verify if created router is there in response
-        list_body = self.client.list_routers()
+        list_body = self.routers_client.list_routers()
         routers_list = list()
         for router in list_body['routers']:
             routers_list.append(router['id'])
         self.assertIn(create_body['router']['id'], routers_list)
         # Update the name of router and verify if it is updated
         updated_name = 'updated ' + name
-        update_body = self.client.update_router(create_body['router']['id'],
-                                                name=updated_name)
+        update_body = self.routers_client.update_router(
+            create_body['router']['id'], name=updated_name)
         self.assertEqual(update_body['router']['name'], updated_name)
-        show_body = self.client.show_router(
+        show_body = self.routers_client.show_router(
             create_body['router']['id'])
         self.assertEqual(show_body['router']['name'], updated_name)
 
@@ -95,9 +96,9 @@
         self.addCleanup(self.identity_utils.delete_project, project_id)
 
         name = data_utils.rand_name('router-')
-        create_body = self.admin_client.create_router(name,
-                                                      tenant_id=project_id)
-        self.addCleanup(self.admin_client.delete_router,
+        create_body = self.admin_routers_client.create_router(
+            name, tenant_id=project_id)
+        self.addCleanup(self.admin_routers_client.delete_router,
                         create_body['router']['id'])
         self.assertEqual(project_id, create_body['router']['tenant_id'])
 
@@ -122,9 +123,9 @@
             external_gateway_info = {
                 'network_id': CONF.network.public_network_id,
                 'enable_snat': enable_snat}
-            create_body = self.admin_client.create_router(
+            create_body = self.admin_routers_client.create_router(
                 name, external_gateway_info=external_gateway_info)
-            self.addCleanup(self.admin_client.delete_router,
+            self.addCleanup(self.admin_routers_client.delete_router,
                             create_body['router']['id'])
             # Verify snat attributes after router creation
             self._verify_router_gateway(create_body['router']['id'],
@@ -137,8 +138,8 @@
         subnet = self.create_subnet(network)
         router = self._create_router(data_utils.rand_name('router-'))
         # Add router interface with subnet id
-        interface = self.client.add_router_interface(router['id'],
-                                                     subnet_id=subnet['id'])
+        interface = self.routers_client.add_router_interface(
+            router['id'], subnet_id=subnet['id'])
         self.addCleanup(self._remove_router_interface_with_subnet_id,
                         router['id'], subnet['id'])
         self.assertIn('subnet_id', interface.keys())
@@ -158,7 +159,7 @@
         port_body = self.ports_client.create_port(
             network_id=network['id'])
         # add router interface to port created above
-        interface = self.client.add_router_interface(
+        interface = self.routers_client.add_router_interface(
             router['id'],
             port_id=port_body['port']['id'])
         self.addCleanup(self._remove_router_interface_with_port_id,
@@ -172,7 +173,7 @@
                          router['id'])
 
     def _verify_router_gateway(self, router_id, exp_ext_gw_info=None):
-        show_body = self.admin_client.show_router(router_id)
+        show_body = self.admin_routers_client.show_router(router_id)
         actual_ext_gw_info = show_body['router']['external_gateway_info']
         if exp_ext_gw_info is None:
             self.assertIsNone(actual_ext_gw_info)
@@ -198,7 +199,7 @@
     @test.idempotent_id('6cc285d8-46bf-4f36-9b1a-783e3008ba79')
     def test_update_router_set_gateway(self):
         router = self._create_router(data_utils.rand_name('router-'))
-        self.client.update_router(
+        self.routers_client.update_router(
             router['id'],
             external_gateway_info={
                 'network_id': CONF.network.public_network_id})
@@ -212,7 +213,7 @@
     @test.requires_ext(extension='ext-gw-mode', service='network')
     def test_update_router_set_gateway_with_snat_explicit(self):
         router = self._create_router(data_utils.rand_name('router-'))
-        self.admin_client.update_router_with_snat_gw_info(
+        self.admin_routers_client.update_router_with_snat_gw_info(
             router['id'],
             external_gateway_info={
                 'network_id': CONF.network.public_network_id,
@@ -227,7 +228,7 @@
     @test.requires_ext(extension='ext-gw-mode', service='network')
     def test_update_router_set_gateway_without_snat(self):
         router = self._create_router(data_utils.rand_name('router-'))
-        self.admin_client.update_router_with_snat_gw_info(
+        self.admin_routers_client.update_router_with_snat_gw_info(
             router['id'],
             external_gateway_info={
                 'network_id': CONF.network.public_network_id,
@@ -243,7 +244,8 @@
         router = self._create_router(
             data_utils.rand_name('router-'),
             external_network_id=CONF.network.public_network_id)
-        self.client.update_router(router['id'], external_gateway_info={})
+        self.routers_client.update_router(router['id'],
+                                          external_gateway_info={})
         self._verify_router_gateway(router['id'])
         # No gateway port expected
         list_body = self.admin_ports_client.list_ports(
@@ -257,7 +259,7 @@
         router = self._create_router(
             data_utils.rand_name('router-'),
             external_network_id=CONF.network.public_network_id)
-        self.admin_client.update_router_with_snat_gw_info(
+        self.admin_routers_client.update_router_with_snat_gw_info(
             router['id'],
             external_gateway_info={
                 'network_id': CONF.network.public_network_id,
@@ -270,7 +272,7 @@
 
     @test.idempotent_id('c86ac3a8-50bd-4b00-a6b8-62af84a0765c')
     @test.requires_ext(extension='extraroute', service='network')
-    def test_update_extra_route(self):
+    def test_update_delete_extra_route(self):
         # Create different cidr for each subnet to avoid cidr duplicate
         # The cidr starts from tenant_cidr
         next_cidr = netaddr.IPNetwork(self.tenant_cidr)
@@ -301,9 +303,9 @@
             )
 
         test_routes.sort(key=lambda x: x['destination'])
-        extra_route = self.client.update_extra_routes(router['id'],
-                                                      routes=test_routes)
-        show_body = self.client.show_router(router['id'])
+        extra_route = self.routers_client.update_extra_routes(
+            router['id'], routes=test_routes)
+        show_body = self.routers_client.show_router(router['id'])
         # Assert the number of routes
         self.assertEqual(routes_num, len(extra_route['router']['routes']))
         self.assertEqual(routes_num, len(show_body['router']['routes']))
@@ -323,18 +325,23 @@
                              routes[i]['destination'])
             self.assertEqual(test_routes[i]['nexthop'], routes[i]['nexthop'])
 
+        self.routers_client.delete_extra_routes(router['id'])
+        show_body_after_deletion = self.routers_client.show_router(
+            router['id'])
+        self.assertEmpty(show_body_after_deletion['router']['routes'])
+
     def _delete_extra_routes(self, router_id):
-        self.client.delete_extra_routes(router_id)
+        self.routers_client.delete_extra_routes(router_id)
 
     @test.idempotent_id('a8902683-c788-4246-95c7-ad9c6d63a4d9')
     def test_update_router_admin_state(self):
         router = self._create_router(data_utils.rand_name('router-'))
         self.assertFalse(router['admin_state_up'])
         # Update router admin state
-        update_body = self.client.update_router(router['id'],
-                                                admin_state_up=True)
+        update_body = self.routers_client.update_router(router['id'],
+                                                        admin_state_up=True)
         self.assertTrue(update_body['router']['admin_state_up'])
-        show_body = self.client.show_router(router['id'])
+        show_body = self.routers_client.show_router(router['id'])
         self.assertTrue(show_body['router']['admin_state_up'])
 
     @test.attr(type='smoke')
@@ -381,21 +388,21 @@
     @test.idempotent_id('141297aa-3424-455d-aa8d-f2d95731e00a')
     def test_create_distributed_router(self):
         name = data_utils.rand_name('router')
-        create_body = self.admin_client.create_router(
+        create_body = self.admin_routers_client.create_router(
             name, distributed=True)
         self.addCleanup(self._delete_router,
                         create_body['router']['id'],
-                        self.admin_client)
+                        self.admin_routers_client)
         self.assertTrue(create_body['router']['distributed'])
 
     @test.idempotent_id('644d7a4a-01a1-4b68-bb8d-0c0042cb1729')
     def test_convert_centralized_router(self):
         router = self._create_router(data_utils.rand_name('router'))
         self.assertNotIn('distributed', router)
-        update_body = self.admin_client.update_router(router['id'],
-                                                      distributed=True)
+        update_body = self.admin_routers_client.update_router(router['id'],
+                                                              distributed=True)
         self.assertTrue(update_body['router']['distributed'])
-        show_body = self.admin_client.show_router(router['id'])
+        show_body = self.admin_routers_client.show_router(router['id'])
         self.assertTrue(show_body['router']['distributed'])
-        show_body = self.client.show_router(router['id'])
+        show_body = self.routers_client.show_router(router['id'])
         self.assertNotIn('distributed', show_body['router'])
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index 7b07d42..36aaf2d 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -14,11 +14,11 @@
 #    under the License.
 
 import netaddr
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.network import base_routers as base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
@@ -47,7 +47,7 @@
     @test.idempotent_id('37a94fc0-a834-45b9-bd23-9a81d2fd1e22')
     def test_router_add_gateway_invalid_network_returns_404(self):
         self.assertRaises(lib_exc.NotFound,
-                          self.client.update_router,
+                          self.routers_client.update_router,
                           self.router['id'],
                           external_gateway_info={
                               'network_id': self.router['id']})
@@ -60,7 +60,7 @@
         sub_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
         self.create_subnet(alt_network, cidr=sub_cidr)
         self.assertRaises(lib_exc.BadRequest,
-                          self.client.update_router,
+                          self.routers_client.update_router,
                           self.router['id'],
                           external_gateway_info={
                               'network_id': alt_network['id']})
@@ -84,31 +84,31 @@
     @test.attr(type=['negative'])
     @test.idempotent_id('04df80f9-224d-47f5-837a-bf23e33d1c20')
     def test_router_remove_interface_in_use_returns_409(self):
-        self.client.add_router_interface(self.router['id'],
-                                         subnet_id=self.subnet['id'])
+        self.routers_client.add_router_interface(self.router['id'],
+                                                 subnet_id=self.subnet['id'])
         self.assertRaises(lib_exc.Conflict,
-                          self.client.delete_router,
+                          self.routers_client.delete_router,
                           self.router['id'])
 
     @test.attr(type=['negative'])
     @test.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.client.show_router,
+        self.assertRaises(lib_exc.NotFound, self.routers_client.show_router,
                           router)
 
     @test.attr(type=['negative'])
     @test.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.client.update_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')
     def test_delete_non_existent_router_returns_404(self):
         router = data_utils.rand_name('non_exist_router')
-        self.assertRaises(lib_exc.NotFound, self.client.delete_router,
+        self.assertRaises(lib_exc.NotFound, self.routers_client.delete_router,
                           router)
 
 
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index ff38e9e..5213c18 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -15,10 +15,9 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.network import base_security_groups as base
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/network/test_service_type_management.py b/tempest/api/network/test_service_type_management.py
index ad1ecc4..f49f082 100644
--- a/tempest/api/network/test_service_type_management.py
+++ b/tempest/api/network/test_service_type_management.py
@@ -10,9 +10,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import decorators
-
 from tempest.api.network import base
+from tempest.lib import decorators
 from tempest import test
 
 
diff --git a/tempest/api/network/test_subnetpools_extensions.py b/tempest/api/network/test_subnetpools_extensions.py
index e5d0462..c6cc8e2 100644
--- a/tempest/api/network/test_subnetpools_extensions.py
+++ b/tempest/api/network/test_subnetpools_extensions.py
@@ -15,8 +15,8 @@
 from tempest.api.network import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 
 CONF = config.CONF
 
@@ -30,7 +30,7 @@
         Lists subnet pool.
         Show subnet pool details.
 
-    v2.0 of the Neutron API is assumed. It is assumed that subnetpools
+    v2.0 of the Neutron API is assumed. It is assumed that subnet_allocation
     options mentioned in the [network-feature-enabled] section and
     default_network option mentioned in the [network] section of
     etc/tempest.conf:
@@ -40,8 +40,8 @@
     @classmethod
     def skip_checks(cls):
         super(SubnetPoolsTestJSON, cls).skip_checks()
-        if not test.is_extension_enabled('subnetpools', 'network'):
-            msg = "subnet pools extension not enabled."
+        if not test.is_extension_enabled('subnet_allocation', 'network'):
+            msg = "subnet_allocation extension not enabled."
             raise cls.skipException(msg)
 
     @test.attr(type='smoke')
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 2621581..044e8c1 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.common import custom_matchers
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 import tempest.test
 
 CONF = config.CONF
diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py
index aee17d3..546bb06 100644
--- a/tempest/api/object_storage/test_account_quotas_negative.py
+++ b/tempest/api/object_storage/test_account_quotas_negative.py
@@ -12,12 +12,11 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-from tempest_lib import decorators
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/object_storage/test_account_services_negative.py b/tempest/api/object_storage/test_account_services_negative.py
index 998c2bd..254a9b3 100644
--- a/tempest/api/object_storage/test_account_services_negative.py
+++ b/tempest/api/object_storage/test_account_services_negative.py
@@ -12,10 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.object_storage import base
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index 3bb47f0..0055bf9 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -12,11 +12,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py
index 896352b..01e5389 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -13,11 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 1cc9437..9d043e5 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -13,9 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib.common.utils import data_utils
-
 from tempest.api.object_storage import base
+from tempest.lib.common.utils import data_utils
 from tempest import test
 
 
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 18593f3..5b3ce79 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -12,11 +12,10 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index 0e39b7e..2a5cec6 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -16,13 +16,13 @@
 import time
 
 from six.moves.urllib import parse as urlparse
-from tempest_lib import decorators
 import testtools
 
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index 1c9d582..9db8bde 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -13,11 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
 import time
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/object_storage/test_object_formpost_negative.py b/tempest/api/object_storage/test_object_formpost_negative.py
index 7d9e115..cb13271 100644
--- a/tempest/api/object_storage/test_object_formpost_negative.py
+++ b/tempest/api/object_storage/test_object_formpost_negative.py
@@ -17,10 +17,10 @@
 import time
 
 from six.moves.urllib import parse as urlparse
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index 5811cb8..752f0b4 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -15,11 +15,11 @@
 import hashlib
 
 from oslo_serialization import jsonutils as json
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 # Each segment, except for the final one, must be at least 1 megabyte
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 6d06143..38fe697 100644
--- a/tempest/api/object_storage/test_object_temp_url_negative.py
+++ b/tempest/api/object_storage/test_object_temp_url_negative.py
@@ -17,10 +17,10 @@
 import time
 
 from six.moves.urllib import parse as urlparse
-from tempest_lib import exceptions as lib_exc
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index c93b5ed..26ace81 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -12,11 +12,11 @@
 
 import os.path
 
-from tempest_lib import exceptions as lib_exc
 import yaml
 
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 import tempest.test
 
 CONF = config.CONF
diff --git a/tempest/api/orchestration/stacks/templates/cinder_basic.yaml b/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
index ffff580..61c271c 100644
--- a/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
+++ b/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
@@ -1,10 +1,15 @@
 heat_template_version: 2013-05-23
 
+parameters:
+  volume_size:
+    type: number
+    default: 1
+
 resources:
     volume:
         type: OS::Cinder::Volume
         properties:
-            size: 1
+            size: { get_param: volume_size }
             description: a descriptive description
             name: volume_name
 
diff --git a/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml b/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
index b660c19..0bc6d69 100644
--- a/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
+++ b/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
@@ -1,11 +1,16 @@
 heat_template_version: 2013-05-23
 
+parameters:
+  volume_size:
+    type: number
+    default: 1
+
 resources:
     volume:
         deletion_policy: 'Retain'
         type: OS::Cinder::Volume
         properties:
-            size: 1
+            size: { get_param: volume_size }
             description: a descriptive description
             name: volume_name
 
diff --git a/tempest/api/orchestration/stacks/test_limits.py b/tempest/api/orchestration/stacks/test_limits.py
index 2acf97b..d85aa96 100644
--- a/tempest/api/orchestration/stacks/test_limits.py
+++ b/tempest/api/orchestration/stacks/test_limits.py
@@ -10,11 +10,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
@@ -33,7 +32,7 @@
   Foo: bar''' % fill
         ex = self.assertRaises(lib_exc.BadRequest, self.create_stack,
                                stack_name, template)
-        self.assertIn('Template exceeds maximum allowed size', str(ex))
+        self.assertIn('exceeds maximum allowed size', str(ex))
 
     @test.idempotent_id('d1b83e73-7cad-4a22-9839-036548c5387c')
     def test_exceed_max_resources_per_stack(self):
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index 09e863e..5483361 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -30,6 +30,8 @@
 
     @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")
@@ -149,7 +151,7 @@
     def test_created_router(self):
         """Verifies created router."""
         router_id = self.test_resources.get('Router')['physical_resource_id']
-        body = self.network_client.show_router(router_id)
+        body = self.routers_client.show_router(router_id)
         router = body['router']
         self.assertEqual(self.neutron_basic_template['resources'][
             'Router']['properties']['name'], router['name'])
diff --git a/tempest/api/orchestration/stacks/test_soft_conf.py b/tempest/api/orchestration/stacks/test_soft_conf.py
index ab45929..6a4e2b9 100644
--- a/tempest/api/orchestration/stacks/test_soft_conf.py
+++ b/tempest/api/orchestration/stacks/test_soft_conf.py
@@ -10,11 +10,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/orchestration/stacks/test_templates_negative.py b/tempest/api/orchestration/stacks/test_templates_negative.py
index 4bd0f33..24e10dd 100644
--- a/tempest/api/orchestration/stacks/test_templates_negative.py
+++ b/tempest/api/orchestration/stacks/test_templates_negative.py
@@ -12,9 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.orchestration import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/orchestration/stacks/test_volumes.py b/tempest/api/orchestration/stacks/test_volumes.py
index e51551b..a5aaf6e 100644
--- a/tempest/api/orchestration/stacks/test_volumes.py
+++ b/tempest/api/orchestration/stacks/test_volumes.py
@@ -10,11 +10,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.orchestration import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
@@ -33,8 +32,7 @@
         self.assertIsNotNone(volume_id)
         volume = self.volumes_client.show_volume(volume_id)['volume']
         self.assertEqual('available', volume.get('status'))
-        self.assertEqual(template['resources']['volume']['properties'][
-            'size'], volume.get('size'))
+        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:
@@ -52,8 +50,8 @@
     def _outputs_verify(self, stack_identifier, template):
         self.assertEqual('available',
                          self.get_stack_output(stack_identifier, 'status'))
-        self.assertEqual(str(template['resources']['volume']['properties'][
-            'size']), self.get_stack_output(stack_identifier, 'size'))
+        self.assertEqual(str(CONF.volume.volume_size),
+                         self.get_stack_output(stack_identifier, 'size'))
         self.assertEqual(template['resources']['volume']['properties'][
             'description'], self.get_stack_output(stack_identifier,
                                                   'display_description'))
@@ -66,7 +64,12 @@
         """Create and delete a volume via OS::Cinder::Volume."""
         stack_name = data_utils.rand_name('heat')
         template = self.read_template('cinder_basic')
-        stack_identifier = self.create_stack(stack_name, template)
+        stack_identifier = self.create_stack(
+            stack_name,
+            template,
+            parameters={
+                'volume_size': CONF.volume.volume_size
+            })
         self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
 
         # Verify with cinder that the volume exists, with matching details
@@ -95,7 +98,12 @@
         """Ensure the 'Retain' deletion policy is respected."""
         stack_name = data_utils.rand_name('heat')
         template = self.read_template('cinder_basic_delete_retain')
-        stack_identifier = self.create_stack(stack_name, template)
+        stack_identifier = self.create_stack(
+            stack_name,
+            template,
+            parameters={
+                'volume_size': CONF.volume.volume_size
+            })
         self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
 
         # Verify with cinder that the volume exists, with matching details
diff --git a/tempest/api/telemetry/base.py b/tempest/api/telemetry/base.py
index ff06810..7238098 100644
--- a/tempest/api/telemetry/base.py
+++ b/tempest/api/telemetry/base.py
@@ -13,13 +13,13 @@
 import time
 
 from oslo_utils import timeutils
-from tempest_lib import exceptions as lib_exc
 
 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 import exceptions as lib_exc
 import tempest.test
 
 CONF = config.CONF
diff --git a/tempest/api/telemetry/test_alarming_api.py b/tempest/api/telemetry/test_alarming_api.py
index daa0939..586bb42 100644
--- a/tempest/api/telemetry/test_alarming_api.py
+++ b/tempest/api/telemetry/test_alarming_api.py
@@ -10,10 +10,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.telemetry import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/telemetry/test_alarming_api_negative.py b/tempest/api/telemetry/test_alarming_api_negative.py
index e945556..0701b54 100644
--- a/tempest/api/telemetry/test_alarming_api_negative.py
+++ b/tempest/api/telemetry/test_alarming_api_negative.py
@@ -14,8 +14,8 @@
 
 from tempest.api.telemetry import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
-from tempest_lib import exceptions as lib_exc
 
 import uuid
 
diff --git a/tempest/api/telemetry/test_telemetry_notification_api.py b/tempest/api/telemetry/test_telemetry_notification_api.py
index a575125..53d457f 100644
--- a/tempest/api/telemetry/test_telemetry_notification_api.py
+++ b/tempest/api/telemetry/test_telemetry_notification_api.py
@@ -10,11 +10,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import decorators
 import testtools
 
 from tempest.api.telemetry import base
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py
index 9185553..a43ee8e 100644
--- a/tempest/api/volume/admin/test_volume_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_quotas_negative.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.volume import base
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/volume/admin/test_volume_services.py b/tempest/api/volume/admin/test_volume_services.py
index 2b7ee45..755365d 100644
--- a/tempest/api/volume/admin/test_volume_services.py
+++ b/tempest/api/volume/admin/test_volume_services.py
@@ -12,11 +12,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.
-
 from tempest.api.volume import base
+from tempest import config
 from tempest import test
 
 
+CONF = config.CONF
+
+
+def _get_host(host):
+    if CONF.volume_feature_enabled.volume_services:
+        host = host.split('@')[0]
+    return host
+
+
 class VolumesServicesV2TestJSON(base.BaseVolumeAdminTest):
     """Tests Volume Services API.
 
@@ -28,7 +37,10 @@
         super(VolumesServicesV2TestJSON, cls).resource_setup()
         cls.services = (cls.admin_volume_services_client.list_services()
                         ['services'])
-        cls.host_name = cls.services[0]['host']
+        # NOTE: Cinder service-list API returns the list contains
+        # "<host name>@<driver name>" like "nova-compute01@lvmdriver-1".
+        # So here picks <host name> up as a host.
+        cls.host_name = _get_host(cls.services[0]['host'])
         cls.binary_name = cls.services[0]['binary']
 
     @test.idempotent_id('e0218299-0a59-4f43-8b2b-f1c035b3d26d')
@@ -48,7 +60,7 @@
     @test.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
-                            service['host'] == self.host_name]
+                            _get_host(service['host']) == self.host_name]
 
         services = (self.admin_volume_services_client.list_services(
             host=self.host_name)['services'])
@@ -68,7 +80,7 @@
             host=self.host_name, binary=self.binary_name))['services']
 
         self.assertEqual(1, len(services))
-        self.assertEqual(self.host_name, services[0]['host'])
+        self.assertEqual(self.host_name, _get_host(services[0]['host']))
         self.assertEqual(self.binary_name, services[0]['binary'])
 
 
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 c66207f..b7f70ba 100644
--- a/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.volume import base
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
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 6483af3..29ce2e7 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
@@ -15,10 +15,9 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.volume import base
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py
index bc32fc9..bccf20e 100644
--- a/tempest/api/volume/admin/test_volume_types_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_negative.py
@@ -15,9 +15,8 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.volume import base
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index 4b2d3f3..30c6a15 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -13,11 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import decorators
-
 from tempest.api.volume import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index cc906e5..82dc2c9 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -13,12 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.common import compute
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
+from tempest.lib import exceptions as lib_exc
 import tempest.test
 
 CONF = config.CONF
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index ad6f556..1b5e72a 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -15,11 +15,10 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.volume import base
 from tempest.common.utils import data_utils
 from tempest.common import waiters
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 
diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py
index d46c9b5..54459ac 100644
--- a/tempest/api/volume/test_volumes_snapshots_negative.py
+++ b/tempest/api/volume/test_volumes_snapshots_negative.py
@@ -12,11 +12,10 @@
 
 import uuid
 
-from tempest_lib import exceptions as lib_exc
-
 from tempest.api.volume import base
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
diff --git a/tempest/api_schema/response/messaging/__init__.py b/tempest/api_schema/response/messaging/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api_schema/response/messaging/__init__.py
+++ /dev/null
diff --git a/tempest/api_schema/response/messaging/v1/queues.py b/tempest/api_schema/response/messaging/v1/queues.py
deleted file mode 100644
index 09e0147..0000000
--- a/tempest/api_schema/response/messaging/v1/queues.py
+++ /dev/null
@@ -1,239 +0,0 @@
-
-# Copyright (c) 2014 Rackspace, Inc.
-#
-# 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_link = {
-    'type': 'object',
-    'properties': {
-        'rel': {'type': 'string'},
-        'href': {
-            'type': 'string',
-            'format': 'uri'
-        }
-    },
-    'required': ['href', 'rel']
-}
-
-list_queue = {
-    'type': 'object',
-    'properties': {
-        'name': {'type': 'string'},
-        'href': {
-            'type': 'string',
-            'format': 'uri'
-        },
-        'metadata': {'type': 'object'}
-    },
-    'required': ['name', 'href']
-}
-
-list_queues = {
-    'status_code': [200, 204],
-    'response_body': {
-        'type': 'object',
-        'properties': {
-            'links': {
-                'type': 'array',
-                'items': list_link,
-                'maxItems': 1
-            },
-            'queues': {
-                'type': 'array',
-                'items': list_queue
-            }
-        },
-        'required': ['links', 'queues']
-    }
-}
-
-age = {
-    'type': 'number',
-    'minimum': 0
-}
-
-message_link = {
-    'type': 'object',
-    'properties': {
-        'href': {
-            'type': 'string',
-            'format': 'uri'
-        },
-        'age': age,
-        'created': {
-            'type': 'string',
-            'format': 'date-time'
-        }
-    },
-    'required': ['href', 'age', 'created']
-}
-
-messages = {
-    'type': 'object',
-    'properties': {
-        'free': {'type': 'number'},
-        'claimed': {'type': 'number'},
-        'total': {'type': 'number'},
-        'oldest': message_link,
-        'newest': message_link
-    },
-    'required': ['free', 'claimed', 'total']
-}
-
-queue_stats = {
-    'status_code': [200],
-    'response_body': {
-        'type': 'object',
-        'properties': {
-            'messages': messages
-        },
-        'required': ['messages']
-    }
-}
-
-resource_schema = {
-    'type': 'array',
-    'items': {
-        'type': 'string'
-    },
-    'minItems': 1
-}
-
-post_messages = {
-    'status_code': [201],
-    'response_body': {
-        'type': 'object',
-        'properties': {
-            'resources': resource_schema,
-            'partial': {'type': 'boolean'}
-        }
-    },
-    'required': ['resources', 'partial']
-}
-
-message_ttl = {
-    'type': 'number',
-    'minimum': 1
-}
-
-list_messages_links = {
-    'type': 'array',
-    'maxItems': 1,
-    'minItems': 1,
-    'items': {
-        'type': 'object',
-        'properties': {
-            'rel': {'type': 'string'},
-            'href': {'type': 'string'}
-        },
-        'required': ['rel', 'href']
-    }
-}
-
-list_messages_response = {
-    'type': 'array',
-    'minItems': 1,
-    'items': {
-        'type': 'object',
-        'properties': {
-            'href': {'type': 'string'},
-            'ttl': message_ttl,
-            'age': age,
-            'body': {'type': 'object'}
-        },
-        'required': ['href', 'ttl', 'age', 'body']
-    }
-}
-
-list_messages = {
-    'status_code': [200, 204],
-    'response_body': {
-        'type': 'object',
-        'properties': {
-            'links': list_messages_links,
-            'messages': list_messages_response
-        }
-    },
-    'required': ['links', 'messages']
-}
-
-single_message = {
-    'type': 'object',
-    'properties': {
-        'href': {'type': 'string'},
-        'ttl': message_ttl,
-        'age': age,
-        'body': {'type': 'object'}
-    },
-    'required': ['href', 'ttl', 'age', 'body']
-}
-
-get_single_message = {
-    'status_code': [200],
-    'response_body': single_message
-}
-
-get_multiple_messages = {
-    'status_code': [200],
-    'response_body': {
-        'type': 'array',
-        'items': single_message,
-        'minItems': 1
-    }
-}
-
-messages_claimed = {
-    'type': 'object',
-    'properties': {
-        'href': {
-            'type': 'string',
-            'format': 'uri'
-        },
-        'ttl': message_ttl,
-        'age': {'type': 'number'},
-        'body': {'type': 'object'}
-    },
-    'required': ['href', 'ttl', 'age', 'body']
-}
-
-claim_messages = {
-    'status_code': [201, 204],
-    'response_body': {
-        'type': 'array',
-        'items': messages_claimed,
-        'minItems': 1
-    }
-}
-
-claim_ttl = {
-    'type': 'number',
-    'minimum': 1
-}
-
-query_claim = {
-    'status_code': [200],
-    'response_body': {
-        'type': 'object',
-        'properties': {
-            'age': {'type': 'number'},
-            'ttl': claim_ttl,
-            'messages': {
-                'type': 'array',
-                'minItems': 1
-            }
-        },
-        'required': ['ttl', 'age', 'messages']
-    }
-}
diff --git a/tempest/clients.py b/tempest/clients.py
index 2ac5e82..8931706 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -16,80 +16,81 @@
 import copy
 
 from oslo_log import log as logging
-from tempest_lib.services.compute.agents_client import AgentsClient
-from tempest_lib.services.compute.aggregates_client import AggregatesClient
-from tempest_lib.services.compute.availability_zone_client import \
-    AvailabilityZoneClient
-from tempest_lib.services.compute.baremetal_nodes_client import \
-    BaremetalNodesClient
-from tempest_lib.services.compute.certificates_client import \
-    CertificatesClient
-from tempest_lib.services.compute.extensions_client import \
-    ExtensionsClient
-from tempest_lib.services.compute.fixed_ips_client import FixedIPsClient
-from tempest_lib.services.compute.flavors_client import FlavorsClient
-from tempest_lib.services.compute.floating_ip_pools_client import \
-    FloatingIPPoolsClient
-from tempest_lib.services.compute.floating_ips_bulk_client import \
-    FloatingIPsBulkClient
-from tempest_lib.services.compute.floating_ips_client import \
-    FloatingIPsClient as ComputeFloatingIPsClient
-from tempest_lib.services.compute.hosts_client import HostsClient
-from tempest_lib.services.compute.hypervisor_client import \
-    HypervisorClient
-from tempest_lib.services.compute.images_client import ImagesClient \
-    as ComputeImagesClient
-from tempest_lib.services.compute.instance_usage_audit_log_client import \
-    InstanceUsagesAuditLogClient
-from tempest_lib.services.compute.interfaces_client import InterfacesClient
-from tempest_lib.services.compute.limits_client import LimitsClient
-from tempest_lib.services.compute.migrations_client import MigrationsClient
-from tempest_lib.services.compute.networks_client import NetworksClient \
-    as ComputeNetworksClient
-from tempest_lib.services.compute.quota_classes_client import \
-    QuotaClassesClient
-from tempest_lib.services.compute.quotas_client import QuotasClient
-from tempest_lib.services.compute.security_group_default_rules_client import \
-    SecurityGroupDefaultRulesClient
-from tempest_lib.services.compute.security_group_rules_client import \
-    SecurityGroupRulesClient as ComputeSecurityGroupRulesClient
-from tempest_lib.services.compute.security_groups_client import \
-    SecurityGroupsClient as ComputeSecurityGroupsClient
-from tempest_lib.services.compute.server_groups_client import \
-    ServerGroupsClient
-from tempest_lib.services.compute.servers_client import ServersClient
-from tempest_lib.services.compute.services_client import ServicesClient
-from tempest_lib.services.compute.snapshots_client import \
-    SnapshotsClient as ComputeSnapshotsClient
-from tempest_lib.services.compute.tenant_networks_client import \
-    TenantNetworksClient
-from tempest_lib.services.compute.tenant_usages_client import \
-    TenantUsagesClient
-from tempest_lib.services.compute.versions_client import VersionsClient
-from tempest_lib.services.compute.volumes_client import \
-    VolumesClient as ComputeVolumesClient
-from tempest_lib.services.identity.v2.token_client import TokenClient
-from tempest_lib.services.identity.v3.token_client import V3TokenClient
-from tempest_lib.services.network.agents_client import AgentsClient \
-    as NetworkAgentsClient
-from tempest_lib.services.network.extensions_client import \
-    ExtensionsClient as NetworkExtensionsClient
-from tempest_lib.services.network.floating_ips_client import FloatingIPsClient
-from tempest_lib.services.network.metering_label_rules_client import \
-    MeteringLabelRulesClient
-from tempest_lib.services.network.metering_labels_client import \
-    MeteringLabelsClient
-from tempest_lib.services.network.networks_client import NetworksClient
-from tempest_lib.services.network.ports_client import PortsClient
-from tempest_lib.services.network.quotas_client import QuotasClient \
-    as NetworkQuotasClient
-from tempest_lib.services.network.security_groups_client import \
-    SecurityGroupsClient
-from tempest_lib.services.network.subnets_client import SubnetsClient
 
 from tempest.common import negative_rest_client
 from tempest import config
 from tempest import exceptions
+from tempest.lib.services.compute.agents_client import AgentsClient
+from tempest.lib.services.compute.aggregates_client import AggregatesClient
+from tempest.lib.services.compute.availability_zone_client import \
+    AvailabilityZoneClient
+from tempest.lib.services.compute.baremetal_nodes_client import \
+    BaremetalNodesClient
+from tempest.lib.services.compute.certificates_client import \
+    CertificatesClient
+from tempest.lib.services.compute.extensions_client import \
+    ExtensionsClient
+from tempest.lib.services.compute.fixed_ips_client import FixedIPsClient
+from tempest.lib.services.compute.flavors_client import FlavorsClient
+from tempest.lib.services.compute.floating_ip_pools_client import \
+    FloatingIPPoolsClient
+from tempest.lib.services.compute.floating_ips_bulk_client import \
+    FloatingIPsBulkClient
+from tempest.lib.services.compute.floating_ips_client import \
+    FloatingIPsClient as ComputeFloatingIPsClient
+from tempest.lib.services.compute.hosts_client import HostsClient
+from tempest.lib.services.compute.hypervisor_client import \
+    HypervisorClient
+from tempest.lib.services.compute.images_client import ImagesClient \
+    as ComputeImagesClient
+from tempest.lib.services.compute.instance_usage_audit_log_client import \
+    InstanceUsagesAuditLogClient
+from tempest.lib.services.compute.interfaces_client import InterfacesClient
+from tempest.lib.services.compute.limits_client import LimitsClient
+from tempest.lib.services.compute.migrations_client import MigrationsClient
+from tempest.lib.services.compute.networks_client import NetworksClient \
+    as ComputeNetworksClient
+from tempest.lib.services.compute.quota_classes_client import \
+    QuotaClassesClient
+from tempest.lib.services.compute.quotas_client import QuotasClient
+from tempest.lib.services.compute.security_group_default_rules_client import \
+    SecurityGroupDefaultRulesClient
+from tempest.lib.services.compute.security_group_rules_client import \
+    SecurityGroupRulesClient as ComputeSecurityGroupRulesClient
+from tempest.lib.services.compute.security_groups_client import \
+    SecurityGroupsClient as ComputeSecurityGroupsClient
+from tempest.lib.services.compute.server_groups_client import \
+    ServerGroupsClient
+from tempest.lib.services.compute.servers_client import ServersClient
+from tempest.lib.services.compute.services_client import ServicesClient
+from tempest.lib.services.compute.snapshots_client import \
+    SnapshotsClient as ComputeSnapshotsClient
+from tempest.lib.services.compute.tenant_networks_client import \
+    TenantNetworksClient
+from tempest.lib.services.compute.tenant_usages_client import \
+    TenantUsagesClient
+from tempest.lib.services.compute.versions_client import VersionsClient
+from tempest.lib.services.compute.volumes_client import \
+    VolumesClient as ComputeVolumesClient
+from tempest.lib.services.identity.v2.token_client import TokenClient
+from tempest.lib.services.identity.v3.token_client import V3TokenClient
+from tempest.lib.services.network.agents_client import AgentsClient \
+    as NetworkAgentsClient
+from tempest.lib.services.network.extensions_client import \
+    ExtensionsClient as NetworkExtensionsClient
+from tempest.lib.services.network.floating_ips_client import FloatingIPsClient
+from tempest.lib.services.network.metering_label_rules_client import \
+    MeteringLabelRulesClient
+from tempest.lib.services.network.metering_labels_client import \
+    MeteringLabelsClient
+from tempest.lib.services.network.networks_client import NetworksClient
+from tempest.lib.services.network.ports_client import PortsClient
+from tempest.lib.services.network.quotas_client import QuotasClient \
+    as NetworkQuotasClient
+from tempest.lib.services.network.security_groups_client import \
+    SecurityGroupsClient
+from tempest.lib.services.network.subnetpools_client import SubnetpoolsClient
+from tempest.lib.services.network.subnets_client import SubnetsClient
 from tempest import manager
 from tempest.services.baremetal.v1.json.baremetal_client import \
     BaremetalClient
@@ -102,40 +103,37 @@
     DatabaseLimitsClient
 from tempest.services.database.json.versions_client import \
     DatabaseVersionsClient
-from tempest.services.identity.v2.json.endpoints_client import \
-    EndpointsClient as EndpointsV2Client
-from tempest.services.identity.v2.json.identity_client import \
-    IdentityClient
-from tempest.services.identity.v2.json.roles_client import \
-    RolesClient
+from tempest.services.identity.v2.json.endpoints_client import EndpointsClient
+from tempest.services.identity.v2.json.identity_client import IdentityClient
+from tempest.services.identity.v2.json.roles_client import RolesClient
 from tempest.services.identity.v2.json.services_client import \
-    ServicesClient as ServicesV2Client
-from tempest.services.identity.v2.json.tenants_client import \
-    TenantsClient
-from tempest.services.identity.v2.json.users_client import \
-    UsersClient
+    ServicesClient as IdentityServicesClient
+from tempest.services.identity.v2.json.tenants_client import TenantsClient
+from tempest.services.identity.v2.json.users_client import UsersClient
 from tempest.services.identity.v3.json.credentials_client import \
-    CredentialsClient as CredentialsV3Client
+    CredentialsClient
+from tempest.services.identity.v3.json.domains_client import DomainsClient
 from tempest.services.identity.v3.json.endpoints_client import \
-    EndPointClient as EndPointV3Client
-from tempest.services.identity.v3.json.groups_client import \
-    GroupsClient as GroupsV3Client
-from tempest.services.identity.v3.json.identity_client import IdentityV3Client
-from tempest.services.identity.v3.json.policies_client import \
-    PoliciesClient as PoliciesV3Client
+    EndPointsClient as EndPointsV3Client
+from tempest.services.identity.v3.json.groups_client import GroupsClient
+from tempest.services.identity.v3.json.identity_client import \
+    IdentityClient as IdentityV3Client
+from tempest.services.identity.v3.json.policies_client import PoliciesClient
 from tempest.services.identity.v3.json.projects_client import ProjectsClient
-from tempest.services.identity.v3.json.regions_client import \
-    RegionsClient as RegionsV3Client
+from tempest.services.identity.v3.json.regions_client import RegionsClient
+from tempest.services.identity.v3.json.roles_client import \
+    RolesClient as RolesV3Client
 from tempest.services.identity.v3.json.services_client import \
     ServicesClient as IdentityServicesV3Client
+from tempest.services.identity.v3.json.trusts_client import TrustsClient
+from tempest.services.identity.v3.json.users_clients import \
+    UsersClient as UsersV3Client
 from tempest.services.image.v1.json.images_client import ImagesClient
 from tempest.services.image.v2.json.images_client import ImagesClientV2
-from tempest.services.messaging.json.messaging_client import \
-    MessagingClient
 from tempest.services.network.json.network_client import NetworkClient
+from tempest.services.network.json.routers_client import RoutersClient
 from tempest.services.network.json.security_group_rules_client import \
     SecurityGroupRulesClient
-from tempest.services.network.json.subnetpools_client import SubnetpoolsClient
 from tempest.services.object_storage.account_client import AccountClient
 from tempest.services.object_storage.container_client import ContainerClient
 from tempest.services.object_storage.object_client import ObjectClient
@@ -203,30 +201,14 @@
     }
     default_params_with_timeout_values.update(default_params)
 
-    def __init__(self, credentials, service=None, api_microversions=None):
+    def __init__(self, credentials, service=None):
         """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 api_microversions: This is dict of services catalog type
-               and their microversion which will be set on respective
-               services clients.
-               {<service catalog type>: request_microversion}
-               Example :
-                {'compute': request_microversion}
-                    - request_microversion will be set on all compute
-                      service clients.
-                OR
-                {'compute': request_microversion,
-                 'volume': request_microversion}
-                    - request_microversion of compute will be set on all
-                      compute service clients.
-                    - request_microversion of volume will be set on all
-                      volume service clients.
         """
         super(Manager, self).__init__(credentials=credentials)
-        self.api_microversions = api_microversions or {}
         self._set_compute_clients()
         self._set_database_clients()
         self._set_identity_clients()
@@ -327,6 +309,14 @@
             build_interval=CONF.network.build_interval,
             build_timeout=CONF.network.build_timeout,
             **self.default_params)
+        self.routers_client = RoutersClient(
+            self.auth_provider,
+            CONF.network.catalog_type,
+            CONF.network.region or CONF.identity.region,
+            endpoint_type=CONF.network.endpoint_type,
+            build_interval=CONF.network.build_interval,
+            build_timeout=CONF.network.build_timeout,
+            **self.default_params)
         self.security_group_rules_client = SecurityGroupRulesClient(
             self.auth_provider,
             CONF.network.catalog_type,
@@ -343,11 +333,6 @@
             build_interval=CONF.network.build_interval,
             build_timeout=CONF.network.build_timeout,
             **self.default_params)
-        self.messaging_client = MessagingClient(
-            self.auth_provider,
-            CONF.messaging.catalog_type,
-            CONF.identity.region,
-            **self.default_params_with_timeout_values)
         if CONF.service_available.ceilometer:
             self.telemetry_client = TelemetryClient(
                 self.auth_provider,
@@ -396,8 +381,6 @@
         self.negative_client = negative_rest_client.NegativeRestClient(
             self.auth_provider, service, **self.default_params)
 
-        self._set_api_microversions()
-
     def _set_compute_clients(self):
         params = {
             'service': CONF.compute.catalog_type,
@@ -506,18 +489,16 @@
         # Clients below use the admin endpoint type of Keystone API v2
         params_v2_admin = params.copy()
         params_v2_admin['endpoint_type'] = CONF.identity.v2_admin_endpoint_type
-        self.endpoints_v2_client = EndpointsV2Client(self.auth_provider,
-                                                     **params_v2_admin)
+        self.endpoints_client = EndpointsClient(self.auth_provider,
+                                                **params_v2_admin)
         self.identity_client = IdentityClient(self.auth_provider,
                                               **params_v2_admin)
         self.tenants_client = TenantsClient(self.auth_provider,
                                             **params_v2_admin)
-        self.roles_client = RolesClient(self.auth_provider,
-                                        **params_v2_admin)
-        self.users_client = UsersClient(self.auth_provider,
-                                        **params_v2_admin)
-        self.services_v2_client = ServicesV2Client(self.auth_provider,
-                                                   **params_v2_admin)
+        self.roles_client = RolesClient(self.auth_provider, **params_v2_admin)
+        self.users_client = UsersClient(self.auth_provider, **params_v2_admin)
+        self.identity_services_client = IdentityServicesClient(
+            self.auth_provider, **params_v2_admin)
 
         # Clients below use the public endpoint type of Keystone API v2
         params_v2_public = params.copy()
@@ -533,19 +514,23 @@
         # Clients below use the endpoint type of Keystone API v3
         params_v3 = params.copy()
         params_v3['endpoint_type'] = CONF.identity.v3_endpoint_type
+        self.domains_client = DomainsClient(self.auth_provider,
+                                            **params_v3)
         self.identity_v3_client = IdentityV3Client(self.auth_provider,
                                                    **params_v3)
-        self.endpoints_client = EndPointV3Client(self.auth_provider,
-                                                 **params_v3)
-        self.identity_services_client = IdentityServicesV3Client(
+        self.trusts_client = TrustsClient(self.auth_provider, **params_v3)
+        self.users_v3_client = UsersV3Client(self.auth_provider, **params_v3)
+        self.endpoints_v3_client = EndPointsV3Client(self.auth_provider,
+                                                     **params_v3)
+        self.roles_v3_client = RolesV3Client(self.auth_provider, **params_v3)
+        self.identity_services_v3_client = IdentityServicesV3Client(
             self.auth_provider, **params_v3)
-        self.policies_client = PoliciesV3Client(self.auth_provider,
-                                                **params_v3)
+        self.policies_client = PoliciesClient(self.auth_provider, **params_v3)
         self.projects_client = ProjectsClient(self.auth_provider, **params_v3)
-        self.regions_client = RegionsV3Client(self.auth_provider, **params_v3)
-        self.credentials_client = CredentialsV3Client(self.auth_provider,
-                                                      **params_v3)
-        self.groups_client = GroupsV3Client(self.auth_provider, **params_v3)
+        self.regions_client = RegionsClient(self.auth_provider, **params_v3)
+        self.credentials_client = CredentialsClient(self.auth_provider,
+                                                    **params_v3)
+        self.groups_client = GroupsClient(self.auth_provider, **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
@@ -628,15 +613,3 @@
         self.account_client = AccountClient(self.auth_provider, **params)
         self.container_client = ContainerClient(self.auth_provider, **params)
         self.object_client = ObjectClient(self.auth_provider, **params)
-
-    def _set_api_microversions(self):
-        service_clients = [x for x in self.__dict__ if x.endswith('_client')]
-        for client in service_clients:
-            client_obj = getattr(self, client)
-            microversion = self.api_microversions.get(client_obj.service)
-            if microversion:
-                if hasattr(client_obj, 'set_api_microversion'):
-                    client_obj.set_api_microversion(microversion)
-                else:
-                    LOG.debug("Need to implement set_api_microversion on %s"
-                              % client)
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index 9e98d90..03dfd7b 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -89,21 +89,22 @@
 
 from cliff import command
 from oslo_log import log as logging
-import tempest_lib.auth
-from tempest_lib.common.utils import data_utils
-import tempest_lib.exceptions
-from tempest_lib.services.network import networks_client
-from tempest_lib.services.network import subnets_client
 import yaml
 
 from tempest.common import identity
 from tempest import config
 from tempest import exceptions as exc
+import tempest.lib.auth
+from tempest.lib.common.utils import data_utils
+import tempest.lib.exceptions
+from tempest.lib.services.network import networks_client
+from tempest.lib.services.network import subnets_client
 from tempest.services.identity.v2.json import identity_client
 from tempest.services.identity.v2.json import roles_client
 from tempest.services.identity.v2.json import tenants_client
 from tempest.services.identity.v2.json import users_client
 from tempest.services.network.json import network_client
+from tempest.services.network.json import routers_client
 
 LOG = None
 CONF = config.CONF
@@ -121,7 +122,7 @@
 
 
 def get_admin_clients(opts):
-    _creds = tempest_lib.auth.KeystoneV2Credentials(
+    _creds = tempest.lib.auth.KeystoneV2Credentials(
         username=opts.os_username,
         password=opts.os_password,
         tenant_name=opts.os_tenant_name)
@@ -131,7 +132,7 @@
         'ca_certs': CONF.identity.ca_certificates_file,
         'trace_requests': CONF.debug.trace_requests
     }
-    _auth = tempest_lib.auth.KeystoneV2AuthProvider(
+    _auth = tempest.lib.auth.KeystoneV2AuthProvider(
         _creds, CONF.identity.uri, **auth_params)
     params = {
         'disable_ssl_certificate_validation':
@@ -171,6 +172,7 @@
     )
     network_admin = None
     networks_admin = None
+    routers_admin = None
     subnets_admin = None
     neutron_iso_networks = False
     if (CONF.service_available.neutron and
@@ -188,6 +190,12 @@
             CONF.network.region or CONF.identity.region,
             endpoint_type='adminURL',
             **params)
+        routers_admin = routers_client.RoutersClient(
+            _auth,
+            CONF.network.catalog_type,
+            CONF.network.region or CONF.identity.region,
+            endpoint_type='adminURL',
+            **params)
         subnets_admin = subnets_client.SubnetsClient(
             _auth,
             CONF.network.catalog_type,
@@ -195,12 +203,13 @@
             endpoint_type='adminURL',
             **params)
     return (identity_admin, tenants_admin, roles_admin, users_admin,
-            neutron_iso_networks, network_admin, networks_admin, subnets_admin)
+            neutron_iso_networks, network_admin, networks_admin, routers_admin,
+            subnets_admin)
 
 
 def create_resources(opts, resources):
     (identity_admin, tenants_admin, roles_admin, users_admin,
-     neutron_iso_networks, network_admin, networks_admin,
+     neutron_iso_networks, network_admin, networks_admin, routers_admin,
      subnets_admin) = get_admin_clients(opts)
     roles = roles_admin.list_roles()['roles']
     for u in resources['users']:
@@ -223,14 +232,14 @@
     for u in resources['users']:
         try:
             tenant = identity.get_tenant_by_name(tenants_admin, u['tenant'])
-        except tempest_lib.exceptions.NotFound:
+        except tempest.lib.exceptions.NotFound:
             LOG.error("Tenant: %s - not found" % u['tenant'])
             continue
         while True:
             try:
                 identity.get_user_by_username(tenants_admin,
                                               tenant['id'], u['name'])
-            except tempest_lib.exceptions.NotFound:
+            except tempest.lib.exceptions.NotFound:
                 users_admin.create_user(
                     u['name'], u['pass'], tenant['id'],
                     "%s@%s" % (u['name'], tenant['id']),
@@ -246,27 +255,27 @@
         for u in resources['users']:
             tenant = identity.get_tenant_by_name(tenants_admin, u['tenant'])
             network_name, router_name = create_network_resources(
-                network_admin, networks_admin, subnets_admin, tenant['id'],
-                u['name'])
+                network_admin, networks_admin, routers_admin, subnets_admin,
+                tenant['id'], u['name'])
             u['network'] = network_name
             u['router'] = router_name
         LOG.info('Networks created')
     for u in resources['users']:
         try:
             tenant = identity.get_tenant_by_name(tenants_admin, u['tenant'])
-        except tempest_lib.exceptions.NotFound:
+        except tempest.lib.exceptions.NotFound:
             LOG.error("Tenant: %s - not found" % u['tenant'])
             continue
         try:
             user = identity.get_user_by_username(tenants_admin,
                                                  tenant['id'], u['name'])
-        except tempest_lib.exceptions.NotFound:
+        except tempest.lib.exceptions.NotFound:
             LOG.error("User: %s - not found" % u['user'])
             continue
         for r in u['role_ids']:
             try:
                 roles_admin.assign_user_role(tenant['id'], user['id'], r)
-            except tempest_lib.exceptions.Conflict:
+            except tempest.lib.exceptions.Conflict:
                 # don't care if it's already assigned
                 pass
     LOG.info('Roles assigned')
@@ -274,7 +283,8 @@
 
 
 def create_network_resources(network_admin_client, networks_admin_client,
-                             subnets_admin_client, tenant_id, name):
+                             routers_admin_client, subnets_admin_client,
+                             tenant_id, name):
 
     def _create_network(name):
         resp_body = networks_admin_client.create_network(
@@ -294,7 +304,7 @@
                         enable_dhcp=True,
                         ip_version=4)
                 break
-            except tempest_lib.exceptions.BadRequest as e:
+            except tempest.lib.exceptions.BadRequest as e:
                 if 'overlaps with another subnet' not in str(e):
                     raise
         else:
@@ -305,14 +315,14 @@
     def _create_router(router_name):
         external_net_id = dict(
             network_id=CONF.network.public_network_id)
-        resp_body = network_admin_client.create_router(
+        resp_body = routers_admin_client.create_router(
             router_name,
             external_gateway_info=external_net_id,
             tenant_id=tenant_id)
         return resp_body['router']
 
     def _add_router_interface(router_id, subnet_id):
-        network_admin_client.add_router_interface(router_id,
+        routers_admin_client.add_router_interface(router_id,
                                                   subnet_id=subnet_id)
 
     network_name = name + "-network"
@@ -480,8 +490,8 @@
 def main(opts=None):
     setup_logging()
     if not opts:
-        LOG.warn("Use of: 'tempest-account-generator' is deprecated, "
-                 "please use: 'tempest account-generator'")
+        LOG.warning("Use of: 'tempest-account-generator' is deprecated, "
+                    "please use: 'tempest account-generator'")
         opts = get_options()
     if opts.config_file:
         config.CONF.set_config_path(opts.config_file)
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index 7b73a61..5a52043 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -77,7 +77,8 @@
     def take_action(self, parsed_args):
         try:
             self.init(parsed_args)
-            self._cleanup()
+            if not parsed_args.init_saved_state:
+                self._cleanup()
         except Exception:
             LOG.exception("Failure during cleanup")
             traceback.print_exc()
@@ -231,7 +232,6 @@
         return 'Cleanup after tempest run'
 
     def _add_admin(self, tenant_id):
-        id_cl = self.admin_mgr.identity_client
         rl_cl = self.admin_mgr.roles_client
         needs_role = True
         roles = rl_cl.list_user_roles(tenant_id, self.admin_id)['roles']
@@ -241,7 +241,7 @@
                 LOG.debug("User already had admin privilege for this tenant")
         if needs_role:
             LOG.debug("Adding admin privilege for : %s" % tenant_id)
-            id_cl.assign_user_role(tenant_id, self.admin_id,
+            rl_cl.assign_user_role(tenant_id, self.admin_id,
                                    self.admin_role_id)
             self.admin_role_added.append(tenant_id)
 
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 33f19b1..28ffb56 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -78,7 +78,7 @@
 
     if IS_NEUTRON:
         CONF_PRIV_NETWORK = _get_network_id(CONF.compute.fixed_network_name,
-                                            CONF.identity.tenant_name)
+                                            CONF.auth.admin_tenant_name)
         CONF_NETWORKS = [CONF_PUB_NETWORK, CONF_PRIV_NETWORK]
 
 
@@ -449,7 +449,7 @@
 class NetworkRouterService(NetworkService):
 
     def list(self):
-        client = self.client
+        client = self.routers_client
         routers = client.list_routers(**self.tenant_filter)
         routers = routers['routers']
         if self.is_preserve:
@@ -460,7 +460,7 @@
         return routers
 
     def delete(self):
-        client = self.client
+        client = self.routers_client
         routers = self.list()
         for router in routers:
             try:
@@ -940,7 +940,7 @@
 
     def __init__(self, manager, **kwargs):
         super(DomainService, self).__init__(kwargs)
-        self.client = manager.identity_v3_client
+        self.client = manager.domains_client
 
     def list(self):
         client = self.client
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index e26a014..48c06ff 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -115,25 +115,26 @@
 from oslo_log import log as logging
 from oslo_utils import timeutils
 import six
-from tempest_lib import auth
-from tempest_lib import exceptions as lib_exc
-from tempest_lib.services.compute import flavors_client
-from tempest_lib.services.compute import floating_ips_client
-from tempest_lib.services.compute import security_group_rules_client
-from tempest_lib.services.compute import security_groups_client
-from tempest_lib.services.compute import servers_client
-from tempest_lib.services.network import subnets_client
 import yaml
 
 from tempest.common import identity
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import auth
+from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.compute import flavors_client
+from tempest.lib.services.compute import floating_ips_client
+from tempest.lib.services.compute import security_group_rules_client
+from tempest.lib.services.compute import security_groups_client
+from tempest.lib.services.compute import servers_client
+from tempest.lib.services.network import subnets_client
 from tempest.services.identity.v2.json import identity_client
 from tempest.services.identity.v2.json import roles_client
 from tempest.services.identity.v2.json import tenants_client
 from tempest.services.identity.v2.json import users_client
 from tempest.services.image.v2.json import images_client
 from tempest.services.network.json import network_client
+from tempest.services.network.json import routers_client
 from tempest.services.object_storage import container_client
 from tempest.services.object_storage import object_client
 from tempest.services.telemetry.json import alarming_client
@@ -270,6 +271,14 @@
             build_interval=CONF.network.build_interval,
             build_timeout=CONF.network.build_timeout,
             **default_params)
+        self.routers = routers_client.RoutersClient(
+            _auth,
+            CONF.network.catalog_type,
+            CONF.network.region or CONF.identity.region,
+            endpoint_type=CONF.network.endpoint_type,
+            build_interval=CONF.network.build_interval,
+            build_timeout=CONF.network.build_timeout,
+            **default_params)
         self.subnets = subnets_client.SubnetsClient(
             _auth,
             CONF.network.catalog_type,
@@ -739,7 +748,7 @@
 def _get_router_namespace(client, network):
     network_id = _get_resource_by_name(client.networks,
                                        'networks', network)['id']
-    n_body = client.networks.list_routers()
+    n_body = client.routers.list_routers()
     for router in n_body['routers']:
         router_id = router['id']
         r_body = client.networks.list_router_interfaces(router_id)
@@ -756,7 +765,7 @@
     # we cannot assume they all have the same signature so we need to discard
     # the unused response first value it two values are being returned.
     body = get_resources()
-    if type(body) == tuple:
+    if isinstance(body, tuple):
         body = body[1]
     if isinstance(body, dict):
         body = body[resource]
@@ -824,7 +833,7 @@
         client = client_for_user(router['owner'])
 
         # only create a router if the name isn't here
-        body = client.networks.list_routers()
+        body = client.routers.list_routers()
         if any(item['name'] == router['name'] for item in body['routers']):
             LOG.warning("Duplicated router name: %s" % router['name'])
             continue
@@ -841,9 +850,9 @@
         for subnet in router['subnet']:
             subnet_id = _get_resource_by_name(client.networks,
                                               'subnets', subnet)['id']
-            client.networks.remove_router_interface(router_id,
-                                                    subnet_id=subnet_id)
-        client.networks.delete_router(router_id)
+            client.routers.remove_router_interface(router_id,
+                                                   subnet_id=subnet_id)
+        client.routers.delete_router(router_id)
 
 
 def add_router_interface(routers):
@@ -856,13 +865,13 @@
             subnet_id = _get_resource_by_name(client.networks,
                                               'subnets', subnet)['id']
             # connect routers to their subnets
-            client.networks.add_router_interface(router_id,
-                                                 subnet_id=subnet_id)
+            client.routers.add_router_interface(router_id,
+                                                subnet_id=subnet_id)
         # connect routers to external network if set to "gateway"
         if router['gateway']:
             if CONF.network.public_network_id:
                 ext_net = CONF.network.public_network_id
-                client.networks._update_router(
+                client.routers._update_router(
                     router_id, set_enable_snat=True,
                     external_gateway_info={"network_id": ext_net})
             else:
diff --git a/tempest/cmd/run_stress.py b/tempest/cmd/run_stress.py
index 943fe5b..6fe3928 100644
--- a/tempest/cmd/run_stress.py
+++ b/tempest/cmd/run_stress.py
@@ -146,8 +146,6 @@
 
 
 def main():
-    LOG.warning("Deprecated: Use 'tempest run-stress' instead. "
-                "The old entrypoint will be removed in a future release.")
     parser = argparse.ArgumentParser(description='Run stress tests')
     pa = add_arguments(parser)
     ns = pa.parse_args()
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 92aa19e..5e5e127 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -269,7 +269,6 @@
         'data_processing': 'sahara',
         'baremetal': 'ironic',
         'identity': 'keystone',
-        'messaging': 'zaqar',
         'database': 'trove'
     }
     # Get catalog list for endpoints to use for validation
diff --git a/tempest/common/api_version_utils.py b/tempest/common/api_version_utils.py
index c3d977f..7c7e96a 100644
--- a/tempest/common/api_version_utils.py
+++ b/tempest/common/api_version_utils.py
@@ -18,6 +18,9 @@
 from tempest import exceptions
 
 
+LATEST_MICROVERSION = 'latest'
+
+
 class BaseMicroversionTest(object):
     """Mixin class for API microversion test class."""
 
@@ -27,7 +30,7 @@
     # for all microversions. We need to define microversion range
     # (min_microversion, max_microversion) on each test class if necessary.
     min_microversion = None
-    max_microversion = 'latest'
+    max_microversion = LATEST_MICROVERSION
 
 
 def check_skip_with_microversion(test_min_version, test_max_version,
diff --git a/tempest/common/commands.py b/tempest/common/commands.py
deleted file mode 100644
index 392c9d0..0000000
--- a/tempest/common/commands.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# 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 shlex
-import subprocess
-
-from oslo_log import log as logging
-
-LOG = logging.getLogger(__name__)
-
-
-def copy_file_to_host(file_from, dest, host, username, pkey):
-    dest = "%s@%s:%s" % (username, host, dest)
-    cmd = "scp -v -o UserKnownHostsFile=/dev/null " \
-          "-o StrictHostKeyChecking=no " \
-          "-i %(pkey)s %(file1)s %(dest)s" % {'pkey': pkey,
-                                              'file1': file_from,
-                                              'dest': dest}
-    args = shlex.split(cmd.encode('utf-8'))
-    subprocess_args = {'stdout': subprocess.PIPE,
-                       'stderr': subprocess.STDOUT}
-    proc = subprocess.Popen(args, **subprocess_args)
-    stdout, stderr = proc.communicate()
-    if proc.returncode != 0:
-        LOG.error(("Command {0} returned with exit status {1},"
-                  "output {2}, error {3}").format(cmd, proc.returncode,
-                                                  stdout, stderr))
-    return stdout
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 73505e6..2fbd1b2 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -15,12 +15,12 @@
 
 from oslo_log import log as logging
 from oslo_utils import excutils
-from tempest_lib.common.utils import data_utils
 
 from tempest.common import fixed_network
-from tempest.common import service_client
 from tempest.common import waiters
 from tempest import config
+from tempest.lib.common import rest_client
+from tempest.lib.common.utils import data_utils
 
 CONF = config.CONF
 
@@ -129,7 +129,7 @@
         servers = \
             [s for s in body_servers['servers'] if s['name'].startswith(name)]
     else:
-        body = service_client.ResponseBody(body.response, body['server'])
+        body = rest_client.ResponseBody(body.response, body['server'])
         servers = [body]
 
     # The name of the method to associate a floating IP to as server is too
diff --git a/tempest/common/cred_client.py b/tempest/common/cred_client.py
index e2309bf..37c9727 100644
--- a/tempest/common/cred_client.py
+++ b/tempest/common/cred_client.py
@@ -14,9 +14,9 @@
 
 from oslo_log import log as logging
 import six
-from tempest_lib import auth
-from tempest_lib import exceptions as lib_exc
 
+from tempest.lib import auth
+from tempest.lib import exceptions as lib_exc
 from tempest.services.identity.v2.json import identity_client as v2_identity
 
 LOG = logging.getLogger(__name__)
@@ -31,15 +31,13 @@
      admin credentials used for generating credentials.
     """
 
-    def __init__(self, identity_client, projects_client,
-                 roles_client=None, users_client=None):
+    def __init__(self, identity_client, projects_client, users_client,
+                 roles_client):
         # The client implies version and credentials
         self.identity_client = identity_client
+        self.users_client = users_client
         self.projects_client = projects_client
-        # this is temporary until v3 roles client and v3 users client are
-        # separated, then these clients will become mandatory
-        self.roles_client = roles_client or identity_client
-        self.users_client = users_client or identity_client
+        self.roles_client = roles_client
 
     def create_user(self, username, password, project, email):
         user = self.users_client.create_user(
@@ -73,8 +71,7 @@
             msg = 'No "%s" role found' % role_name
             raise lib_exc.NotFound(msg)
         try:
-            self.roles_client.assign_user_role(project['id'], user['id'],
-                                               role['id'])
+            self._assign_user_role(project, user, role)
         except lib_exc.Conflict:
             LOG.debug("Role %s already assigned on project %s for user %s" % (
                 role['id'], project['id'], user['id']))
@@ -97,12 +94,12 @@
 
 class V2CredsClient(CredsClient):
 
-    def __init__(self, identity_client, projects_client, roles_client,
-                 users_client):
+    def __init__(self, identity_client, projects_client, users_client,
+                 roles_client):
         super(V2CredsClient, self).__init__(identity_client,
                                             projects_client,
-                                            roles_client,
-                                            users_client)
+                                            users_client,
+                                            roles_client)
 
     def create_project(self, name, description):
         tenant = self.projects_client.create_tenant(
@@ -123,15 +120,23 @@
             tenant_name=project['name'], tenant_id=project['id'],
             password=password)
 
+    def _assign_user_role(self, project, user, role):
+        self.roles_client.assign_user_role(project['id'], user['id'],
+                                           role['id'])
+
 
 class V3CredsClient(CredsClient):
 
-    def __init__(self, identity_client, projects_client, domain_name):
-        super(V3CredsClient, self).__init__(identity_client, projects_client)
+    def __init__(self, identity_client, projects_client, users_client,
+                 roles_client, domains_client, domain_name):
+        super(V3CredsClient, self).__init__(identity_client, projects_client,
+                                            users_client, roles_client)
+        self.domains_client = domains_client
+
         try:
             # Domain names must be unique, in any case a list is returned,
             # selecting the first (and only) element
-            self.creds_domain = self.identity_client.list_domains(
+            self.creds_domain = self.domains_client.list_domains(
                 params={'name': domain_name})['domains'][0]
         except lib_exc.NotFound:
             # TODO(andrea) we could probably create the domain on the fly
@@ -160,19 +165,21 @@
             project_domain_id=self.creds_domain['id'],
             project_domain_name=self.creds_domain['name'])
 
-    def _list_roles(self):
-        roles = self.identity_client.list_roles()['roles']
-        return roles
+    def _assign_user_role(self, project, user, role):
+        self.roles_client.assign_user_role_on_project(project['id'],
+                                                      user['id'],
+                                                      role['id'])
 
 
 def get_creds_client(identity_client,
                      projects_client,
-                     roles_client=None,
-                     users_client=None,
+                     users_client,
+                     roles_client,
+                     domains_client=None,
                      project_domain_name=None):
     if isinstance(identity_client, v2_identity.IdentityClient):
-        return V2CredsClient(identity_client, projects_client, roles_client,
-                             users_client)
+        return V2CredsClient(identity_client, projects_client, users_client,
+                             roles_client)
     else:
-        return V3CredsClient(identity_client,
-                             projects_client, project_domain_name)
+        return V3CredsClient(identity_client, projects_client, users_client,
+                             roles_client, domains_client, project_domain_name)
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
index 9dd89ea..a4b2ae8 100644
--- a/tempest/common/cred_provider.py
+++ b/tempest/common/cred_provider.py
@@ -15,9 +15,9 @@
 import abc
 
 import six
-from tempest_lib import auth
 
 from tempest import exceptions
+from tempest.lib import auth
 
 
 @six.add_metaclass(abc.ABCMeta)
diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py
index 24c1198..0ca14a9 100644
--- a/tempest/common/credentials_factory.py
+++ b/tempest/common/credentials_factory.py
@@ -12,7 +12,6 @@
 #    limitations under the License.
 
 from oslo_concurrency import lockutils
-from tempest_lib import auth
 
 from tempest import clients
 from tempest.common import cred_provider
@@ -20,6 +19,7 @@
 from tempest.common import preprov_creds
 from tempest import config
 from tempest import exceptions
+from tempest.lib import auth
 
 CONF = config.CONF
 
diff --git a/tempest/common/dynamic_creds.py b/tempest/common/dynamic_creds.py
index 9e5e0dd..2ffc92d 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -15,7 +15,6 @@
 import netaddr
 from oslo_log import log as logging
 import six
-from tempest_lib import exceptions as lib_exc
 
 from tempest import clients
 from tempest.common import cred_client
@@ -23,6 +22,7 @@
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
+from tempest.lib import exceptions as lib_exc
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
@@ -59,10 +59,12 @@
         self.default_admin_creds = admin_creds
         (self.identity_admin_client,
          self.tenants_admin_client,
-         self.roles_admin_client,
          self.users_admin_client,
+         self.roles_admin_client,
+         self.domains_admin_client,
          self.network_admin_client,
          self.networks_admin_client,
+         self.routers_admin_client,
          self.subnets_admin_client,
          self.ports_admin_client,
          self.security_groups_admin_client) = self._get_admin_clients()
@@ -76,8 +78,9 @@
         self.creds_client = cred_client.get_creds_client(
             self.identity_admin_client,
             self.tenants_admin_client,
-            self.roles_admin_client,
             self.users_admin_client,
+            self.roles_admin_client,
+            self.domains_admin_client,
             self.creds_domain_name)
 
     def _get_admin_clients(self):
@@ -89,14 +92,16 @@
         """
         os = clients.Manager(self.default_admin_creds)
         if self.identity_version == 'v2':
-            return (os.identity_client, os.tenants_client, os.roles_client,
-                    os.users_client, os.network_client, os.networks_client,
+            return (os.identity_client, os.tenants_client, os.users_client,
+                    os.roles_client, None, os.network_client,
+                    os.networks_client, os.routers_client, os.subnets_client,
+                    os.ports_client, os.security_groups_client)
+        else:
+            return (os.identity_v3_client, os.projects_client,
+                    os.users_v3_client, os.roles_v3_client, os.domains_client,
+                    os.network_client, os.networks_client, os.routers_client,
                     os.subnets_client, os.ports_client,
                     os.security_groups_client)
-        else:
-            return (os.identity_v3_client, os.projects_client, None, None,
-                    os.network_client, os.networks_client, os.subnets_client,
-                    os.ports_client, os.security_groups_client)
 
     def _create_creds(self, suffix="", admin=False, roles=None):
         """Create random credentials under the following schema.
@@ -181,12 +186,19 @@
                 router = self._create_router(router_name, tenant_id)
                 self._add_router_interface(router['id'], subnet['id'])
         except Exception:
-            if router:
-                self._clear_isolated_router(router['id'], router['name'])
-            if subnet:
-                self._clear_isolated_subnet(subnet['id'], subnet['name'])
-            if network:
-                self._clear_isolated_network(network['id'], network['name'])
+            try:
+                if router:
+                    self._clear_isolated_router(router['id'], router['name'])
+                if subnet:
+                    self._clear_isolated_subnet(subnet['id'], subnet['name'])
+                if network:
+                    self._clear_isolated_network(network['id'],
+                                                 network['name'])
+            except Exception as cleanup_exception:
+                msg = "There was an exception trying to setup network " \
+                      "resources for tenant %s, and this error happened " \
+                      "trying to clean them up: %s"
+                LOG.warning(msg % (tenant_id, cleanup_exception))
             raise
         return network, subnet, router
 
@@ -227,14 +239,14 @@
     def _create_router(self, router_name, tenant_id):
         external_net_id = dict(
             network_id=CONF.network.public_network_id)
-        resp_body = self.network_admin_client.create_router(
+        resp_body = self.routers_admin_client.create_router(
             router_name,
             external_gateway_info=external_net_id,
             tenant_id=tenant_id)
         return resp_body['router']
 
     def _add_router_interface(self, router_id, subnet_id):
-        self.network_admin_client.add_router_interface(router_id,
+        self.routers_admin_client.add_router_interface(router_id,
                                                        subnet_id=subnet_id)
 
     def get_credentials(self, credential_type):
@@ -285,9 +297,9 @@
         return self.get_credentials(roles)
 
     def _clear_isolated_router(self, router_id, router_name):
-        net_client = self.network_admin_client
+        client = self.routers_admin_client
         try:
-            net_client.delete_router(router_id)
+            client.delete_router(router_id)
         except lib_exc.NotFound:
             LOG.warning('router with name: %s not found for delete' %
                         router_name)
@@ -321,7 +333,7 @@
                             (secgroup['name'], secgroup['id']))
 
     def _clear_isolated_net_resources(self):
-        net_client = self.network_admin_client
+        client = self.routers_admin_client
         for cred in self._creds:
             creds = self._creds.get(cred)
             if (not creds or not any([creds.router, creds.network,
@@ -334,7 +346,7 @@
             if (not self.network_resources or
                     (self.network_resources.get('router') and creds.subnet)):
                 try:
-                    net_client.remove_router_interface(
+                    client.remove_router_interface(
                         creds.router['id'],
                         subnet_id=creds.subnet['id'])
                 except lib_exc.NotFound:
diff --git a/tempest/common/fixed_network.py b/tempest/common/fixed_network.py
index 3fc1365..5f0685e 100644
--- a/tempest/common/fixed_network.py
+++ b/tempest/common/fixed_network.py
@@ -13,9 +13,8 @@
 import copy
 from oslo_log import log as logging
 
-from tempest_lib.common.utils import misc as misc_utils
-
 from tempest import exceptions
+from tempest.lib.common.utils import misc as misc_utils
 
 LOG = logging.getLogger(__name__)
 
diff --git a/tempest/common/glance_http.py b/tempest/common/glance_http.py
index 800e977..baf796d 100644
--- a/tempest/common/glance_http.py
+++ b/tempest/common/glance_http.py
@@ -47,7 +47,6 @@
         self.endpoint_scheme = endpoint_parts.scheme
         self.endpoint_hostname = endpoint_parts.hostname
         self.endpoint_port = endpoint_parts.port
-        self.endpoint_path = endpoint_parts.path
 
         self.connection_class = self._get_connection_class(
             self.endpoint_scheme)
diff --git a/tempest/common/identity.py b/tempest/common/identity.py
index 2179363..469defe 100644
--- a/tempest/common/identity.py
+++ b/tempest/common/identity.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import exceptions as lib_exc
+from tempest.lib import exceptions as lib_exc
 
 
 def get_tenant_by_name(client, tenant_name):
diff --git a/tempest/common/negative_rest_client.py b/tempest/common/negative_rest_client.py
index d97411c..3495a24 100644
--- a/tempest/common/negative_rest_client.py
+++ b/tempest/common/negative_rest_client.py
@@ -15,30 +15,19 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.common import service_client
 from tempest import config
+from tempest.lib.common import rest_client
 
 CONF = config.CONF
 
 
-class NegativeRestClient(service_client.ServiceClient):
+class NegativeRestClient(rest_client.RestClient):
     """Version of RestClient that does not raise exceptions."""
-    def __init__(self, auth_provider, service,
-                 build_interval=None, build_timeout=None,
-                 disable_ssl_certificate_validation=None,
-                 ca_certs=None, trace_requests=None):
+    def __init__(self, auth_provider, service, **kwargs):
         region, endpoint_type = self._get_region_and_endpoint_type(service)
         super(NegativeRestClient, self).__init__(
-            auth_provider,
-            service,
-            region,
-            endpoint_type=endpoint_type,
-            build_interval=build_interval,
-            build_timeout=build_timeout,
-            disable_ssl_certificate_validation=(
-                disable_ssl_certificate_validation),
-            ca_certs=ca_certs,
-            trace_requests=trace_requests)
+            auth_provider, service, region, endpoint_type=endpoint_type,
+            **kwargs)
 
     def _get_region_and_endpoint_type(self, service):
         """Returns the region for a specific service"""
diff --git a/tempest/common/preprov_creds.py b/tempest/common/preprov_creds.py
index 34af31e..97cc2ec 100644
--- a/tempest/common/preprov_creds.py
+++ b/tempest/common/preprov_creds.py
@@ -18,14 +18,14 @@
 from oslo_concurrency import lockutils
 from oslo_log import log as logging
 import six
-from tempest_lib import auth
-from tempest_lib import exceptions as lib_exc
 import yaml
 
 from tempest import clients
 from tempest.common import cred_provider
 from tempest.common import fixed_network
 from tempest import exceptions
+from tempest.lib import auth
+from tempest.lib import exceptions as lib_exc
 
 LOG = logging.getLogger(__name__)
 
diff --git a/tempest/common/service_client.py b/tempest/common/service_client.py
deleted file mode 100644
index b3a5a09..0000000
--- a/tempest/common/service_client.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# 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.
-
-from tempest_lib.common import rest_client
-
-
-class ServiceClient(rest_client.RestClient):
-
-    def __init__(self, auth_provider, service, region,
-                 endpoint_type=None, build_interval=None, build_timeout=None,
-                 disable_ssl_certificate_validation=None, ca_certs=None,
-                 trace_requests=None):
-
-        dscv = disable_ssl_certificate_validation
-        params = {
-            'disable_ssl_certificate_validation': dscv,
-            'ca_certs': ca_certs,
-            'trace_requests': trace_requests
-        }
-
-        if endpoint_type is not None:
-            params.update({'endpoint_type': endpoint_type})
-        if build_interval is not None:
-            params.update({'build_interval': build_interval})
-        if build_timeout is not None:
-            params.update({'build_timeout': build_timeout})
-        super(ServiceClient, self).__init__(auth_provider, service, region,
-                                            **params)
-
-
-class ResponseBody(dict):
-    """Class that wraps an http response and dict body into a single value.
-
-    Callers that receive this object will normally use it as a dict but
-    can extract the response if needed.
-    """
-
-    def __init__(self, response, body=None):
-        body_data = body or {}
-        self.update(body_data)
-        self.response = response
-
-    def __str__(self):
-        body = super(ResponseBody, self).__str__()
-        return "response: %s\nBody: %s" % (self.response, body)
-
-
-class ResponseBodyData(object):
-    """Class that wraps an http response and string data into a single value"""
-
-    def __init__(self, response, data):
-        self.response = response
-        self.data = data
-
-    def __str__(self):
-        return "response: %s\nBody: %s" % (self.response, self.data)
-
-
-class ResponseBodyList(list):
-    """Class that wraps an http response and list body into a single value.
-
-    Callers that receive this object will normally use it as a list but
-    can extract the response if needed.
-    """
-
-    def __init__(self, response, body=None):
-        body_data = body or []
-        self.extend(body_data)
-        self.response = response
-
-    def __str__(self):
-        body = super(ResponseBodyList, self).__str__()
-        return "response: %s\nBody: %s" % (self.response, body)
diff --git a/tempest/common/utils/__init__.py b/tempest/common/utils/__init__.py
index aad6373..b6565d1 100644
--- a/tempest/common/utils/__init__.py
+++ b/tempest/common/utils/__init__.py
@@ -15,8 +15,7 @@
 from functools import partial
 
 from tempest import config
-
-from tempest_lib.common.utils import data_utils as lib_data_utils
+from tempest.lib.common.utils import data_utils as lib_data_utils
 
 CONF = config.CONF
 
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index adb9b1a..36e3e3a 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -15,11 +15,11 @@
 import time
 
 from oslo_log import log as logging
-from tempest_lib.common import ssh
-import tempest_lib.exceptions
 
 from tempest import config
 from tempest import exceptions
+from tempest.lib.common import ssh
+import tempest.lib.exceptions
 
 CONF = config.CONF
 
@@ -186,7 +186,7 @@
         cmd_mkfs = 'sudo /usr/sbin/mke2fs -t %s /dev/%s' % (fs, dev_name)
         try:
             self.exec_command(cmd_mkfs)
-        except tempest_lib.exceptions.SSHExecCommandFailed:
+        except tempest.lib.exceptions.SSHExecCommandFailed:
             LOG.error("Couldn't mke2fs")
             cmd_why = 'sudo ls -lR /dev'
             LOG.info("Contents of /dev: %s" % self.exec_command(cmd_why))
diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py
index 9457a60..84d0143 100644
--- a/tempest/common/validation_resources.py
+++ b/tempest/common/validation_resources.py
@@ -14,9 +14,9 @@
 from oslo_log import log as logging
 
 from tempest import config
-from tempest_lib import exceptions as lib_exc
 
 from tempest.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index 867d3f6..95305f3 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -14,11 +14,11 @@
 import time
 
 from oslo_log import log as logging
-from tempest_lib.common.utils import misc as misc_utils
-from tempest_lib import exceptions as lib_exc
 
 from tempest import config
 from tempest import exceptions
+from tempest.lib.common.utils import misc as misc_utils
+from tempest.lib import exceptions as lib_exc
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
diff --git a/tempest/config.py b/tempest/config.py
index 14a6ad2..ea151ae 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -352,13 +352,6 @@
                 help="Does the test environment block migration support "
                 "cinder iSCSI volumes. Note, libvirt doesn't support this, "
                 "see https://bugs.launchpad.net/nova/+bug/1398999"),
-    # TODO(gilliard): Remove live_migrate_paused_instances at juno-eol.
-    cfg.BoolOpt('live_migrate_paused_instances',
-                default=False,
-                help="Does the test system allow live-migration of paused "
-                "instances? Note, this is more than just the ANDing of "
-                "paused and live_migrate, but all 3 should be set to True "
-                "to run those tests"),
     cfg.BoolOpt('vnc_console',
                 default=False,
                 help='Enable VNC console. This configuration value should '
@@ -394,12 +387,6 @@
     cfg.BoolOpt('personality',
                 default=True,
                 help='Does the test environment support server personality'),
-    # TODO(mriedem): Remove preserve_ports once juno-eol happens.
-    cfg.BoolOpt('preserve_ports',
-                default=False,
-                help='Does Nova preserve preexisting ports from Neutron '
-                     'when deleting an instance? This should be set to True '
-                     'if testing Kilo+ Nova.'),
     cfg.BoolOpt('attach_encrypted_volume',
                 default=True,
                 help='Does the test environment support attaching an '
@@ -417,6 +404,15 @@
     cfg.BoolOpt('config_drive',
                 default=True,
                 help='Enable special configuration drive with metadata.'),
+    cfg.ListOpt('scheduler_available_filters',
+                default=['all'],
+                help="A list of enabled filters that nova will accept as hints"
+                     " to the scheduler when creating a server. A special "
+                     "entry 'all' indicates all filters are enabled. Empty "
+                     "list indicates all filters are disabled. The full "
+                     "available list of filters is in nova.conf: "
+                     "DEFAULT.scheduler_available_filters"),
+
 ]
 
 
@@ -574,41 +570,6 @@
                      " port admin state"),
 ]
 
-messaging_group = cfg.OptGroup(name='messaging',
-                               title='Messaging Service')
-
-MessagingGroup = [
-    cfg.StrOpt('catalog_type',
-               default='messaging',
-               help='Catalog type of the Messaging service.'),
-    cfg.IntOpt('max_queues_per_page',
-               default=20,
-               help='The maximum number of queue records per page when '
-                    'listing queues'),
-    cfg.IntOpt('max_queue_metadata',
-               default=65536,
-               help='The maximum metadata size for a queue'),
-    cfg.IntOpt('max_messages_per_page',
-               default=20,
-               help='The maximum number of queue message per page when '
-                    'listing (or) posting messages'),
-    cfg.IntOpt('max_message_size',
-               default=262144,
-               help='The maximum size of a message body'),
-    cfg.IntOpt('max_messages_per_claim',
-               default=20,
-               help='The maximum number of messages per claim'),
-    cfg.IntOpt('max_message_ttl',
-               default=1209600,
-               help='The maximum ttl for a message'),
-    cfg.IntOpt('max_claim_ttl',
-               default=43200,
-               help='The maximum ttl for a claim'),
-    cfg.IntOpt('max_claim_grace',
-               default=43200,
-               help='The maximum grace period for a claim'),
-]
-
 validation_group = cfg.OptGroup(name='validation',
                                 title='SSH Validation options')
 
@@ -788,7 +749,11 @@
                 default=True,
                 help='Update bootable status of a volume '
                      'Not implemented on icehouse ',
-                deprecated_for_removal=True)
+                deprecated_for_removal=True),
+    # TODO(ynesenenko): Remove volume_services once liberty-eol happens.
+    cfg.BoolOpt('volume_services',
+                default=False,
+                help='Extract correct host info from host@backend')
 ]
 
 
@@ -997,7 +962,7 @@
 
 DataProcessingFeaturesGroup = [
     cfg.ListOpt('plugins',
-                default=["vanilla", "hdp"],
+                default=["vanilla", "cdh"],
                 deprecated_group="data_processing-feature-enabled",
                 help="List of enabled data processing plugins")
 ]
@@ -1071,11 +1036,6 @@
                default='cirros-0.3.1-x86_64-vmlinuz',
                help='AKI image file name',
                deprecated_for_removal=True),
-    cfg.IntOpt(
-        'large_ops_number',
-        default=0,
-        help="specifies how many resources to request at once. Used "
-        "for large operations testing."),
     # TODO(yfried): add support for dhcpcd
     cfg.StrOpt('dhcp_client',
                default='udhcpc',
@@ -1126,9 +1086,6 @@
     cfg.BoolOpt('trove',
                 default=False,
                 help="Whether or not Trove is expected to be available"),
-    cfg.BoolOpt('zaqar',
-                default=False,
-                help="Whether or not Zaqar is expected to be available"),
 ]
 
 debug_group = cfg.OptGroup(name="debug",
@@ -1255,7 +1212,6 @@
     (image_feature_group, ImageFeaturesGroup),
     (network_group, NetworkGroup),
     (network_feature_group, NetworkFeaturesGroup),
-    (messaging_group, MessagingGroup),
     (validation_group, ValidationGroup),
     (volume_group, VolumeGroup),
     (volume_feature_group, VolumeFeaturesGroup),
@@ -1296,7 +1252,10 @@
     generator to discover the options exposed to users.
     """
     ext_plugins = plugins.TempestTestPluginManager()
-    opt_list = [(getattr(g, 'name', None), o) for g, o in _opts]
+    # Make a shallow copy of the options list that can be
+    # extended by plugins. Send back the group object
+    # to allow group help text to be generated.
+    opt_list = [(g, o) for g, o in _opts]
     opt_list.extend(ext_plugins.get_plugin_options_list())
     return opt_list
 
@@ -1331,7 +1290,6 @@
             'object-storage-feature-enabled']
         self.database = _CONF.database
         self.orchestration = _CONF.orchestration
-        self.messaging = _CONF.messaging
         self.telemetry = _CONF.telemetry
         self.telemetry_feature_enabled = _CONF['telemetry-feature-enabled']
         self.dashboard = _CONF.dashboard
@@ -1384,7 +1342,8 @@
             _CONF([], project='tempest')
 
         logging_cfg_path = "%s/logging.conf" % os.path.dirname(path)
-        if (not hasattr(_CONF, 'log_config_append') and
+        if ((not hasattr(_CONF, 'log_config_append') or
+            _CONF.log_config_append is None) and
             os.path.isfile(logging_cfg_path)):
             # if logging conf is in place we need to set log_config_append
             _CONF.log_config_append = logging_cfg_path
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 88598de..c666c96 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -20,7 +20,7 @@
 
 PYTHON_CLIENTS = ['cinder', 'glance', 'keystone', 'nova', 'swift', 'neutron',
                   'trove', 'ironic', 'savanna', 'heat', 'ceilometer',
-                  'zaqar', 'sahara']
+                  'sahara']
 
 PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS))
 TEST_DEFINITION = re.compile(r'^\s*def test.*')
@@ -69,10 +69,12 @@
     if pep8.noqa(physical_line):
         return
 
-    if 'tempest/test.py' not in filename:
-        if SETUP_TEARDOWN_CLASS_DEFINITION.match(physical_line):
-            return (physical_line.find('def'),
-                    "T105: (setUp|tearDown)Class can not be used in tests")
+    if 'tempest/test.py' in filename or 'tempest/lib/' in filename:
+        return
+
+    if SETUP_TEARDOWN_CLASS_DEFINITION.match(physical_line):
+        return (physical_line.find('def'),
+                "T105: (setUp|tearDown)Class can not be used in tests")
 
 
 def no_vi_headers(physical_line, line_number, lines):
diff --git a/tempest/hacking/ignored_list_T110.txt b/tempest/hacking/ignored_list_T110.txt
index f1f21d1..5d3fc93 100644
--- a/tempest/hacking/ignored_list_T110.txt
+++ b/tempest/hacking/ignored_list_T110.txt
@@ -1,4 +1,3 @@
-./tempest/services/messaging/json/messaging_client.py
 ./tempest/services/object_storage/object_client.py
 ./tempest/services/telemetry/json/alarming_client.py
 ./tempest/services/telemetry/json/telemetry_client.py
@@ -6,3 +5,4 @@
 ./tempest/services/volume/base/base_backups_client.py
 ./tempest/services/baremetal/base.py
 ./tempest/services/network/json/network_client.py
+./tempest/services/network/json/routers_client.py
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/__init__.py
similarity index 100%
rename from tempest/api/messaging/__init__.py
rename to tempest/lib/__init__.py
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/api_schema/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/api_schema/__init__.py
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/api_schema/response/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/api_schema/response/__init__.py
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/api_schema/response/compute/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/api_schema/response/compute/__init__.py
diff --git a/tempest/api_schema/response/messaging/v1/__init__.py b/tempest/lib/api_schema/response/compute/v2_1/__init__.py
similarity index 100%
rename from tempest/api_schema/response/messaging/v1/__init__.py
rename to tempest/lib/api_schema/response/compute/v2_1/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_1/agents.py b/tempest/lib/api_schema/response/compute/v2_1/agents.py
new file mode 100644
index 0000000..6f712b4
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/agents.py
@@ -0,0 +1,82 @@
+# Copyright 2014 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.
+
+common_agent_info = {
+    'type': 'object',
+    'properties': {
+        'agent_id': {'type': ['integer', 'string']},
+        'hypervisor': {'type': 'string'},
+        'os': {'type': 'string'},
+        'architecture': {'type': 'string'},
+        'version': {'type': 'string'},
+        'url': {'type': 'string', 'format': 'uri'},
+        'md5hash': {'type': 'string'}
+    },
+    'additionalProperties': False,
+    'required': ['agent_id', 'hypervisor', 'os', 'architecture',
+                 'version', 'url', 'md5hash']
+}
+
+list_agents = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'agents': {
+                'type': 'array',
+                'items': common_agent_info
+            }
+        },
+        'additionalProperties': False,
+        'required': ['agents']
+    }
+}
+
+create_agent = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'agent': common_agent_info
+        },
+        'additionalProperties': False,
+        'required': ['agent']
+    }
+}
+
+update_agent = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'agent': {
+                'type': 'object',
+                'properties': {
+                    'agent_id': {'type': ['integer', 'string']},
+                    'version': {'type': 'string'},
+                    'url': {'type': 'string', 'format': 'uri'},
+                    'md5hash': {'type': 'string'}
+                },
+                'additionalProperties': False,
+                'required': ['agent_id', 'version', 'url', 'md5hash']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['agent']
+    }
+}
+
+delete_agent = {
+    'status_code': [200]
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/aggregates.py b/tempest/lib/api_schema/response/compute/v2_1/aggregates.py
new file mode 100644
index 0000000..1a9fe41
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/aggregates.py
@@ -0,0 +1,92 @@
+# Copyright 2014 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 copy
+
+# 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'},
+        'deleted': {'type': 'boolean'},
+        'deleted_at': {'type': ['string', 'null']},
+        'id': {'type': 'integer'},
+        'name': {'type': 'string'},
+        'updated_at': {'type': ['string', 'null']}
+    },
+    'additionalProperties': False,
+    'required': ['availability_zone', 'created_at', 'deleted',
+                 'deleted_at', 'id', 'name', 'updated_at'],
+}
+
+common_aggregate_info = copy.deepcopy(aggregate_for_create)
+common_aggregate_info['properties'].update({
+    'hosts': {'type': 'array'},
+    'metadata': {'type': 'object'}
+})
+common_aggregate_info['required'].extend(['hosts', 'metadata'])
+
+list_aggregates = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'aggregates': {
+                'type': 'array',
+                'items': common_aggregate_info
+            }
+        },
+        'additionalProperties': False,
+        'required': ['aggregates'],
+    }
+}
+
+get_aggregate = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'aggregate': common_aggregate_info
+        },
+        'additionalProperties': False,
+        'required': ['aggregate'],
+    }
+}
+
+aggregate_set_metadata = get_aggregate
+# 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'
+    }
+
+delete_aggregate = {
+    'status_code': [200]
+}
+
+create_aggregate = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'aggregate': aggregate_for_create
+        },
+        'additionalProperties': False,
+        'required': ['aggregate'],
+    }
+}
+
+aggregate_add_remove_host = get_aggregate
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
new file mode 100644
index 0000000..d9aebce
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/availability_zone.py
@@ -0,0 +1,78 @@
+# Copyright 2014 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 copy
+
+
+base = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'availabilityZoneInfo': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'zoneName': {'type': 'string'},
+                        'zoneState': {
+                            'type': 'object',
+                            'properties': {
+                                'available': {'type': 'boolean'}
+                            },
+                            'additionalProperties': False,
+                            'required': ['available']
+                        },
+                        # NOTE: Here is the difference between detail and
+                        # non-detail.
+                        'hosts': {'type': 'null'}
+                    },
+                    'additionalProperties': False,
+                    'required': ['zoneName', 'zoneState', 'hosts']
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['availabilityZoneInfo']
+    }
+}
+
+detail = {
+    'type': 'object',
+    'patternProperties': {
+        # NOTE: Here is for a hostname
+        '^[a-zA-Z0-9-_.]+$': {
+            'type': 'object',
+            'patternProperties': {
+                # NOTE: Here is for a service name
+                '^.*$': {
+                    'type': 'object',
+                    'properties': {
+                        'available': {'type': 'boolean'},
+                        'active': {'type': 'boolean'},
+                        'updated_at': {'type': ['string', 'null']}
+                    },
+                    'additionalProperties': False,
+                    'required': ['available', 'active', 'updated_at']
+                }
+            }
+        }
+    }
+}
+
+list_availability_zone_list = copy.deepcopy(base)
+
+list_availability_zone_list_detail = copy.deepcopy(base)
+list_availability_zone_list_detail['response_body']['properties'][
+    'availabilityZoneInfo']['items']['properties']['hosts'] = detail
diff --git a/tempest/lib/api_schema/response/compute/v2_1/baremetal_nodes.py b/tempest/lib/api_schema/response/compute/v2_1/baremetal_nodes.py
new file mode 100644
index 0000000..d1ee877
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/baremetal_nodes.py
@@ -0,0 +1,63 @@
+# 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.
+
+import copy
+
+node = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'string'},
+        'interfaces': {'type': 'array'},
+        'host': {'type': 'string'},
+        'task_state': {'type': ['string', 'null']},
+        'cpus': {'type': ['integer', 'string']},
+        'memory_mb': {'type': ['integer', 'string']},
+        'disk_gb': {'type': ['integer', 'string']},
+    },
+    'additionalProperties': False,
+    'required': ['id', 'interfaces', 'host', 'task_state', 'cpus', 'memory_mb',
+                 'disk_gb']
+}
+
+list_baremetal_nodes = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'nodes': {
+                'type': 'array',
+                'items': node
+            }
+        },
+        'additionalProperties': False,
+        'required': ['nodes']
+    }
+}
+
+baremetal_node = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'node': node
+        },
+        'additionalProperties': False,
+        'required': ['node']
+    }
+}
+get_baremetal_node = copy.deepcopy(baremetal_node)
+get_baremetal_node['response_body']['properties']['node'][
+    'properties'].update({'instance_uuid': {'type': ['string', 'null']}})
+get_baremetal_node['response_body']['properties']['node'][
+    'required'].append('instance_uuid')
diff --git a/tempest/lib/api_schema/response/compute/v2_1/certificates.py b/tempest/lib/api_schema/response/compute/v2_1/certificates.py
new file mode 100644
index 0000000..4e7cbe4
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/certificates.py
@@ -0,0 +1,41 @@
+# Copyright 2014 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 copy
+
+_common_schema = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'certificate': {
+                'type': 'object',
+                'properties': {
+                    'data': {'type': 'string'},
+                    'private_key': {'type': 'string'},
+                },
+                'additionalProperties': False,
+                'required': ['data', 'private_key']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['certificate']
+    }
+}
+
+get_certificate = copy.deepcopy(_common_schema)
+get_certificate['response_body']['properties']['certificate'][
+    'properties']['private_key'].update({'type': 'null'})
+
+create_certificate = copy.deepcopy(_common_schema)
diff --git a/tempest/lib/api_schema/response/compute/v2_1/extensions.py b/tempest/lib/api_schema/response/compute/v2_1/extensions.py
new file mode 100644
index 0000000..a6a455c
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/extensions.py
@@ -0,0 +1,47 @@
+# Copyright 2014 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_extensions = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'extensions': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'updated': {
+                            'type': 'string',
+                            'format': 'data-time'
+                        },
+                        'name': {'type': 'string'},
+                        'links': {'type': 'array'},
+                        'namespace': {
+                            'type': 'string',
+                            'format': 'uri'
+                        },
+                        'alias': {'type': 'string'},
+                        'description': {'type': 'string'}
+                    },
+                    'additionalProperties': False,
+                    'required': ['updated', 'name', 'links', 'namespace',
+                                 'alias', 'description']
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['extensions']
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/fixed_ips.py b/tempest/lib/api_schema/response/compute/v2_1/fixed_ips.py
new file mode 100644
index 0000000..a653213
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/fixed_ips.py
@@ -0,0 +1,41 @@
+# Copyright 2014 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
+
+get_fixed_ip = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'fixed_ip': {
+                'type': 'object',
+                'properties': {
+                    'address': parameter_types.ip_address,
+                    'cidr': {'type': 'string'},
+                    'host': {'type': 'string'},
+                    'hostname': {'type': 'string'}
+                },
+                'additionalProperties': False,
+                'required': ['address', 'cidr', 'host', 'hostname']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['fixed_ip']
+    }
+}
+
+reserve_unreserve_fixed_ip = {
+    'status_code': [202]
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/flavors.py b/tempest/lib/api_schema/response/compute/v2_1/flavors.py
new file mode 100644
index 0000000..547d94d
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/flavors.py
@@ -0,0 +1,103 @@
+# Copyright 2014 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
+
+list_flavors = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'flavors': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'name': {'type': 'string'},
+                        'links': parameter_types.links,
+                        'id': {'type': 'string'}
+                    },
+                    'additionalProperties': False,
+                    'required': ['name', 'links', 'id']
+                }
+            },
+            'flavors_links': parameter_types.links
+        },
+        'additionalProperties': False,
+        # NOTE(gmann): flavors_links attribute is not necessary
+        # to be present always So it is not 'required'.
+        'required': ['flavors']
+    }
+}
+
+common_flavor_info = {
+    'type': 'object',
+    'properties': {
+        'name': {'type': 'string'},
+        'links': parameter_types.links,
+        'ram': {'type': 'integer'},
+        'vcpus': {'type': 'integer'},
+        # 'swap' attributes comes as integer value but if it is empty
+        # it comes as "". So defining type of as string and integer.
+        'swap': {'type': ['integer', 'string']},
+        'disk': {'type': 'integer'},
+        'id': {'type': 'string'},
+        'OS-FLV-DISABLED:disabled': {'type': 'boolean'},
+        'os-flavor-access:is_public': {'type': 'boolean'},
+        'rxtx_factor': {'type': 'number'},
+        'OS-FLV-EXT-DATA:ephemeral': {'type': 'integer'}
+    },
+    'additionalProperties': False,
+    # 'OS-FLV-DISABLED', 'os-flavor-access', 'rxtx_factor' and
+    # 'OS-FLV-EXT-DATA' are API extensions. So they are not 'required'.
+    'required': ['name', 'links', 'ram', 'vcpus', 'swap', 'disk', 'id']
+}
+
+list_flavors_details = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'flavors': {
+                'type': 'array',
+                'items': common_flavor_info
+            },
+            # NOTE(gmann): flavors_links attribute is not necessary
+            # to be present always So it is not 'required'.
+            'flavors_links': parameter_types.links
+        },
+        'additionalProperties': False,
+        'required': ['flavors']
+    }
+}
+
+unset_flavor_extra_specs = {
+    'status_code': [200]
+}
+
+create_get_flavor_details = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'flavor': common_flavor_info
+        },
+        'additionalProperties': False,
+        'required': ['flavor']
+    }
+}
+
+delete_flavor = {
+    'status_code': [202]
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/flavors_access.py b/tempest/lib/api_schema/response/compute/v2_1/flavors_access.py
new file mode 100644
index 0000000..a4d6af0
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/flavors_access.py
@@ -0,0 +1,36 @@
+# Copyright 2014 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.
+
+add_remove_list_flavor_access = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'flavor_access': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'flavor_id': {'type': 'string'},
+                        'tenant_id': {'type': 'string'},
+                    },
+                    'additionalProperties': False,
+                    'required': ['flavor_id', 'tenant_id'],
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['flavor_access']
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/flavors_extra_specs.py b/tempest/lib/api_schema/response/compute/v2_1/flavors_extra_specs.py
new file mode 100644
index 0000000..a438d48
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/flavors_extra_specs.py
@@ -0,0 +1,40 @@
+# Copyright 2014 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.
+
+set_get_flavor_extra_specs = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'extra_specs': {
+                'type': 'object',
+                'patternProperties': {
+                    '^[a-zA-Z0-9_\-\. :]+$': {'type': 'string'}
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['extra_specs']
+    }
+}
+
+set_get_flavor_extra_specs_key = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'patternProperties': {
+            '^[a-zA-Z0-9_\-\. :]+$': {'type': 'string'}
+        }
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/floating_ips.py b/tempest/lib/api_schema/response/compute/v2_1/floating_ips.py
new file mode 100644
index 0000000..0c66590
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/floating_ips.py
@@ -0,0 +1,148 @@
+# Copyright 2014 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
+
+common_floating_ip_info = {
+    'type': 'object',
+    'properties': {
+        # NOTE: Now the type of 'id' is integer, but
+        # here allows 'string' also because we will be
+        # able to change it to 'uuid' in the future.
+        'id': {'type': ['integer', 'string']},
+        'pool': {'type': ['string', 'null']},
+        'instance_id': {'type': ['string', 'null']},
+        'ip': parameter_types.ip_address,
+        'fixed_ip': parameter_types.ip_address
+    },
+    'additionalProperties': False,
+    'required': ['id', 'pool', 'instance_id',
+                 'ip', 'fixed_ip'],
+
+}
+list_floating_ips = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'floating_ips': {
+                'type': 'array',
+                'items': common_floating_ip_info
+            },
+        },
+        'additionalProperties': False,
+        'required': ['floating_ips'],
+    }
+}
+
+create_get_floating_ip = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'floating_ip': common_floating_ip_info
+        },
+        'additionalProperties': False,
+        'required': ['floating_ip'],
+    }
+}
+
+list_floating_ip_pools = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'floating_ip_pools': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'name': {'type': 'string'}
+                    },
+                    'additionalProperties': False,
+                    'required': ['name'],
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['floating_ip_pools'],
+    }
+}
+
+add_remove_floating_ip = {
+    'status_code': [202]
+}
+
+create_floating_ips_bulk = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'floating_ips_bulk_create': {
+                'type': 'object',
+                'properties': {
+                    'interface': {'type': ['string', 'null']},
+                    'ip_range': {'type': 'string'},
+                    'pool': {'type': ['string', 'null']},
+                },
+                'additionalProperties': False,
+                'required': ['interface', 'ip_range', 'pool'],
+            }
+        },
+        'additionalProperties': False,
+        'required': ['floating_ips_bulk_create'],
+    }
+}
+
+delete_floating_ips_bulk = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'floating_ips_bulk_delete': {'type': 'string'}
+        },
+        'additionalProperties': False,
+        'required': ['floating_ips_bulk_delete'],
+    }
+}
+
+list_floating_ips_bulk = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'floating_ip_info': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'address': parameter_types.ip_address,
+                        'instance_uuid': {'type': ['string', 'null']},
+                        'interface': {'type': ['string', 'null']},
+                        'pool': {'type': ['string', 'null']},
+                        'project_id': {'type': ['string', 'null']},
+                        'fixed_ip': parameter_types.ip_address
+                    },
+                    'additionalProperties': False,
+                    # NOTE: fixed_ip is introduced after JUNO release,
+                    # So it is not defined as 'required'.
+                    'required': ['address', 'instance_uuid', 'interface',
+                                 'pool', 'project_id'],
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['floating_ip_info'],
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/hosts.py b/tempest/lib/api_schema/response/compute/v2_1/hosts.py
new file mode 100644
index 0000000..ae70ff1
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/hosts.py
@@ -0,0 +1,116 @@
+# Copyright 2014 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 copy
+
+
+list_hosts = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'hosts': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'host_name': {'type': 'string'},
+                        'service': {'type': 'string'},
+                        'zone': {'type': 'string'}
+                    },
+                    'additionalProperties': False,
+                    'required': ['host_name', 'service', 'zone']
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['hosts']
+    }
+}
+
+get_host_detail = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'host': {
+                'type': 'array',
+                'item': {
+                    'type': 'object',
+                    'properties': {
+                        'resource': {
+                            'type': 'object',
+                            'properties': {
+                                'cpu': {'type': 'integer'},
+                                'disk_gb': {'type': 'integer'},
+                                'host': {'type': 'string'},
+                                'memory_mb': {'type': 'integer'},
+                                'project': {'type': 'string'}
+                            },
+                            'additionalProperties': False,
+                            'required': ['cpu', 'disk_gb', 'host',
+                                         'memory_mb', 'project']
+                        }
+                    },
+                    'additionalProperties': False,
+                    'required': ['resource']
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['host']
+    }
+}
+
+startup_host = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'host': {'type': 'string'},
+            'power_action': {'enum': ['startup']}
+        },
+        'additionalProperties': False,
+        'required': ['host', 'power_action']
+    }
+}
+
+# The 'power_action' attribute of 'shutdown_host' API is 'shutdown'
+shutdown_host = copy.deepcopy(startup_host)
+
+shutdown_host['response_body']['properties']['power_action'] = {
+    'enum': ['shutdown']
+}
+
+# The 'power_action' attribute of 'reboot_host' API is 'reboot'
+reboot_host = copy.deepcopy(startup_host)
+
+reboot_host['response_body']['properties']['power_action'] = {
+    'enum': ['reboot']
+}
+
+update_host = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'host': {'type': 'string'},
+            'maintenance_mode': {'enum': ['on_maintenance',
+                                          'off_maintenance']},
+            'status': {'enum': ['enabled', 'disabled']}
+        },
+        'additionalProperties': False,
+        'required': ['host', 'maintenance_mode', 'status']
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/hypervisors.py b/tempest/lib/api_schema/response/compute/v2_1/hypervisors.py
new file mode 100644
index 0000000..d15b4f6
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/hypervisors.py
@@ -0,0 +1,195 @@
+# Copyright 2014 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
+get_hypervisor_statistics = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'hypervisor_statistics': {
+                'type': 'object',
+                'properties': {
+                    'count': {'type': 'integer'},
+                    'current_workload': {'type': 'integer'},
+                    'disk_available_least': {'type': ['integer', 'null']},
+                    'free_disk_gb': {'type': 'integer'},
+                    'free_ram_mb': {'type': 'integer'},
+                    'local_gb': {'type': 'integer'},
+                    'local_gb_used': {'type': 'integer'},
+                    'memory_mb': {'type': 'integer'},
+                    'memory_mb_used': {'type': 'integer'},
+                    'running_vms': {'type': 'integer'},
+                    'vcpus': {'type': 'integer'},
+                    'vcpus_used': {'type': 'integer'}
+                },
+                'additionalProperties': False,
+                'required': ['count', 'current_workload',
+                             'disk_available_least', 'free_disk_gb',
+                             'free_ram_mb', 'local_gb', 'local_gb_used',
+                             'memory_mb', 'memory_mb_used', 'running_vms',
+                             'vcpus', 'vcpus_used']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['hypervisor_statistics']
+    }
+}
+
+
+hypervisor_detail = {
+    'type': 'object',
+    'properties': {
+        'status': {'type': 'string'},
+        'state': {'type': 'string'},
+        'cpu_info': {'type': 'string'},
+        'current_workload': {'type': 'integer'},
+        'disk_available_least': {'type': ['integer', 'null']},
+        'host_ip': parameter_types.ip_address,
+        'free_disk_gb': {'type': 'integer'},
+        'free_ram_mb': {'type': 'integer'},
+        'hypervisor_hostname': {'type': 'string'},
+        'hypervisor_type': {'type': 'string'},
+        'hypervisor_version': {'type': 'integer'},
+        'id': {'type': ['integer', 'string']},
+        'local_gb': {'type': 'integer'},
+        'local_gb_used': {'type': 'integer'},
+        'memory_mb': {'type': 'integer'},
+        'memory_mb_used': {'type': 'integer'},
+        'running_vms': {'type': 'integer'},
+        'service': {
+            'type': 'object',
+            'properties': {
+                'host': {'type': 'string'},
+                'id': {'type': ['integer', 'string']},
+                'disabled_reason': {'type': ['string', 'null']}
+            },
+            'additionalProperties': False,
+            'required': ['host', 'id']
+        },
+        'vcpus': {'type': 'integer'},
+        'vcpus_used': {'type': 'integer'}
+    },
+    'additionalProperties': False,
+    # NOTE: When loading os-hypervisor-status extension,
+    # a response contains status and state. So these params
+    # should not be required.
+    'required': ['cpu_info', 'current_workload',
+                 'disk_available_least', 'host_ip',
+                 'free_disk_gb', 'free_ram_mb',
+                 'hypervisor_hostname', 'hypervisor_type',
+                 'hypervisor_version', 'id', 'local_gb',
+                 'local_gb_used', 'memory_mb', 'memory_mb_used',
+                 'running_vms', 'service', 'vcpus', 'vcpus_used']
+}
+
+list_hypervisors_detail = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'hypervisors': {
+                'type': 'array',
+                'items': hypervisor_detail
+            }
+        },
+        'additionalProperties': False,
+        'required': ['hypervisors']
+    }
+}
+
+get_hypervisor = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'hypervisor': hypervisor_detail
+        },
+        'additionalProperties': False,
+        'required': ['hypervisor']
+    }
+}
+
+list_search_hypervisors = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'hypervisors': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'status': {'type': 'string'},
+                        'state': {'type': 'string'},
+                        'id': {'type': ['integer', 'string']},
+                        'hypervisor_hostname': {'type': 'string'}
+                    },
+                    'additionalProperties': False,
+                    # NOTE: When loading os-hypervisor-status extension,
+                    # a response contains status and state. So these params
+                    # should not be required.
+                    'required': ['id', 'hypervisor_hostname']
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['hypervisors']
+    }
+}
+
+get_hypervisor_uptime = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'hypervisor': {
+                'type': 'object',
+                'properties': {
+                    'status': {'type': 'string'},
+                    'state': {'type': 'string'},
+                    'id': {'type': ['integer', 'string']},
+                    'hypervisor_hostname': {'type': 'string'},
+                    'uptime': {'type': 'string'}
+                },
+                'additionalProperties': False,
+                # NOTE: When loading os-hypervisor-status extension,
+                # a response contains status and state. So these params
+                # should not be required.
+                'required': ['id', 'hypervisor_hostname', 'uptime']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['hypervisor']
+    }
+}
+
+get_hypervisors_servers = copy.deepcopy(list_search_hypervisors)
+get_hypervisors_servers['response_body']['properties']['hypervisors']['items'][
+    'properties']['servers'] = {
+        'type': 'array',
+        'items': {
+            'type': 'object',
+            'properties': {
+                'uuid': {'type': 'string'},
+                'name': {'type': 'string'}
+            },
+            'additionalProperties': False,
+        }
+    }
+# In V2 API, if there is no servers (VM) on the Hypervisor host then 'servers'
+# attribute will not be present in response body So it is not 'required'.
diff --git a/tempest/lib/api_schema/response/compute/v2_1/images.py b/tempest/lib/api_schema/response/compute/v2_1/images.py
new file mode 100644
index 0000000..daab898
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/images.py
@@ -0,0 +1,154 @@
+# Copyright 2014 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
+image_links = copy.deepcopy(parameter_types.links)
+image_links['items']['properties'].update({'type': {'type': 'string'}})
+
+common_image_schema = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'string'},
+        'status': {'type': 'string'},
+        'updated': {'type': 'string'},
+        'links': image_links,
+        'name': {'type': ['string', 'null']},
+        'created': {'type': 'string'},
+        'minDisk': {'type': 'integer'},
+        'minRam': {'type': 'integer'},
+        'progress': {'type': 'integer'},
+        'metadata': {'type': 'object'},
+        'server': {
+            'type': 'object',
+            'properties': {
+                'id': {'type': 'string'},
+                'links': parameter_types.links
+            },
+            'additionalProperties': False,
+            'required': ['id', 'links']
+        },
+        'OS-EXT-IMG-SIZE:size': {'type': ['integer', 'null']},
+        'OS-DCF:diskConfig': {'type': 'string'}
+    },
+    'additionalProperties': False,
+    # 'server' attributes only comes in response body if image is
+    # associated with any server. 'OS-EXT-IMG-SIZE:size' & 'OS-DCF:diskConfig'
+    # are API extension,  So those are not defined as 'required'.
+    'required': ['id', 'status', 'updated', 'links', 'name',
+                 'created', 'minDisk', 'minRam', 'progress',
+                 'metadata']
+}
+
+get_image = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'image': common_image_schema
+        },
+        'additionalProperties': False,
+        'required': ['image']
+    }
+}
+
+list_images = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'images': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'id': {'type': 'string'},
+                        'links': image_links,
+                        'name': {'type': 'string'}
+                    },
+                    'additionalProperties': False,
+                    'required': ['id', 'links', 'name']
+                }
+            },
+            'images_links': parameter_types.links
+        },
+        'additionalProperties': False,
+        # NOTE(gmann): images_links attribute is not necessary to be
+        # present always So it is not 'required'.
+        'required': ['images']
+    }
+}
+
+create_image = {
+    'status_code': [202],
+    'response_header': {
+        'type': 'object',
+        'properties': parameter_types.response_header
+    }
+}
+create_image['response_header']['properties'].update(
+    {'location': {
+        'type': 'string',
+        'format': 'uri'}
+     }
+)
+create_image['response_header']['required'] = ['location']
+
+delete = {
+    'status_code': [204]
+}
+
+image_metadata = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'metadata': {'type': 'object'}
+        },
+        'additionalProperties': False,
+        'required': ['metadata']
+    }
+}
+
+image_meta_item = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'meta': {'type': 'object'}
+        },
+        'additionalProperties': False,
+        'required': ['meta']
+    }
+}
+
+list_images_details = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'images': {
+                'type': 'array',
+                'items': common_image_schema
+            },
+            'images_links': parameter_types.links
+        },
+        'additionalProperties': False,
+        # NOTE(gmann): images_links attribute is not necessary to be
+        # present always So it is not 'required'.
+        'required': ['images']
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/instance_usage_audit_logs.py b/tempest/lib/api_schema/response/compute/v2_1/instance_usage_audit_logs.py
new file mode 100644
index 0000000..c6c4deb
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/instance_usage_audit_logs.py
@@ -0,0 +1,62 @@
+# Copyright 2014 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.
+
+common_instance_usage_audit_log = {
+    'type': 'object',
+    'properties': {
+        'hosts_not_run': {
+            'type': 'array',
+            'items': {'type': 'string'}
+        },
+        'log': {'type': 'object'},
+        'num_hosts': {'type': 'integer'},
+        'num_hosts_done': {'type': 'integer'},
+        'num_hosts_not_run': {'type': 'integer'},
+        'num_hosts_running': {'type': 'integer'},
+        'overall_status': {'type': 'string'},
+        'period_beginning': {'type': 'string'},
+        'period_ending': {'type': 'string'},
+        'total_errors': {'type': 'integer'},
+        'total_instances': {'type': 'integer'}
+    },
+    'additionalProperties': False,
+    'required': ['hosts_not_run', 'log', 'num_hosts', 'num_hosts_done',
+                 'num_hosts_not_run', 'num_hosts_running', 'overall_status',
+                 'period_beginning', 'period_ending', 'total_errors',
+                 'total_instances']
+}
+
+get_instance_usage_audit_log = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'instance_usage_audit_log': common_instance_usage_audit_log
+        },
+        'additionalProperties': False,
+        'required': ['instance_usage_audit_log']
+    }
+}
+
+list_instance_usage_audit_log = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'instance_usage_audit_logs': common_instance_usage_audit_log
+        },
+        'additionalProperties': False,
+        'required': ['instance_usage_audit_logs']
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/interfaces.py b/tempest/lib/api_schema/response/compute/v2_1/interfaces.py
new file mode 100644
index 0000000..9984750
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/interfaces.py
@@ -0,0 +1,73 @@
+# Copyright 2014 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
+
+interface_common_info = {
+    'type': 'object',
+    'properties': {
+        'port_state': {'type': 'string'},
+        'fixed_ips': {
+            'type': 'array',
+            'items': {
+                'type': 'object',
+                'properties': {
+                    'subnet_id': {
+                        'type': 'string',
+                        'format': 'uuid'
+                    },
+                    'ip_address': parameter_types.ip_address
+                },
+                'additionalProperties': False,
+                'required': ['subnet_id', 'ip_address']
+            }
+        },
+        'port_id': {'type': 'string', 'format': 'uuid'},
+        'net_id': {'type': 'string', 'format': 'uuid'},
+        'mac_addr': parameter_types.mac_address
+    },
+    'additionalProperties': False,
+    'required': ['port_state', 'fixed_ips', 'port_id', 'net_id', 'mac_addr']
+}
+
+get_create_interfaces = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'interfaceAttachment': interface_common_info
+        },
+        'additionalProperties': False,
+        'required': ['interfaceAttachment']
+    }
+}
+
+list_interfaces = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'interfaceAttachments': {
+                'type': 'array',
+                'items': interface_common_info
+            }
+        },
+        'additionalProperties': False,
+        'required': ['interfaceAttachments']
+    }
+}
+
+delete_interface = {
+    'status_code': [202]
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/keypairs.py b/tempest/lib/api_schema/response/compute/v2_1/keypairs.py
new file mode 100644
index 0000000..9c04c79
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/keypairs.py
@@ -0,0 +1,107 @@
+# Copyright 2014 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.
+
+get_keypair = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'keypair': {
+                'type': 'object',
+                'properties': {
+                    'public_key': {'type': 'string'},
+                    'name': {'type': 'string'},
+                    'fingerprint': {'type': 'string'},
+                    'user_id': {'type': 'string'},
+                    'deleted': {'type': 'boolean'},
+                    'created_at': {'type': 'string'},
+                    'updated_at': {'type': ['string', 'null']},
+                    'deleted_at': {'type': ['string', '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']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['keypair']
+    }
+}
+
+create_keypair = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'keypair': {
+                'type': 'object',
+                'properties': {
+                    'fingerprint': {'type': 'string'},
+                    'name': {'type': 'string'},
+                    'public_key': {'type': 'string'},
+                    'user_id': {'type': 'string'},
+                    'private_key': {'type': 'string'}
+                },
+                'additionalProperties': False,
+                # When create keypair API is being called with 'Public key'
+                # (Importing keypair) then, response body does not contain
+                # 'private_key' So it is not defined as 'required'
+                'required': ['fingerprint', 'name', 'public_key', 'user_id']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['keypair']
+    }
+}
+
+delete_keypair = {
+    'status_code': [202],
+}
+
+list_keypairs = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'keypairs': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'keypair': {
+                            'type': 'object',
+                            'properties': {
+                                'public_key': {'type': 'string'},
+                                'name': {'type': 'string'},
+                                'fingerprint': {'type': 'string'}
+                            },
+                            'additionalProperties': False,
+                            'required': ['public_key', 'name', 'fingerprint']
+                        }
+                    },
+                    'additionalProperties': False,
+                    'required': ['keypair']
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['keypairs']
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/limits.py b/tempest/lib/api_schema/response/compute/v2_1/limits.py
new file mode 100644
index 0000000..81f175f
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/limits.py
@@ -0,0 +1,106 @@
+# Copyright 2014 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.
+
+get_limit = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'limits': {
+                'type': 'object',
+                'properties': {
+                    'absolute': {
+                        'type': 'object',
+                        'properties': {
+                            'maxTotalRAMSize': {'type': 'integer'},
+                            'totalCoresUsed': {'type': 'integer'},
+                            'maxTotalInstances': {'type': 'integer'},
+                            'maxTotalFloatingIps': {'type': 'integer'},
+                            'totalSecurityGroupsUsed': {'type': 'integer'},
+                            'maxTotalCores': {'type': 'integer'},
+                            'totalFloatingIpsUsed': {'type': 'integer'},
+                            'maxSecurityGroups': {'type': 'integer'},
+                            'maxServerMeta': {'type': 'integer'},
+                            'maxPersonality': {'type': 'integer'},
+                            'maxImageMeta': {'type': 'integer'},
+                            'maxPersonalitySize': {'type': 'integer'},
+                            'maxSecurityGroupRules': {'type': 'integer'},
+                            'maxTotalKeypairs': {'type': 'integer'},
+                            'totalRAMUsed': {'type': 'integer'},
+                            'totalInstancesUsed': {'type': 'integer'},
+                            'maxServerGroupMembers': {'type': 'integer'},
+                            'maxServerGroups': {'type': 'integer'},
+                            'totalServerGroupsUsed': {'type': 'integer'}
+                        },
+                        'additionalProperties': False,
+                        # NOTE(gmann): maxServerGroupMembers,  maxServerGroups
+                        # and totalServerGroupsUsed are API extension,
+                        # and some environments return a response without these
+                        # attributes.So they are not 'required'.
+                        'required': ['maxImageMeta',
+                                     'maxPersonality',
+                                     'maxPersonalitySize',
+                                     'maxSecurityGroupRules',
+                                     'maxSecurityGroups',
+                                     'maxServerMeta',
+                                     'maxTotalCores',
+                                     'maxTotalFloatingIps',
+                                     'maxTotalInstances',
+                                     'maxTotalKeypairs',
+                                     'maxTotalRAMSize',
+                                     'totalCoresUsed',
+                                     'totalFloatingIpsUsed',
+                                     'totalInstancesUsed',
+                                     'totalRAMUsed',
+                                     'totalSecurityGroupsUsed']
+                    },
+                    'rate': {
+                        'type': 'array',
+                        'items': {
+                            'type': 'object',
+                            'properties': {
+                                'limit': {
+                                    'type': 'array',
+                                    'items': {
+                                        'type': 'object',
+                                        'properties': {
+                                            'next-available':
+                                                {'type': 'string'},
+                                            'remaining':
+                                                {'type': 'integer'},
+                                            'unit':
+                                                {'type': 'string'},
+                                            'value':
+                                                {'type': 'integer'},
+                                            'verb':
+                                                {'type': 'string'}
+                                        },
+                                        'additionalProperties': False,
+                                    }
+                                },
+                                'regex': {'type': 'string'},
+                                'uri': {'type': 'string'}
+                            },
+                            'additionalProperties': False,
+                        }
+                    }
+                },
+                'additionalProperties': False,
+                'required': ['absolute', 'rate']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['limits']
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/migrations.py b/tempest/lib/api_schema/response/compute/v2_1/migrations.py
new file mode 100644
index 0000000..b7d66ea
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/migrations.py
@@ -0,0 +1,51 @@
+# Copyright 2014 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_migrations = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'migrations': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'id': {'type': 'integer'},
+                        'status': {'type': ['string', 'null']},
+                        'instance_uuid': {'type': ['string', 'null']},
+                        'source_node': {'type': ['string', 'null']},
+                        'source_compute': {'type': ['string', 'null']},
+                        'dest_node': {'type': ['string', 'null']},
+                        'dest_compute': {'type': ['string', 'null']},
+                        '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']}
+                    },
+                    'additionalProperties': False,
+                    'required': [
+                        'id', 'status', 'instance_uuid', 'source_node',
+                        'source_compute', 'dest_node', 'dest_compute',
+                        'dest_host', 'old_instance_type_id',
+                        'new_instance_type_id', 'created_at', 'updated_at'
+                    ]
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['migrations']
+    }
+}
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
new file mode 100644
index 0000000..07cc890
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py
@@ -0,0 +1,96 @@
+# Copyright 2014 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.
+
+links = {
+    'type': 'array',
+    'items': {
+        'type': 'object',
+        'properties': {
+            'href': {
+                'type': 'string',
+                'format': 'uri'
+            },
+            'rel': {'type': 'string'}
+        },
+        'additionalProperties': False,
+        'required': ['href', 'rel']
+    }
+}
+
+mac_address = {
+    'type': 'string',
+    'pattern': '(?:[a-f0-9]{2}:){5}[a-f0-9]{2}'
+}
+
+ip_address = {
+    'oneOf': [
+        {
+            'type': 'string',
+            'oneOf': [
+                {'format': 'ipv4'},
+                {'format': 'ipv6'}
+            ]
+        },
+        {'type': 'null'}
+    ]
+}
+
+access_ip_v4 = {
+    'type': 'string',
+    'oneOf': [{'format': 'ipv4'}, {'enum': ['']}]
+}
+
+access_ip_v6 = {
+    'type': 'string',
+    'oneOf': [{'format': 'ipv6'}, {'enum': ['']}]
+}
+
+addresses = {
+    'type': 'object',
+    'patternProperties': {
+        # NOTE: Here is for 'private' or something.
+        '^[a-zA-Z0-9-_.]+$': {
+            'type': 'array',
+            'items': {
+                'type': 'object',
+                'properties': {
+                    'version': {'type': 'integer'},
+                    'addr': {
+                        'type': 'string',
+                        'oneOf': [
+                            {'format': 'ipv4'},
+                            {'format': 'ipv6'}
+                        ]
+                    }
+                },
+                'additionalProperties': False,
+                'required': ['version', 'addr']
+            }
+        }
+    }
+}
+
+response_header = {
+    'connection': {'type': 'string'},
+    'content-length': {'type': 'string'},
+    'content-type': {'type': 'string'},
+    'status': {'type': 'string'},
+    'x-compute-request-id': {'type': 'string'},
+    'vary': {'type': 'string'},
+    'x-openstack-nova-api-version': {'type': 'string'},
+    'date': {
+        'type': 'string',
+        'format': 'data-time'
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/quota_classes.py b/tempest/lib/api_schema/response/compute/v2_1/quota_classes.py
new file mode 100644
index 0000000..03d7f12
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/quota_classes.py
@@ -0,0 +1,31 @@
+# Copyright 2014 IBM 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import quotas
+
+# NOTE(mriedem): os-quota-class-sets responses are the same as os-quota-sets
+# except for the key in the response body is quota_class_set instead of
+# quota_set, so update this copy of the schema from os-quota-sets.
+get_quota_class_set = copy.deepcopy(quotas.get_quota_set)
+get_quota_class_set['response_body']['properties']['quota_class_set'] = (
+    get_quota_class_set['response_body']['properties'].pop('quota_set'))
+get_quota_class_set['response_body']['required'] = ['quota_class_set']
+
+update_quota_class_set = copy.deepcopy(quotas.update_quota_set)
+update_quota_class_set['response_body']['properties']['quota_class_set'] = (
+    update_quota_class_set['response_body']['properties'].pop('quota_set'))
+update_quota_class_set['response_body']['required'] = ['quota_class_set']
diff --git a/tempest/lib/api_schema/response/compute/v2_1/quotas.py b/tempest/lib/api_schema/response/compute/v2_1/quotas.py
new file mode 100644
index 0000000..7953983
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/quotas.py
@@ -0,0 +1,65 @@
+# Copyright 2014 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 copy
+
+update_quota_set = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'quota_set': {
+                'type': 'object',
+                'properties': {
+                    'instances': {'type': 'integer'},
+                    'cores': {'type': 'integer'},
+                    'ram': {'type': 'integer'},
+                    'floating_ips': {'type': 'integer'},
+                    'fixed_ips': {'type': 'integer'},
+                    'metadata_items': {'type': 'integer'},
+                    'key_pairs': {'type': 'integer'},
+                    'security_groups': {'type': 'integer'},
+                    'security_group_rules': {'type': 'integer'},
+                    'server_group_members': {'type': 'integer'},
+                    'server_groups': {'type': 'integer'},
+                    'injected_files': {'type': 'integer'},
+                    'injected_file_content_bytes': {'type': 'integer'},
+                    'injected_file_path_bytes': {'type': 'integer'}
+                },
+                'additionalProperties': False,
+                # NOTE: server_group_members and server_groups are represented
+                # when enabling quota_server_group extension. So they should
+                # not be required.
+                'required': ['instances', 'cores', 'ram',
+                             'floating_ips', 'fixed_ips',
+                             'metadata_items', 'key_pairs',
+                             'security_groups', 'security_group_rules',
+                             'injected_files', 'injected_file_content_bytes',
+                             'injected_file_path_bytes']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['quota_set']
+    }
+}
+
+get_quota_set = copy.deepcopy(update_quota_set)
+get_quota_set['response_body']['properties']['quota_set']['properties'][
+    'id'] = {'type': 'string'}
+get_quota_set['response_body']['properties']['quota_set']['required'].extend([
+    'id'])
+
+delete_quota = {
+    'status_code': [202]
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/security_group_default_rule.py b/tempest/lib/api_schema/response/compute/v2_1/security_group_default_rule.py
new file mode 100644
index 0000000..2ec2826
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/security_group_default_rule.py
@@ -0,0 +1,65 @@
+# Copyright 2014 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.
+
+common_security_group_default_rule_info = {
+    'type': 'object',
+    'properties': {
+        'from_port': {'type': 'integer'},
+        'id': {'type': 'integer'},
+        'ip_protocol': {'type': 'string'},
+        'ip_range': {
+            'type': 'object',
+            'properties': {
+                'cidr': {'type': 'string'}
+            },
+            'additionalProperties': False,
+            'required': ['cidr'],
+        },
+        'to_port': {'type': 'integer'},
+    },
+    'additionalProperties': False,
+    'required': ['from_port', 'id', 'ip_protocol', 'ip_range', 'to_port'],
+}
+
+create_get_security_group_default_rule = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'security_group_default_rule':
+                common_security_group_default_rule_info
+        },
+        'additionalProperties': False,
+        'required': ['security_group_default_rule']
+    }
+}
+
+delete_security_group_default_rule = {
+    'status_code': [204]
+}
+
+list_security_group_default_rules = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'security_group_default_rules': {
+                'type': 'array',
+                'items': common_security_group_default_rule_info
+            }
+        },
+        'additionalProperties': False,
+        'required': ['security_group_default_rules']
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/security_groups.py b/tempest/lib/api_schema/response/compute/v2_1/security_groups.py
new file mode 100644
index 0000000..5ed5a5c
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/security_groups.py
@@ -0,0 +1,113 @@
+# Copyright 2014 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.
+
+common_security_group_rule = {
+    'from_port': {'type': ['integer', 'null']},
+    'to_port': {'type': ['integer', 'null']},
+    'group': {
+        'type': 'object',
+        'properties': {
+            'tenant_id': {'type': 'string'},
+            'name': {'type': 'string'}
+        },
+        'additionalProperties': False,
+    },
+    'ip_protocol': {'type': ['string', 'null']},
+    # 'parent_group_id' can be UUID so defining it as 'string' also.
+    'parent_group_id': {'type': ['string', 'integer', 'null']},
+    'ip_range': {
+        'type': 'object',
+        'properties': {
+            'cidr': {'type': 'string'}
+        },
+        'additionalProperties': False,
+        # When optional argument is provided in request body
+        # like 'group_id' then, attribute 'cidr' does not
+        # comes in response body. So it is not 'required'.
+    },
+    'id': {'type': ['string', 'integer']}
+}
+
+common_security_group = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': ['integer', 'string']},
+        'name': {'type': 'string'},
+        'tenant_id': {'type': 'string'},
+        'rules': {
+            'type': 'array',
+            'items': {
+                'type': ['object', 'null'],
+                'properties': common_security_group_rule,
+                'additionalProperties': False,
+            }
+        },
+        'description': {'type': 'string'},
+    },
+    'additionalProperties': False,
+    'required': ['id', 'name', 'tenant_id', 'rules', 'description'],
+}
+
+list_security_groups = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'security_groups': {
+                'type': 'array',
+                'items': common_security_group
+            }
+        },
+        'additionalProperties': False,
+        'required': ['security_groups']
+    }
+}
+
+get_security_group = create_security_group = update_security_group = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'security_group': common_security_group
+        },
+        'additionalProperties': False,
+        'required': ['security_group']
+    }
+}
+
+delete_security_group = {
+    'status_code': [202]
+}
+
+create_security_group_rule = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'security_group_rule': {
+                'type': 'object',
+                'properties': common_security_group_rule,
+                'additionalProperties': False,
+                'required': ['from_port', 'to_port', 'group', 'ip_protocol',
+                             'parent_group_id', 'id', 'ip_range']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['security_group_rule']
+    }
+}
+
+delete_security_group_rule = {
+    '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
new file mode 100644
index 0000000..3289f04
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/servers.py
@@ -0,0 +1,554 @@
+# Copyright 2014 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
+create_server = {
+    'status_code': [202],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'server': {
+                'type': 'object',
+                'properties': {
+                    'id': {'type': 'string'},
+                    'security_groups': {'type': 'array'},
+                    'links': parameter_types.links,
+                    'OS-DCF:diskConfig': {'type': 'string'}
+                },
+                'additionalProperties': False,
+                # NOTE: OS-DCF:diskConfig & security_groups are API extension,
+                # and some environments return a response without these
+                # attributes.So they are not 'required'.
+                'required': ['id', 'links']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['server']
+    }
+}
+
+create_server_with_admin_pass = copy.deepcopy(create_server)
+create_server_with_admin_pass['response_body']['properties']['server'][
+    'properties'].update({'adminPass': {'type': 'string'}})
+create_server_with_admin_pass['response_body']['properties']['server'][
+    'required'].append('adminPass')
+
+list_servers = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'servers': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'id': {'type': 'string'},
+                        'links': parameter_types.links,
+                        'name': {'type': 'string'}
+                    },
+                    'additionalProperties': False,
+                    'required': ['id', 'links', 'name']
+                }
+            },
+            'servers_links': parameter_types.links
+        },
+        'additionalProperties': False,
+        # NOTE(gmann): servers_links attribute is not necessary to be
+        # present always So it is not 'required'.
+        'required': ['servers']
+    }
+}
+
+delete_server = {
+    'status_code': [204],
+}
+
+common_show_server = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'string'},
+        'name': {'type': 'string'},
+        'status': {'type': 'string'},
+        'image': {'oneOf': [
+            {'type': 'object',
+                'properties': {
+                    'id': {'type': 'string'},
+                    'links': parameter_types.links
+                },
+                'additionalProperties': False,
+                'required': ['id', 'links']},
+            {'type': ['string', 'null']}
+        ]},
+        'flavor': {
+            'type': 'object',
+            'properties': {
+                'id': {'type': 'string'},
+                'links': parameter_types.links
+            },
+            'additionalProperties': False,
+            'required': ['id', 'links']
+        },
+        'fault': {
+            'type': 'object',
+            'properties': {
+                'code': {'type': 'integer'},
+                'created': {'type': 'string'},
+                'message': {'type': 'string'},
+                'details': {'type': 'string'},
+            },
+            'additionalProperties': False,
+            # NOTE(gmann): 'details' is not necessary to be present
+            #  in the 'fault'. So it is not defined as 'required'.
+            'required': ['code', 'created', 'message']
+        },
+        'user_id': {'type': 'string'},
+        'tenant_id': {'type': 'string'},
+        'created': {'type': 'string'},
+        'updated': {'type': 'string'},
+        'progress': {'type': 'integer'},
+        'metadata': {'type': 'object'},
+        'links': parameter_types.links,
+        'addresses': parameter_types.addresses,
+        'hostId': {'type': 'string'},
+        'OS-DCF:diskConfig': {'type': 'string'},
+        'accessIPv4': parameter_types.access_ip_v4,
+        'accessIPv6': parameter_types.access_ip_v6
+    },
+    'additionalProperties': False,
+    # NOTE(GMann): 'progress' attribute is present in the response
+    # only when server's status is one of the progress statuses
+    # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE")
+    # 'fault' attribute is present in the response
+    # only when server's status is one of the  "ERROR", "DELETED".
+    # OS-DCF:diskConfig and accessIPv4/v6 are API
+    # extensions, and some environments return a response
+    # without these attributes.So these are not defined as 'required'.
+    'required': ['id', 'name', 'status', 'image', 'flavor',
+                 'user_id', 'tenant_id', 'created', 'updated',
+                 'metadata', 'links', 'addresses', 'hostId']
+}
+
+update_server = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'server': common_show_server
+        },
+        'additionalProperties': False,
+        'required': ['server']
+    }
+}
+
+server_detail = copy.deepcopy(common_show_server)
+server_detail['properties'].update({
+    'key_name': {'type': ['string', 'null']},
+    'security_groups': {'type': 'array'},
+
+    # NOTE: Non-admin users also can see "OS-SRV-USG" and "OS-EXT-AZ"
+    # attributes.
+    'OS-SRV-USG:launched_at': {'type': ['string', 'null']},
+    'OS-SRV-USG:terminated_at': {'type': ['string', 'null']},
+    'OS-EXT-AZ:availability_zone': {'type': 'string'},
+
+    # NOTE: Admin users only can see "OS-EXT-STS" and "OS-EXT-SRV-ATTR"
+    # attributes.
+    'OS-EXT-STS:task_state': {'type': ['string', 'null']},
+    'OS-EXT-STS:vm_state': {'type': 'string'},
+    'OS-EXT-STS:power_state': {'type': 'integer'},
+    'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']},
+    'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
+    'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
+    'os-extended-volumes:volumes_attached': {'type': 'array'},
+    'config_drive': {'type': 'string'}
+})
+server_detail['properties']['addresses']['patternProperties'][
+    '^[a-zA-Z0-9-_.]+$']['items']['properties'].update({
+        'OS-EXT-IPS:type': {'type': 'string'},
+        'OS-EXT-IPS-MAC:mac_addr': parameter_types.mac_address})
+# NOTE(gmann): Update OS-EXT-IPS:type and OS-EXT-IPS-MAC:mac_addr
+# attributes in server address. Those are API extension,
+# and some environments return a response without
+# these attributes. So they are not 'required'.
+
+get_server = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'server': server_detail
+        },
+        'additionalProperties': False,
+        'required': ['server']
+    }
+}
+
+list_servers_detail = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'servers': {
+                'type': 'array',
+                'items': server_detail
+            },
+            'servers_links': parameter_types.links
+        },
+        'additionalProperties': False,
+        # NOTE(gmann): servers_links attribute is not necessary to be
+        # present always So it is not 'required'.
+        'required': ['servers']
+    }
+}
+
+rebuild_server = copy.deepcopy(update_server)
+rebuild_server['status_code'] = [202]
+
+rebuild_server_with_admin_pass = copy.deepcopy(rebuild_server)
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+    'properties'].update({'adminPass': {'type': 'string'}})
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+    'required'].append('adminPass')
+
+rescue_server = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'adminPass': {'type': 'string'}
+        },
+        'additionalProperties': False,
+        'required': ['adminPass']
+    }
+}
+
+list_virtual_interfaces = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'virtual_interfaces': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'id': {'type': 'string'},
+                        'mac_address': parameter_types.mac_address,
+                        'OS-EXT-VIF-NET:net_id': {'type': 'string'}
+                    },
+                    'additionalProperties': False,
+                    # 'OS-EXT-VIF-NET:net_id' is API extension So it is
+                    # not defined as 'required'
+                    'required': ['id', 'mac_address']
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['virtual_interfaces']
+    }
+}
+
+common_attach_volume_info = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'string'},
+        'device': {'type': ['string', 'null']},
+        'volumeId': {'type': 'string'},
+        'serverId': {'type': ['integer', 'string']}
+    },
+    'additionalProperties': False,
+    # 'device' is optional in response.
+    'required': ['id', 'volumeId', 'serverId']
+}
+
+attach_volume = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'volumeAttachment': common_attach_volume_info
+        },
+        'additionalProperties': False,
+        'required': ['volumeAttachment']
+    }
+}
+
+detach_volume = {
+    'status_code': [202]
+}
+
+show_volume_attachment = copy.deepcopy(attach_volume)
+show_volume_attachment['response_body']['properties'][
+    'volumeAttachment']['properties'].update({'serverId': {'type': 'string'}})
+
+list_volume_attachments = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'volumeAttachments': {
+                'type': 'array',
+                'items': common_attach_volume_info
+            }
+        },
+        'additionalProperties': False,
+        'required': ['volumeAttachments']
+    }
+}
+list_volume_attachments['response_body']['properties'][
+    'volumeAttachments']['items']['properties'].update(
+    {'serverId': {'type': 'string'}})
+
+list_addresses_by_network = {
+    'status_code': [200],
+    'response_body': parameter_types.addresses
+}
+
+list_addresses = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'addresses': parameter_types.addresses
+        },
+        'additionalProperties': False,
+        'required': ['addresses']
+    }
+}
+
+common_server_group = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'string'},
+        'name': {'type': 'string'},
+        'policies': {
+            'type': 'array',
+            'items': {'type': 'string'}
+        },
+        # 'members' attribute contains the array of instance's UUID of
+        # instances present in server group
+        'members': {
+            'type': 'array',
+            'items': {'type': 'string'}
+        },
+        'metadata': {'type': 'object'}
+    },
+    'additionalProperties': False,
+    'required': ['id', 'name', 'policies', 'members', 'metadata']
+}
+
+create_show_server_group = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'server_group': common_server_group
+        },
+        'additionalProperties': False,
+        'required': ['server_group']
+    }
+}
+
+delete_server_group = {
+    'status_code': [204]
+}
+
+list_server_groups = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'server_groups': {
+                'type': 'array',
+                'items': common_server_group
+            }
+        },
+        'additionalProperties': False,
+        'required': ['server_groups']
+    }
+}
+
+instance_actions = {
+    'type': 'object',
+    'properties': {
+        'action': {'type': 'string'},
+        'request_id': {'type': 'string'},
+        'user_id': {'type': 'string'},
+        'project_id': {'type': 'string'},
+        'start_time': {'type': 'string'},
+        'message': {'type': ['string', 'null']},
+        'instance_uuid': {'type': 'string'}
+    },
+    'additionalProperties': False,
+    'required': ['action', 'request_id', 'user_id', 'project_id',
+                 'start_time', 'message', 'instance_uuid']
+}
+
+instance_action_events = {
+    'type': 'array',
+    'items': {
+        'type': 'object',
+        'properties': {
+            'event': {'type': 'string'},
+            'start_time': {'type': 'string'},
+            'finish_time': {'type': 'string'},
+            'result': {'type': 'string'},
+            'traceback': {'type': ['string', 'null']}
+        },
+        'additionalProperties': False,
+        'required': ['event', 'start_time', 'finish_time', 'result',
+                     'traceback']
+    }
+}
+
+list_instance_actions = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'instanceActions': {
+                'type': 'array',
+                'items': instance_actions
+            }
+        },
+        'additionalProperties': False,
+        'required': ['instanceActions']
+    }
+}
+
+instance_actions_with_events = copy.deepcopy(instance_actions)
+instance_actions_with_events['properties'].update({
+    'events': instance_action_events})
+# 'events' does not come in response body always so it is not
+# defined as 'required'
+
+show_instance_action = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'instanceAction': instance_actions_with_events
+        },
+        'additionalProperties': False,
+        'required': ['instanceAction']
+    }
+}
+
+show_password = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'password': {'type': 'string'}
+        },
+        'additionalProperties': False,
+        'required': ['password']
+    }
+}
+
+get_vnc_console = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'console': {
+                'type': 'object',
+                'properties': {
+                    'type': {'type': 'string'},
+                    'url': {
+                        'type': 'string',
+                        'format': 'uri'
+                    }
+                },
+                'additionalProperties': False,
+                'required': ['type', 'url']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['console']
+    }
+}
+
+get_console_output = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'output': {'type': 'string'}
+        },
+        'additionalProperties': False,
+        'required': ['output']
+    }
+}
+
+set_server_metadata = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'metadata': {
+                'type': 'object',
+                'patternProperties': {
+                    '^.+$': {'type': 'string'}
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['metadata']
+    }
+}
+
+list_server_metadata = copy.deepcopy(set_server_metadata)
+
+update_server_metadata = copy.deepcopy(set_server_metadata)
+
+delete_server_metadata_item = {
+    'status_code': [204]
+}
+
+set_show_server_metadata_item = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'meta': {
+                'type': 'object',
+                'patternProperties': {
+                    '^.+$': {'type': 'string'}
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['meta']
+    }
+}
+
+server_actions_common_schema = {
+    'status_code': [202]
+}
+
+server_actions_delete_password = {
+    'status_code': [204]
+}
+
+server_actions_confirm_resize = copy.deepcopy(
+    server_actions_delete_password)
+
+update_attached_volume = {
+    'status_code': [202]
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/services.py b/tempest/lib/api_schema/response/compute/v2_1/services.py
new file mode 100644
index 0000000..ddef7b2
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/services.py
@@ -0,0 +1,65 @@
+# Copyright 2014 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_services = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'services': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'id': {'type': ['integer', 'string'],
+                               'pattern': '^[a-zA-Z!]*@[0-9]+$'},
+                        'zone': {'type': 'string'},
+                        'host': {'type': 'string'},
+                        'state': {'type': 'string'},
+                        'binary': {'type': 'string'},
+                        'status': {'type': 'string'},
+                        'updated_at': {'type': ['string', 'null']},
+                        'disabled_reason': {'type': ['string', 'null']}
+                    },
+                    'additionalProperties': False,
+                    'required': ['id', 'zone', 'host', 'state', 'binary',
+                                 'status', 'updated_at', 'disabled_reason']
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['services']
+    }
+}
+
+enable_disable_service = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'service': {
+                'type': 'object',
+                'properties': {
+                    'status': {'type': 'string'},
+                    'binary': {'type': 'string'},
+                    'host': {'type': 'string'}
+                },
+                'additionalProperties': False,
+                'required': ['status', 'binary', 'host']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['service']
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/snapshots.py b/tempest/lib/api_schema/response/compute/v2_1/snapshots.py
new file mode 100644
index 0000000..01a524b
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/snapshots.py
@@ -0,0 +1,61 @@
+# Copyright 2015 Fujitsu(fnst) 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.
+
+common_snapshot_info = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'string'},
+        'volumeId': {'type': 'string'},
+        'status': {'type': 'string'},
+        'size': {'type': 'integer'},
+        'createdAt': {'type': 'string'},
+        'displayName': {'type': ['string', 'null']},
+        'displayDescription': {'type': ['string', 'null']}
+    },
+    'additionalProperties': False,
+    'required': ['id', 'volumeId', 'status', 'size',
+                 'createdAt', 'displayName', 'displayDescription']
+}
+
+create_get_snapshot = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'snapshot': common_snapshot_info
+        },
+        'additionalProperties': False,
+        'required': ['snapshot']
+    }
+}
+
+list_snapshots = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'snapshots': {
+                'type': 'array',
+                'items': common_snapshot_info
+            }
+        },
+        'additionalProperties': False,
+        'required': ['snapshots']
+    }
+}
+
+delete_snapshot = {
+    'status_code': [202]
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/tenant_networks.py b/tempest/lib/api_schema/response/compute/v2_1/tenant_networks.py
new file mode 100644
index 0000000..ddfab96
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/tenant_networks.py
@@ -0,0 +1,53 @@
+# 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.
+
+param_network = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'string'},
+        'cidr': {'type': ['string', 'null']},
+        'label': {'type': 'string'}
+    },
+    'additionalProperties': False,
+    'required': ['id', 'cidr', 'label']
+}
+
+
+list_tenant_networks = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'networks': {
+                'type': 'array',
+                'items': param_network
+            }
+        },
+        'additionalProperties': False,
+        'required': ['networks']
+    }
+}
+
+
+get_tenant_network = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'network': param_network
+        },
+        'additionalProperties': False,
+        'required': ['network']
+    }
+}
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
new file mode 100644
index 0000000..d51ef12
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/tenant_usages.py
@@ -0,0 +1,92 @@
+# Copyright 2014 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 copy
+
+_server_usages = {
+    'type': 'array',
+    'items': {
+        'type': 'object',
+        'properties': {
+            'ended_at': {
+                'oneOf': [
+                    {'type': 'string'},
+                    {'type': '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'},
+            'state': {'type': 'string'},
+            'tenant_id': {'type': 'string'},
+            'uptime': {'type': 'integer'},
+            'vcpus': {'type': 'integer'},
+        },
+        'required': ['ended_at', 'flavor', 'hours', 'instance_id', 'local_gb',
+                     'memory_mb', 'name', 'started_at', 'state', 'tenant_id',
+                     'uptime', 'vcpus']
+    }
+}
+
+_tenant_usage_list = {
+    'type': 'object',
+    'properties': {
+        'server_usages': _server_usages,
+        'start': {'type': 'string'},
+        'stop': {'type': 'string'},
+        'tenant_id': {'type': 'string'},
+        'total_hours': {'type': 'number'},
+        'total_local_gb_usage': {'type': 'number'},
+        'total_memory_mb_usage': {'type': 'number'},
+        'total_vcpus_usage': {'type': 'number'},
+    },
+    'required': ['start', 'stop', 'tenant_id',
+                 'total_hours', 'total_local_gb_usage',
+                 'total_memory_mb_usage', 'total_vcpus_usage']
+}
+
+# 'required' of get_tenant is different from list_tenant's.
+_tenant_usage_get = copy.deepcopy(_tenant_usage_list)
+_tenant_usage_get['required'] = ['server_usages', 'start', 'stop', 'tenant_id',
+                                 'total_hours', 'total_local_gb_usage',
+                                 'total_memory_mb_usage', 'total_vcpus_usage']
+
+list_tenant_usage = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'tenant_usages': {
+                'type': 'array',
+                'items': _tenant_usage_list
+            }
+        },
+        'required': ['tenant_usages']
+    }
+}
+
+get_tenant_usage = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'tenant_usage': _tenant_usage_get
+        },
+        'required': ['tenant_usage']
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/versions.py b/tempest/lib/api_schema/response/compute/v2_1/versions.py
new file mode 100644
index 0000000..08a9fab
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/versions.py
@@ -0,0 +1,110 @@
+# 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.
+
+import copy
+
+
+_version = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'string'},
+        'links': {
+            'type': 'array',
+            'items': {
+                'type': 'object',
+                'properties': {
+                    'href': {'type': 'string', 'format': 'uri'},
+                    'rel': {'type': 'string'},
+                    'type': {'type': 'string'},
+                },
+                'required': ['href', 'rel'],
+                'additionalProperties': False
+            }
+        },
+        'status': {'type': 'string'},
+        'updated': {'type': 'string', 'format': 'date-time'},
+        'version': {'type': 'string'},
+        'min_version': {'type': 'string'},
+        'media-types': {
+            'type': 'array',
+            'properties': {
+                'base': {'type': 'string'},
+                'type': {'type': 'string'},
+            }
+        },
+    },
+    # NOTE: version and min_version have been added since Kilo,
+    # so they should not be required.
+    # NOTE(sdague): media-types only shows up in single version requests.
+    'required': ['id', 'links', 'status', 'updated'],
+    'additionalProperties': False
+}
+
+list_versions = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'versions': {
+                'type': 'array',
+                'items': _version
+            }
+        },
+        'required': ['versions'],
+        'additionalProperties': False
+    }
+}
+
+
+_detail_get_version = copy.deepcopy(_version)
+_detail_get_version['properties'].pop('min_version')
+_detail_get_version['properties'].pop('version')
+_detail_get_version['properties'].pop('updated')
+_detail_get_version['properties']['media-types'] = {
+    'type': 'array',
+    'items': {
+        'type': 'object',
+        'properties': {
+            'base': {'type': 'string'},
+            'type': {'type': 'string'}
+        }
+    }
+}
+_detail_get_version['required'] = ['id', 'links', 'status', 'media-types']
+
+get_version = {
+    'status_code': [300],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'choices': {
+                'type': 'array',
+                'items': _detail_get_version
+            }
+        },
+        'required': ['choices'],
+        'additionalProperties': False
+    }
+}
+
+get_one_version = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'version': _version
+        },
+        'additionalProperties': False
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/volumes.py b/tempest/lib/api_schema/response/compute/v2_1/volumes.py
new file mode 100644
index 0000000..bb34acb
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_1/volumes.py
@@ -0,0 +1,120 @@
+# Copyright 2014 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.
+
+create_get_volume = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'volume': {
+                'type': 'object',
+                'properties': {
+                    'id': {'type': 'string'},
+                    'status': {'type': 'string'},
+                    'displayName': {'type': ['string', 'null']},
+                    'availabilityZone': {'type': 'string'},
+                    'createdAt': {'type': 'string'},
+                    'displayDescription': {'type': ['string', 'null']},
+                    'volumeType': {'type': ['string', 'null']},
+                    'snapshotId': {'type': ['string', 'null']},
+                    'metadata': {'type': 'object'},
+                    'size': {'type': 'integer'},
+                    'attachments': {
+                        'type': 'array',
+                        'items': {
+                            'type': 'object',
+                            'properties': {
+                                'id': {'type': 'string'},
+                                'device': {'type': 'string'},
+                                'volumeId': {'type': 'string'},
+                                'serverId': {'type': 'string'}
+                            },
+                            'additionalProperties': False,
+                            # NOTE- If volume is not attached to any server
+                            # then, 'attachments' attributes comes as array
+                            # with empty objects "[{}]" due to that elements
+                            # of 'attachments' cannot defined as 'required'.
+                            # If it would come as empty array "[]" then,
+                            # those elements can be defined as 'required'.
+                        }
+                    }
+                },
+                'additionalProperties': False,
+                'required': ['id', 'status', 'displayName', 'availabilityZone',
+                             'createdAt', 'displayDescription', 'volumeType',
+                             'snapshotId', 'metadata', 'size', 'attachments']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['volume']
+    }
+}
+
+list_volumes = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'volumes': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'id': {'type': 'string'},
+                        'status': {'type': 'string'},
+                        'displayName': {'type': ['string', 'null']},
+                        'availabilityZone': {'type': 'string'},
+                        'createdAt': {'type': 'string'},
+                        'displayDescription': {'type': ['string', 'null']},
+                        'volumeType': {'type': ['string', 'null']},
+                        'snapshotId': {'type': ['string', 'null']},
+                        'metadata': {'type': 'object'},
+                        'size': {'type': 'integer'},
+                        'attachments': {
+                            'type': 'array',
+                            'items': {
+                                'type': 'object',
+                                'properties': {
+                                    'id': {'type': 'string'},
+                                    'device': {'type': 'string'},
+                                    'volumeId': {'type': 'string'},
+                                    'serverId': {'type': 'string'}
+                                },
+                                'additionalProperties': False,
+                                # NOTE- If volume is not attached to any server
+                                # then, 'attachments' attributes comes as array
+                                # with empty object "[{}]" due to that elements
+                                # of 'attachments' cannot defined as 'required'
+                                # If it would come as empty array "[]" then,
+                                # those elements can be defined as 'required'.
+                            }
+                        }
+                    },
+                    'additionalProperties': False,
+                    'required': ['id', 'status', 'displayName',
+                                 'availabilityZone', 'createdAt',
+                                 'displayDescription', 'volumeType',
+                                 'snapshotId', 'metadata', 'size',
+                                 'attachments']
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['volumes']
+    }
+}
+
+delete_volume = {
+    'status_code': [202]
+}
diff --git a/tempest/lib/auth.py b/tempest/lib/auth.py
new file mode 100644
index 0000000..2d20a0b
--- /dev/null
+++ b/tempest/lib/auth.py
@@ -0,0 +1,700 @@
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
+# 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 abc
+import copy
+import datetime
+import re
+
+from oslo_log import log as logging
+import six
+from six.moves.urllib import parse as urlparse
+
+from tempest.lib import exceptions
+from tempest.lib.services.identity.v2 import token_client as json_v2id
+from tempest.lib.services.identity.v3 import token_client as json_v3id
+
+ISO8601_FLOAT_SECONDS = '%Y-%m-%dT%H:%M:%S.%fZ'
+ISO8601_INT_SECONDS = '%Y-%m-%dT%H:%M:%SZ'
+LOG = logging.getLogger(__name__)
+
+
+@six.add_metaclass(abc.ABCMeta)
+class AuthProvider(object):
+    """Provide authentication"""
+
+    def __init__(self, credentials):
+        """Auth provider __init__
+
+        :param credentials: credentials for authentication
+        """
+        if self.check_credentials(credentials):
+            self.credentials = credentials
+        else:
+            if isinstance(credentials, Credentials):
+                password = credentials.get('password')
+                message = "Credentials are: " + str(credentials)
+                if password is None:
+                    message += " Password is not defined."
+                else:
+                    message += " Password is defined."
+                raise exceptions.InvalidCredentials(message)
+            else:
+                raise TypeError("credentials object is of type %s, which is"
+                                " not a valid Credentials object type." %
+                                credentials.__class__.__name__)
+        self.cache = None
+        self.alt_auth_data = None
+        self.alt_part = None
+
+    def __str__(self):
+        return "Creds :{creds}, cached auth data: {cache}".format(
+            creds=self.credentials, cache=self.cache)
+
+    @abc.abstractmethod
+    def _decorate_request(self, filters, method, url, headers=None, body=None,
+                          auth_data=None):
+        """Decorate request with authentication data"""
+        return
+
+    @abc.abstractmethod
+    def _get_auth(self):
+        return
+
+    @abc.abstractmethod
+    def _fill_credentials(self, auth_data_body):
+        return
+
+    def fill_credentials(self):
+        """Fill credentials object with data from auth"""
+        auth_data = self.get_auth()
+        self._fill_credentials(auth_data[1])
+        return self.credentials
+
+    @classmethod
+    def check_credentials(cls, credentials):
+        """Verify credentials are valid."""
+        return isinstance(credentials, Credentials) and credentials.is_valid()
+
+    @property
+    def auth_data(self):
+        return self.get_auth()
+
+    @auth_data.deleter
+    def auth_data(self):
+        self.clear_auth()
+
+    def get_auth(self):
+        """Returns auth from cache if available, else auth first"""
+        if self.cache is None or self.is_expired(self.cache):
+            self.set_auth()
+        return self.cache
+
+    def set_auth(self):
+        """Forces setting auth.
+
+        Forces setting auth, ignores cache if it exists.
+        Refills credentials
+        """
+        self.cache = self._get_auth()
+        self._fill_credentials(self.cache[1])
+
+    def clear_auth(self):
+        """Clear access cache
+
+        Can be called to clear the access cache so that next request
+        will fetch a new token and base_url.
+        """
+        self.cache = None
+        self.credentials.reset()
+
+    @abc.abstractmethod
+    def is_expired(self, auth_data):
+        return
+
+    def auth_request(self, method, url, headers=None, body=None, filters=None):
+        """Obtains auth data and decorates a request with that.
+
+        :param method: HTTP method of the request
+        :param url: relative URL of the request (path)
+        :param headers: HTTP headers of the request
+        :param body: HTTP body in case of POST / PUT
+        :param filters: select a base URL out of the catalog
+        :returns a Tuple (url, headers, body)
+        """
+        orig_req = dict(url=url, headers=headers, body=body)
+
+        auth_url, auth_headers, auth_body = self._decorate_request(
+            filters, method, url, headers, body)
+        auth_req = dict(url=auth_url, headers=auth_headers, body=auth_body)
+
+        # Overwrite part if the request if it has been requested
+        if self.alt_part is not None:
+            if self.alt_auth_data is not None:
+                alt_url, alt_headers, alt_body = self._decorate_request(
+                    filters, method, url, headers, body,
+                    auth_data=self.alt_auth_data)
+                alt_auth_req = dict(url=alt_url, headers=alt_headers,
+                                    body=alt_body)
+                if auth_req[self.alt_part] == alt_auth_req[self.alt_part]:
+                    raise exceptions.BadAltAuth(part=self.alt_part)
+                auth_req[self.alt_part] = alt_auth_req[self.alt_part]
+
+            else:
+                # If the requested part is not affected by auth, we are
+                # not altering auth as expected, raise an exception
+                if auth_req[self.alt_part] == orig_req[self.alt_part]:
+                    raise exceptions.BadAltAuth(part=self.alt_part)
+                # If alt auth data is None, skip auth in the requested part
+                auth_req[self.alt_part] = orig_req[self.alt_part]
+
+            # Next auth request will be normal, unless otherwise requested
+            self.reset_alt_auth_data()
+
+        return auth_req['url'], auth_req['headers'], auth_req['body']
+
+    def reset_alt_auth_data(self):
+        """Configure auth provider to provide valid authentication data"""
+        self.alt_part = None
+        self.alt_auth_data = None
+
+    def set_alt_auth_data(self, request_part, auth_data):
+        """Alternate auth data on next request
+
+        Configure auth provider to provide alt authentication data
+        on a part of the *next* auth_request. If credentials are None,
+        set invalid data.
+        :param request_part: request part to contain invalid auth: url,
+                             headers, body
+        :param auth_data: alternative auth_data from which to get the
+                          invalid data to be injected
+        """
+        self.alt_part = request_part
+        self.alt_auth_data = auth_data
+
+    @abc.abstractmethod
+    def base_url(self, filters, auth_data=None):
+        """Extracts the base_url based on provided filters"""
+        return
+
+
+class KeystoneAuthProvider(AuthProvider):
+
+    EXPIRY_DATE_FORMATS = (ISO8601_FLOAT_SECONDS, ISO8601_INT_SECONDS)
+
+    token_expiry_threshold = datetime.timedelta(seconds=60)
+
+    def __init__(self, credentials, auth_url,
+                 disable_ssl_certificate_validation=None,
+                 ca_certs=None, trace_requests=None):
+        super(KeystoneAuthProvider, self).__init__(credentials)
+        self.dsvm = disable_ssl_certificate_validation
+        self.ca_certs = ca_certs
+        self.trace_requests = trace_requests
+        self.auth_client = self._auth_client(auth_url)
+
+    def _decorate_request(self, filters, method, url, headers=None, body=None,
+                          auth_data=None):
+        if auth_data is None:
+            auth_data = self.auth_data
+        token, _ = auth_data
+        base_url = self.base_url(filters=filters, auth_data=auth_data)
+        # build authenticated request
+        # returns new request, it does not touch the original values
+        _headers = copy.deepcopy(headers) if headers is not None else {}
+        _headers['X-Auth-Token'] = str(token)
+        if url is None or url == "":
+            _url = base_url
+        else:
+            # Join base URL and url, and remove multiple contiguous slashes
+            _url = "/".join([base_url, url])
+            parts = [x for x in urlparse.urlparse(_url)]
+            parts[2] = re.sub("/{2,}", "/", parts[2])
+            _url = urlparse.urlunparse(parts)
+        # no change to method or body
+        return str(_url), _headers, body
+
+    @abc.abstractmethod
+    def _auth_client(self):
+        return
+
+    @abc.abstractmethod
+    def _auth_params(self):
+        return
+
+    def _get_auth(self):
+        # Bypasses the cache
+        auth_func = getattr(self.auth_client, 'get_token')
+        auth_params = self._auth_params()
+
+        # returns token, auth_data
+        token, auth_data = auth_func(**auth_params)
+        return token, auth_data
+
+    def _parse_expiry_time(self, expiry_string):
+        expiry = None
+        for date_format in self.EXPIRY_DATE_FORMATS:
+            try:
+                expiry = datetime.datetime.strptime(
+                    expiry_string, date_format)
+            except ValueError:
+                pass
+        if expiry is None:
+            raise ValueError(
+                "time data '{data}' does not match any of the"
+                "expected formats: {formats}".format(
+                    data=expiry_string, formats=self.EXPIRY_DATE_FORMATS))
+        return expiry
+
+    def get_token(self):
+        return self.auth_data[0]
+
+
+class KeystoneV2AuthProvider(KeystoneAuthProvider):
+
+    def _auth_client(self, auth_url):
+        return json_v2id.TokenClient(
+            auth_url, disable_ssl_certificate_validation=self.dsvm,
+            ca_certs=self.ca_certs, trace_requests=self.trace_requests)
+
+    def _auth_params(self):
+        return dict(
+            user=self.credentials.username,
+            password=self.credentials.password,
+            tenant=self.credentials.tenant_name,
+            auth_data=True)
+
+    def _fill_credentials(self, auth_data_body):
+        tenant = auth_data_body['token']['tenant']
+        user = auth_data_body['user']
+        if self.credentials.tenant_name is None:
+            self.credentials.tenant_name = tenant['name']
+        if self.credentials.tenant_id is None:
+            self.credentials.tenant_id = tenant['id']
+        if self.credentials.username is None:
+            self.credentials.username = user['name']
+        if self.credentials.user_id is None:
+            self.credentials.user_id = user['id']
+
+    def base_url(self, filters, auth_data=None):
+        """Base URL from catalog
+
+        Filters can be:
+        - service: compute, image, etc
+        - region: the service region
+        - endpoint_type: adminURL, publicURL, internalURL
+        - api_version: replace catalog version with this
+        - skip_path: take just the base URL
+        """
+        if auth_data is None:
+            auth_data = self.auth_data
+        token, _auth_data = auth_data
+        service = filters.get('service')
+        region = filters.get('region')
+        endpoint_type = filters.get('endpoint_type', 'publicURL')
+
+        if service is None:
+            raise exceptions.EndpointNotFound("No service provided")
+
+        _base_url = None
+        for ep in _auth_data['serviceCatalog']:
+            if ep["type"] == service:
+                for _ep in ep['endpoints']:
+                    if region is not None and _ep['region'] == region:
+                        _base_url = _ep.get(endpoint_type)
+                if not _base_url:
+                    # No region matching, use the first
+                    _base_url = ep['endpoints'][0].get(endpoint_type)
+                break
+        if _base_url is None:
+            raise exceptions.EndpointNotFound(
+                "service: %s, region: %s, endpoint_type: %s" %
+                (service, region, endpoint_type))
+
+        parts = urlparse.urlparse(_base_url)
+        if filters.get('api_version', None) is not None:
+            version_path = '/%s' % filters['api_version']
+            path = re.sub(r'(^|/)+v\d+(?:\.\d+)?',
+                          version_path,
+                          parts.path,
+                          count=1)
+            _base_url = urlparse.urlunparse((parts.scheme,
+                                             parts.netloc,
+                                             path or version_path,
+                                             parts.params,
+                                             parts.query,
+                                             parts.fragment))
+        if filters.get('skip_path', None) is not None and parts.path != '':
+            _base_url = urlparse.urlunparse((parts.scheme,
+                                             parts.netloc,
+                                             '/',
+                                             parts.params,
+                                             parts.query,
+                                             parts.fragment))
+
+        return _base_url
+
+    def is_expired(self, auth_data):
+        _, access = auth_data
+        expiry = self._parse_expiry_time(access['token']['expires'])
+        return (expiry - self.token_expiry_threshold <=
+                datetime.datetime.utcnow())
+
+
+class KeystoneV3AuthProvider(KeystoneAuthProvider):
+
+    def _auth_client(self, auth_url):
+        return json_v3id.V3TokenClient(
+            auth_url, disable_ssl_certificate_validation=self.dsvm,
+            ca_certs=self.ca_certs, trace_requests=self.trace_requests)
+
+    def _auth_params(self):
+        return dict(
+            user_id=self.credentials.user_id,
+            username=self.credentials.username,
+            password=self.credentials.password,
+            project_id=self.credentials.project_id,
+            project_name=self.credentials.project_name,
+            user_domain_id=self.credentials.user_domain_id,
+            user_domain_name=self.credentials.user_domain_name,
+            project_domain_id=self.credentials.project_domain_id,
+            project_domain_name=self.credentials.project_domain_name,
+            domain_id=self.credentials.domain_id,
+            domain_name=self.credentials.domain_name,
+            auth_data=True)
+
+    def _fill_credentials(self, auth_data_body):
+        # project or domain, depending on the scope
+        project = auth_data_body.get('project', None)
+        domain = auth_data_body.get('domain', None)
+        # user is always there
+        user = auth_data_body['user']
+        # Set project fields
+        if project is not None:
+            if self.credentials.project_name is None:
+                self.credentials.project_name = project['name']
+            if self.credentials.project_id is None:
+                self.credentials.project_id = project['id']
+            if self.credentials.project_domain_id is None:
+                self.credentials.project_domain_id = project['domain']['id']
+            if self.credentials.project_domain_name is None:
+                self.credentials.project_domain_name = (
+                    project['domain']['name'])
+        # Set domain fields
+        if domain is not None:
+            if self.credentials.domain_id is None:
+                self.credentials.domain_id = domain['id']
+            if self.credentials.domain_name is None:
+                self.credentials.domain_name = domain['name']
+        # Set user fields
+        if self.credentials.username is None:
+            self.credentials.username = user['name']
+        if self.credentials.user_id is None:
+            self.credentials.user_id = user['id']
+        if self.credentials.user_domain_id is None:
+            self.credentials.user_domain_id = user['domain']['id']
+        if self.credentials.user_domain_name is None:
+            self.credentials.user_domain_name = user['domain']['name']
+
+    def base_url(self, filters, auth_data=None):
+        """Base URL from catalog
+
+        Filters can be:
+        - service: compute, image, etc
+        - region: the service region
+        - endpoint_type: adminURL, publicURL, internalURL
+        - api_version: replace catalog version with this
+        - skip_path: take just the base URL
+        """
+        if auth_data is None:
+            auth_data = self.auth_data
+        token, _auth_data = auth_data
+        service = filters.get('service')
+        region = filters.get('region')
+        endpoint_type = filters.get('endpoint_type', 'public')
+
+        if service is None:
+            raise exceptions.EndpointNotFound("No service provided")
+
+        if 'URL' in endpoint_type:
+            endpoint_type = endpoint_type.replace('URL', '')
+        _base_url = None
+        catalog = _auth_data['catalog']
+        # Select entries with matching service type
+        service_catalog = [ep for ep in catalog if ep['type'] == service]
+        if len(service_catalog) > 0:
+            service_catalog = service_catalog[0]['endpoints']
+        else:
+            # No matching service
+            raise exceptions.EndpointNotFound(service)
+        # Filter by endpoint type (interface)
+        filtered_catalog = [ep for ep in service_catalog if
+                            ep['interface'] == endpoint_type]
+        if len(filtered_catalog) == 0:
+            # No matching type, keep all and try matching by region at least
+            filtered_catalog = service_catalog
+        # Filter by region
+        filtered_catalog = [ep for ep in filtered_catalog if
+                            ep['region'] == region]
+        if len(filtered_catalog) == 0:
+            # No matching region, take the first endpoint
+            filtered_catalog = [service_catalog[0]]
+        # There should be only one match. If not take the first.
+        _base_url = filtered_catalog[0].get('url', None)
+        if _base_url is None:
+                raise exceptions.EndpointNotFound(service)
+
+        parts = urlparse.urlparse(_base_url)
+        if filters.get('api_version', None) is not None:
+            version_path = '/%s' % filters['api_version']
+            path = re.sub(r'(^|/)+v\d+(?:\.\d+)?',
+                          version_path,
+                          parts.path,
+                          count=1)
+            _base_url = urlparse.urlunparse((parts.scheme,
+                                             parts.netloc,
+                                             path or version_path,
+                                             parts.params,
+                                             parts.query,
+                                             parts.fragment))
+        if filters.get('skip_path', None) is not None:
+            _base_url = urlparse.urlunparse((parts.scheme,
+                                             parts.netloc,
+                                             '/',
+                                             parts.params,
+                                             parts.query,
+                                             parts.fragment))
+
+        return _base_url
+
+    def is_expired(self, auth_data):
+        _, access = auth_data
+        expiry = self._parse_expiry_time(access['expires_at'])
+        return (expiry - self.token_expiry_threshold <=
+                datetime.datetime.utcnow())
+
+
+def is_identity_version_supported(identity_version):
+    return identity_version in IDENTITY_VERSION
+
+
+def get_credentials(auth_url, fill_in=True, identity_version='v2',
+                    disable_ssl_certificate_validation=None, ca_certs=None,
+                    trace_requests=None, **kwargs):
+    """Builds a credentials object based on the configured auth_version
+
+    :param auth_url (string): Full URI of the OpenStack Identity API(Keystone)
+           which is used to fetch the token from Identity service.
+    :param fill_in (boolean): obtain a token and fill in all credential
+           details provided by the identity service. When fill_in is not
+           specified, credentials are not validated. Validation can be invoked
+           by invoking ``is_valid()``
+    :param identity_version (string): identity API version is used to
+           select the matching auth provider and credentials class
+    :param disable_ssl_certificate_validation: whether to enforce SSL
+           certificate validation in SSL API requests to the auth system
+    :param ca_certs: CA certificate bundle for validation of certificates
+           in SSL API requests to the auth system
+    :param trace_requests: trace in log API requests to the auth system
+    :param kwargs (dict): Dict of credential key/value pairs
+
+    Examples:
+
+        Returns credentials from the provided parameters:
+        >>> get_credentials(username='foo', password='bar')
+
+        Returns credentials including IDs:
+        >>> get_credentials(username='foo', password='bar', fill_in=True)
+    """
+    if not is_identity_version_supported(identity_version):
+        raise exceptions.InvalidIdentityVersion(
+            identity_version=identity_version)
+
+    credential_class, auth_provider_class = IDENTITY_VERSION.get(
+        identity_version)
+
+    creds = credential_class(**kwargs)
+    # Fill in the credentials fields that were not specified
+    if fill_in:
+        dsvm = disable_ssl_certificate_validation
+        auth_provider = auth_provider_class(
+            creds, auth_url, disable_ssl_certificate_validation=dsvm,
+            ca_certs=ca_certs, trace_requests=trace_requests)
+        creds = auth_provider.fill_credentials()
+    return creds
+
+
+class Credentials(object):
+    """Set of credentials for accessing OpenStack services
+
+    ATTRIBUTES: list of valid class attributes representing credentials.
+    """
+
+    ATTRIBUTES = []
+
+    def __init__(self, **kwargs):
+        """Enforce the available attributes at init time (only).
+
+        Additional attributes can still be set afterwards if tests need
+        to do so.
+        """
+        self._initial = kwargs
+        self._apply_credentials(kwargs)
+
+    def _apply_credentials(self, attr):
+        for key in attr.keys():
+            if key in self.ATTRIBUTES:
+                setattr(self, key, attr[key])
+            else:
+                msg = '%s is not a valid attr for %s' % (key, self.__class__)
+                raise exceptions.InvalidCredentials(msg)
+
+    def __str__(self):
+        """Represent only attributes included in self.ATTRIBUTES"""
+        attrs = [attr for attr in self.ATTRIBUTES if attr is not 'password']
+        _repr = dict((k, getattr(self, k)) for k in attrs)
+        return str(_repr)
+
+    def __eq__(self, other):
+        """Credentials are equal if attributes in self.ATTRIBUTES are equal"""
+        return str(self) == str(other)
+
+    def __getattr__(self, key):
+        # If an attribute is set, __getattr__ is not invoked
+        # If an attribute is not set, and it is a known one, return None
+        if key in self.ATTRIBUTES:
+            return None
+        else:
+            raise AttributeError
+
+    def __delitem__(self, key):
+        # For backwards compatibility, support dict behaviour
+        if key in self.ATTRIBUTES:
+            delattr(self, key)
+        else:
+            raise AttributeError
+
+    def get(self, item, default=None):
+        # In this patch act as dict for backward compatibility
+        try:
+            return getattr(self, item)
+        except AttributeError:
+            return default
+
+    def get_init_attributes(self):
+        return self._initial.keys()
+
+    def is_valid(self):
+        raise NotImplementedError
+
+    def reset(self):
+        # First delete all known attributes
+        for key in self.ATTRIBUTES:
+            if getattr(self, key) is not None:
+                delattr(self, key)
+        # Then re-apply initial setup
+        self._apply_credentials(self._initial)
+
+
+class KeystoneV2Credentials(Credentials):
+
+    ATTRIBUTES = ['username', 'password', 'tenant_name', 'user_id',
+                  'tenant_id']
+
+    def is_valid(self):
+        """Check of credentials (no API call)
+
+        Minimum set of valid credentials, are username and password.
+        Tenant is optional.
+        """
+        return None not in (self.username, self.password)
+
+
+class KeystoneV3Credentials(Credentials):
+    """Credentials suitable for the Keystone Identity V3 API"""
+
+    ATTRIBUTES = ['domain_id', 'domain_name', 'password', 'username',
+                  'project_domain_id', 'project_domain_name', 'project_id',
+                  'project_name', 'tenant_id', 'tenant_name', 'user_domain_id',
+                  'user_domain_name', 'user_id']
+
+    def __setattr__(self, key, value):
+        parent = super(KeystoneV3Credentials, self)
+        # for tenant_* set both project and tenant
+        if key == 'tenant_id':
+            parent.__setattr__('project_id', value)
+        elif key == 'tenant_name':
+            parent.__setattr__('project_name', value)
+        # for project_* set both project and tenant
+        if key == 'project_id':
+            parent.__setattr__('tenant_id', value)
+        elif key == 'project_name':
+            parent.__setattr__('tenant_name', value)
+        # for *_domain_* set both user and project if not set yet
+        if key == 'user_domain_id':
+            if self.project_domain_id is None:
+                parent.__setattr__('project_domain_id', value)
+        if key == 'project_domain_id':
+            if self.user_domain_id is None:
+                parent.__setattr__('user_domain_id', value)
+        if key == 'user_domain_name':
+            if self.project_domain_name is None:
+                parent.__setattr__('project_domain_name', value)
+        if key == 'project_domain_name':
+            if self.user_domain_name is None:
+                parent.__setattr__('user_domain_name', value)
+        # support domain_name coming from config
+        if key == 'domain_name':
+            parent.__setattr__('user_domain_name', value)
+            parent.__setattr__('project_domain_name', value)
+        # finally trigger default behaviour for all attributes
+        parent.__setattr__(key, value)
+
+    def is_valid(self):
+        """Check of credentials (no API call)
+
+        Valid combinations of v3 credentials (excluding token, scope)
+        - User id, password (optional domain)
+        - User name, password and its domain id/name
+        For the scope, valid combinations are:
+        - None
+        - Project id (optional domain)
+        - Project name and its domain id/name
+        - Domain id
+        - Domain name
+        """
+        valid_user_domain = any(
+            [self.user_domain_id is not None,
+             self.user_domain_name is not None])
+        valid_project_domain = any(
+            [self.project_domain_id is not None,
+             self.project_domain_name is not None])
+        valid_user = any(
+            [self.user_id is not None,
+             self.username is not None and valid_user_domain])
+        valid_project_scope = any(
+            [self.project_name is None and self.project_id is None,
+             self.project_id is not None,
+             self.project_name is not None and valid_project_domain])
+        valid_domain_scope = any(
+            [self.domain_id is None and self.domain_name is None,
+             self.domain_id or self.domain_name])
+        return all([self.password is not None,
+                    valid_user,
+                    valid_project_scope and valid_domain_scope])
+
+
+IDENTITY_VERSION = {'v2': (KeystoneV2Credentials, KeystoneV2AuthProvider),
+                    'v3': (KeystoneV3Credentials, KeystoneV3AuthProvider)}
diff --git a/tempest/lib/base.py b/tempest/lib/base.py
new file mode 100644
index 0000000..227ac37
--- /dev/null
+++ b/tempest/lib/base.py
@@ -0,0 +1,71 @@
+# 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.
+
+import logging
+import os
+
+import fixtures
+import testtools
+
+LOG = logging.getLogger(__name__)
+
+
+class BaseTestCase(testtools.testcase.WithAttributes, testtools.TestCase):
+    setUpClassCalled = False
+
+    # NOTE(sdague): log_format is defined inline here instead of using the oslo
+    # default because going through the config path recouples config to the
+    # stress tests too early, and depending on testr order will fail unit tests
+    log_format = ('%(asctime)s %(process)d %(levelname)-8s '
+                  '[%(name)s] %(message)s')
+
+    @classmethod
+    def setUpClass(cls):
+        if hasattr(super(BaseTestCase, cls), 'setUpClass'):
+            super(BaseTestCase, cls).setUpClass()
+        cls.setUpClassCalled = True
+
+    @classmethod
+    def tearDownClass(cls):
+        if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
+            super(BaseTestCase, cls).tearDownClass()
+
+    def setUp(self):
+        super(BaseTestCase, self).setUp()
+        if not self.setUpClassCalled:
+            raise RuntimeError("setUpClass does not calls the super's"
+                               "setUpClass in the "
+                               + self.__class__.__name__)
+        test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
+        try:
+            test_timeout = int(test_timeout)
+        except ValueError:
+            test_timeout = 0
+        if test_timeout > 0:
+            self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
+
+        if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
+                os.environ.get('OS_STDOUT_CAPTURE') == '1'):
+            stdout = self.useFixture(fixtures.StringStream('stdout')).stream
+            self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
+        if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
+                os.environ.get('OS_STDERR_CAPTURE') == '1'):
+            stderr = self.useFixture(fixtures.StringStream('stderr')).stream
+            self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
+        if (os.environ.get('OS_LOG_CAPTURE') != 'False' and
+            os.environ.get('OS_LOG_CAPTURE') != '0'):
+            self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
+                                                   format=self.log_format,
+                                                   level=None))
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/cli/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/cli/__init__.py
diff --git a/tempest/lib/cli/base.py b/tempest/lib/cli/base.py
new file mode 100644
index 0000000..54f35f4
--- /dev/null
+++ b/tempest/lib/cli/base.py
@@ -0,0 +1,410 @@
+# Copyright 2013 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 logging
+import os
+import shlex
+import subprocess
+
+import six
+
+from tempest.lib import base
+import tempest.lib.cli.output_parser
+from tempest.lib import exceptions
+
+
+LOG = logging.getLogger(__name__)
+
+
+def execute(cmd, action, flags='', params='', fail_ok=False,
+            merge_stderr=False, cli_dir='/usr/bin'):
+    """Executes specified command for the given action.
+
+    :param cmd: command to be executed
+    :type cmd: string
+    :param action: string of the cli command to run
+    :type action: string
+    :param flags: any optional cli flags to use
+    :type flags: string
+    :param params: string of any optional positional args to use
+    :type params: string
+    :param fail_ok: boolean if True an exception is not raised when the
+                    cli return code is non-zero
+    :type fail_ok: boolean
+    :param merge_stderr: boolean if True the stderr buffer is merged into
+                         stdout
+    :type merge_stderr: boolean
+    :param cli_dir: The path where the cmd can be executed
+    :type cli_dir: string
+    """
+    cmd = ' '.join([os.path.join(cli_dir, cmd),
+                    flags, action, params])
+    LOG.info("running: '%s'" % cmd)
+    if six.PY2:
+        cmd = cmd.encode('utf-8')
+    cmd = shlex.split(cmd)
+    result = ''
+    result_err = ''
+    stdout = subprocess.PIPE
+    stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE
+    proc = subprocess.Popen(cmd, stdout=stdout, stderr=stderr)
+    result, result_err = proc.communicate()
+    if not fail_ok and proc.returncode != 0:
+        raise exceptions.CommandFailed(proc.returncode,
+                                       cmd,
+                                       result,
+                                       result_err)
+    if six.PY2:
+        return result
+    else:
+        return os.fsdecode(result)
+
+
+class CLIClient(object):
+    """Class to use OpenStack official python client CLI's with auth
+
+    :param username: The username to authenticate with
+    :type username: string
+    :param password: The password to authenticate with
+    :type password: string
+    :param tenant_name: The name of the tenant to use with the client calls
+    :type tenant_name: string
+    :param uri: The auth uri for the OpenStack Deployment
+    :type uri: string
+    :param cli_dir: The path where the python client binaries are installed.
+                    defaults to /usr/bin
+    :type cli_dir: string
+    :param insecure: if True, --insecure is passed to python client binaries.
+    :type insecure: boolean
+    """
+
+    def __init__(self, username='', password='', tenant_name='', uri='',
+                 cli_dir='', insecure=False, *args, **kwargs):
+        """Initialize a new CLIClient object."""
+        super(CLIClient, self).__init__()
+        self.cli_dir = cli_dir if cli_dir else '/usr/bin'
+        self.username = username
+        self.tenant_name = tenant_name
+        self.password = password
+        self.uri = uri
+        self.insecure = insecure
+
+    def nova(self, action, flags='', params='', fail_ok=False,
+             endpoint_type='publicURL', merge_stderr=False):
+        """Executes nova command for the given action.
+
+        :param action: the cli command to run using nova
+        :type action: string
+        :param flags: any optional cli flags to use
+        :type flags: string
+        :param params: any optional positional args to use
+        :type params: string
+        :param fail_ok: if True an exception is not raised when the
+                        cli return code is non-zero
+        :type fail_ok: boolean
+        :param endpoint_type: the type of endpoint for the service
+        :type endpoint_type: string
+        :param merge_stderr: if True the stderr buffer is merged into stdout
+        :type merge_stderr: boolean
+        """
+        flags += ' --endpoint-type %s' % endpoint_type
+        return self.cmd_with_auth(
+            'nova', action, flags, params, fail_ok, merge_stderr)
+
+    def nova_manage(self, action, flags='', params='', fail_ok=False,
+                    merge_stderr=False):
+        """Executes nova-manage command for the given action.
+
+        :param action: the cli command to run using nova-manage
+        :type action: string
+        :param flags: any optional cli flags to use
+        :type flags: string
+        :param params: any optional positional args to use
+        :type params: string
+        :param fail_ok: if True an exception is not raised when the
+                        cli return code is non-zero
+        :type fail_ok: boolean
+        :param merge_stderr: if True the stderr buffer is merged into stdout
+        :type merge_stderr: boolean
+        """
+        return execute(
+            'nova-manage', action, flags, params, fail_ok, merge_stderr,
+            self.cli_dir)
+
+    def keystone(self, action, flags='', params='', fail_ok=False,
+                 merge_stderr=False):
+        """Executes keystone command for the given action.
+
+        :param action: the cli command to run using keystone
+        :type action: string
+        :param flags: any optional cli flags to use
+        :type flags: string
+        :param params: any optional positional args to use
+        :type params: string
+        :param fail_ok: if True an exception is not raised when the
+                        cli return code is non-zero
+        :type fail_ok: boolean
+        :param merge_stderr: if True the stderr buffer is merged into stdout
+        :type merge_stderr: boolean
+        """
+        return self.cmd_with_auth(
+            'keystone', action, flags, params, fail_ok, merge_stderr)
+
+    def glance(self, action, flags='', params='', fail_ok=False,
+               endpoint_type='publicURL', merge_stderr=False):
+        """Executes glance command for the given action.
+
+        :param action: the cli command to run using glance
+        :type action: string
+        :param flags: any optional cli flags to use
+        :type flags: string
+        :param params: any optional positional args to use
+        :type params: string
+        :param fail_ok: if True an exception is not raised when the
+                        cli return code is non-zero
+        :type fail_ok: boolean
+        :param endpoint_type: the type of endpoint for the service
+        :type endpoint_type: string
+        :param merge_stderr: if True the stderr buffer is merged into stdout
+        :type merge_stderr: boolean
+        """
+        flags += ' --os-endpoint-type %s' % endpoint_type
+        return self.cmd_with_auth(
+            'glance', action, flags, params, fail_ok, merge_stderr)
+
+    def ceilometer(self, action, flags='', params='',
+                   fail_ok=False, endpoint_type='publicURL',
+                   merge_stderr=False):
+        """Executes ceilometer command for the given action.
+
+        :param action: the cli command to run using ceilometer
+        :type action: string
+        :param flags: any optional cli flags to use
+        :type flags: string
+        :param params: any optional positional args to use
+        :type params: string
+        :param fail_ok: if True an exception is not raised when the
+                        cli return code is non-zero
+        :type fail_ok: boolean
+        :param endpoint_type: the type of endpoint for the service
+        :type endpoint_type: string
+        :param merge_stderr: if True the stderr buffer is merged into stdout
+        :type merge_stderr: boolean
+        """
+        flags += ' --os-endpoint-type %s' % endpoint_type
+        return self.cmd_with_auth(
+            'ceilometer', action, flags, params, fail_ok, merge_stderr)
+
+    def heat(self, action, flags='', params='',
+             fail_ok=False, endpoint_type='publicURL', merge_stderr=False):
+        """Executes heat command for the given action.
+
+        :param action: the cli command to run using heat
+        :type action: string
+        :param flags: any optional cli flags to use
+        :type flags: string
+        :param params: any optional positional args to use
+        :type params: string
+        :param fail_ok: if True an exception is not raised when the
+                        cli return code is non-zero
+        :type fail_ok: boolean
+        :param endpoint_type: the type of endpoint for the service
+        :type endpoint_type: string
+        :param merge_stderr: if True the stderr buffer is merged into stdout
+        :type merge_stderr: boolean
+        """
+        flags += ' --os-endpoint-type %s' % endpoint_type
+        return self.cmd_with_auth(
+            'heat', action, flags, params, fail_ok, merge_stderr)
+
+    def cinder(self, action, flags='', params='', fail_ok=False,
+               endpoint_type='publicURL', merge_stderr=False):
+        """Executes cinder command for the given action.
+
+        :param action: the cli command to run using cinder
+        :type action: string
+        :param flags: any optional cli flags to use
+        :type flags: string
+        :param params: any optional positional args to use
+        :type params: string
+        :param fail_ok: if True an exception is not raised when the
+                        cli return code is non-zero
+        :type fail_ok: boolean
+        :param endpoint_type: the type of endpoint for the service
+        :type endpoint_type: string
+        :param merge_stderr: if True the stderr buffer is merged into stdout
+        :type merge_stderr: boolean
+        """
+        flags += ' --endpoint-type %s' % endpoint_type
+        return self.cmd_with_auth(
+            'cinder', action, flags, params, fail_ok, merge_stderr)
+
+    def swift(self, action, flags='', params='', fail_ok=False,
+              endpoint_type='publicURL', merge_stderr=False):
+        """Executes swift command for the given action.
+
+        :param action: the cli command to run using swift
+        :type action: string
+        :param flags: any optional cli flags to use
+        :type flags: string
+        :param params: any optional positional args to use
+        :type params: string
+        :param fail_ok: if True an exception is not raised when the
+                        cli return code is non-zero
+        :type fail_ok: boolean
+        :param endpoint_type: the type of endpoint for the service
+        :type endpoint_type: string
+        :param merge_stderr: if True the stderr buffer is merged into stdout
+        :type merge_stderr: boolean
+        """
+        flags += ' --os-endpoint-type %s' % endpoint_type
+        return self.cmd_with_auth(
+            'swift', action, flags, params, fail_ok, merge_stderr)
+
+    def neutron(self, action, flags='', params='', fail_ok=False,
+                endpoint_type='publicURL', merge_stderr=False):
+        """Executes neutron command for the given action.
+
+        :param action: the cli command to run using neutron
+        :type action: string
+        :param flags: any optional cli flags to use
+        :type flags: string
+        :param params: any optional positional args to use
+        :type params: string
+        :param fail_ok: if True an exception is not raised when the
+                        cli return code is non-zero
+        :type fail_ok: boolean
+        :param endpoint_type: the type of endpoint for the service
+        :type endpoint_type: string
+        :param merge_stderr: if True the stderr buffer is merged into stdout
+        :type merge_stderr: boolean
+        """
+        flags += ' --endpoint-type %s' % endpoint_type
+        return self.cmd_with_auth(
+            'neutron', action, flags, params, fail_ok, merge_stderr)
+
+    def sahara(self, action, flags='', params='',
+               fail_ok=False, endpoint_type='publicURL', merge_stderr=True):
+        """Executes sahara command for the given action.
+
+        :param action: the cli command to run using sahara
+        :type action: string
+        :param flags: any optional cli flags to use
+        :type flags: string
+        :param params: any optional positional args to use
+        :type params: string
+        :param fail_ok: if True an exception is not raised when the
+                        cli return code is non-zero
+        :type fail_ok: boolean
+        :param endpoint_type: the type of endpoint for the service
+        :type endpoint_type: string
+        :param merge_stderr: if True the stderr buffer is merged into stdout
+        :type merge_stderr: boolean
+        """
+        flags += ' --endpoint-type %s' % endpoint_type
+        return self.cmd_with_auth(
+            'sahara', action, flags, params, fail_ok, merge_stderr)
+
+    def openstack(self, action, flags='', params='', fail_ok=False,
+                  merge_stderr=False):
+        """Executes openstack command for the given action.
+
+        :param action: the cli command to run using openstack
+        :type action: string
+        :param flags: any optional cli flags to use
+        :type flags: string
+        :param params: any optional positional args to use
+        :type params: string
+        :param fail_ok: if True an exception is not raised when the
+                        cli return code is non-zero
+        :type fail_ok: boolean
+        :param merge_stderr: if True the stderr buffer is merged into stdout
+        :type merge_stderr: boolean
+        """
+        return self.cmd_with_auth(
+            'openstack', action, flags, params, fail_ok, merge_stderr)
+
+    def cmd_with_auth(self, cmd, action, flags='', params='',
+                      fail_ok=False, merge_stderr=False):
+        """Executes given command with auth attributes appended.
+
+        :param cmd: command to be executed
+        :type cmd: string
+        :param action: command on cli to run
+        :type action: string
+        :param flags: optional cli flags to use
+        :type flags: string
+        :param params: optional positional args to use
+        :type params: string
+        :param fail_ok: if True an exception is not raised when the cli return
+                        code is non-zero
+        :type fail_ok: boolean
+        :param merge_stderr:  if True the stderr buffer is merged into stdout
+        :type merge_stderr: boolean
+        """
+        creds = ('--os-username %s --os-tenant-name %s --os-password %s '
+                 '--os-auth-url %s' %
+                 (self.username,
+                  self.tenant_name,
+                  self.password,
+                  self.uri))
+        if self.insecure:
+            flags = creds + ' --insecure ' + flags
+        else:
+            flags = creds + ' ' + flags
+        return execute(cmd, action, flags, params, fail_ok, merge_stderr,
+                       self.cli_dir)
+
+
+class ClientTestBase(base.BaseTestCase):
+    """Base test class for testing the OpenStack client CLI interfaces."""
+
+    def setUp(self):
+        super(ClientTestBase, self).setUp()
+        self.clients = self._get_clients()
+        self.parser = tempest.lib.cli.output_parser
+
+    def _get_clients(self):
+        """Abstract method to initialize CLIClient object.
+
+        This method must be overloaded in child test classes. It should be
+        used to initialize the CLIClient object with the appropriate
+        credentials during the setUp() phase of tests.
+        """
+        raise NotImplementedError
+
+    def assertTableStruct(self, items, field_names):
+        """Verify that all items has keys listed in field_names.
+
+        :param items: items to assert are field names in the output table
+        :type items: list
+        :param field_names: field names from the output table of the cmd
+        :type field_names: list
+        """
+        for item in items:
+            for field in field_names:
+                self.assertIn(field, item)
+
+    def assertFirstLineStartsWith(self, lines, beginning):
+        """Verify that the first line starts with a string
+
+        :param lines: strings for each line of output
+        :type lines: list
+        :param beginning: verify this is at the beginning of the first line
+        :type beginning: string
+        """
+        self.assertTrue(lines[0].startswith(beginning),
+                        msg=('Beginning of first line has invalid content: %s'
+                             % lines[:3]))
diff --git a/tempest/lib/cli/output_parser.py b/tempest/lib/cli/output_parser.py
new file mode 100644
index 0000000..0313505
--- /dev/null
+++ b/tempest/lib/cli/output_parser.py
@@ -0,0 +1,170 @@
+# Copyright 2013 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.
+
+"""Collection of utilities for parsing CLI clients output."""
+
+import logging
+import re
+
+from tempest.lib import exceptions
+
+
+LOG = logging.getLogger(__name__)
+
+
+delimiter_line = re.compile('^\+\-[\+\-]+\-\+$')
+
+
+def details_multiple(output_lines, with_label=False):
+    """Return list of dicts with item details from cli output tables.
+
+    If with_label is True, key '__label' is added to each items dict.
+    For more about 'label' see OutputParser.tables().
+    """
+    items = []
+    tables_ = tables(output_lines)
+    for table_ in tables_:
+        if ('Property' not in table_['headers']
+            or 'Value' not in table_['headers']):
+            raise exceptions.InvalidStructure()
+        item = {}
+        for value in table_['values']:
+            item[value[0]] = value[1]
+        if with_label:
+            item['__label'] = table_['label']
+        items.append(item)
+    return items
+
+
+def details(output_lines, with_label=False):
+    """Return dict with details of first item (table) found in output."""
+    items = details_multiple(output_lines, with_label)
+    return items[0]
+
+
+def listing(output_lines):
+    """Return list of dicts with basic item info parsed from cli output."""
+
+    items = []
+    table_ = table(output_lines)
+    for row in table_['values']:
+        item = {}
+        for col_idx, col_key in enumerate(table_['headers']):
+            item[col_key] = row[col_idx]
+        items.append(item)
+    return items
+
+
+def tables(output_lines):
+    """Find all ascii-tables in output and parse them.
+
+    Return list of tables parsed from cli output as dicts.
+    (see OutputParser.table())
+
+    And, if found, label key (separated line preceding the table)
+    is added to each tables dict.
+    """
+    tables_ = []
+
+    table_ = []
+    label = None
+
+    start = False
+    header = False
+
+    if not isinstance(output_lines, list):
+        output_lines = output_lines.split('\n')
+
+    for line in output_lines:
+        if delimiter_line.match(line):
+            if not start:
+                start = True
+            elif not header:
+                # we are after head area
+                header = True
+            else:
+                # table ends here
+                start = header = None
+                table_.append(line)
+
+                parsed = table(table_)
+                parsed['label'] = label
+                tables_.append(parsed)
+
+                table_ = []
+                label = None
+                continue
+        if start:
+            table_.append(line)
+        else:
+            if label is None:
+                label = line
+            else:
+                LOG.warning('Invalid line between tables: %s' % line)
+    if len(table_) > 0:
+        LOG.warning('Missing end of table')
+
+    return tables_
+
+
+def table(output_lines):
+    """Parse single table from cli output.
+
+    Return dict with list of column names in 'headers' key and
+    rows in 'values' key.
+    """
+    table_ = {'headers': [], 'values': []}
+    columns = None
+
+    if not isinstance(output_lines, list):
+        output_lines = output_lines.split('\n')
+
+    if not output_lines[-1]:
+        # skip last line if empty (just newline at the end)
+        output_lines = output_lines[:-1]
+
+    for line in output_lines:
+        if delimiter_line.match(line):
+            columns = _table_columns(line)
+            continue
+        if '|' not in line:
+            LOG.warning('skipping invalid table line: %s' % line)
+            continue
+        row = []
+        for col in columns:
+            row.append(line[col[0]:col[1]].strip())
+        if table_['headers']:
+            table_['values'].append(row)
+        else:
+            table_['headers'] = row
+
+    return table_
+
+
+def _table_columns(first_table_row):
+    """Find column ranges in output line.
+
+    Return list of tuples (start,end) for each column
+    detected by plus (+) characters in delimiter line.
+    """
+    positions = []
+    start = 1  # there is '+' at 0
+    while start < len(first_table_row):
+        end = first_table_row.find('+', start)
+        if end == -1:
+            break
+        positions.append((start, end))
+        start = end + 1
+    return positions
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/cmd/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/cmd/__init__.py
diff --git a/tempest/lib/cmd/check_uuid.py b/tempest/lib/cmd/check_uuid.py
new file mode 100755
index 0000000..be3aa49
--- /dev/null
+++ b/tempest/lib/cmd/check_uuid.py
@@ -0,0 +1,358 @@
+#!/usr/bin/env python
+
+# Copyright 2014 Mirantis, Inc.
+#
+# 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 argparse
+import ast
+import importlib
+import inspect
+import os
+import sys
+import unittest
+import uuid
+
+import six.moves.urllib.parse as urlparse
+
+DECORATOR_MODULE = 'test'
+DECORATOR_NAME = 'idempotent_id'
+DECORATOR_IMPORT = 'tempest.%s' % DECORATOR_MODULE
+IMPORT_LINE = 'from tempest import %s' % DECORATOR_MODULE
+DECORATOR_TEMPLATE = "@%s.%s('%%s')" % (DECORATOR_MODULE,
+                                        DECORATOR_NAME)
+UNIT_TESTS_EXCLUDE = 'tempest.tests'
+
+
+class SourcePatcher(object):
+
+    """"Lazy patcher for python source files"""
+
+    def __init__(self):
+        self.source_files = None
+        self.patches = None
+        self.clear()
+
+    def clear(self):
+        """Clear inner state"""
+        self.source_files = {}
+        self.patches = {}
+
+    @staticmethod
+    def _quote(s):
+        return urlparse.quote(s)
+
+    @staticmethod
+    def _unquote(s):
+        return urlparse.unquote(s)
+
+    def add_patch(self, filename, patch, line_no):
+        """Add lazy patch"""
+        if filename not in self.source_files:
+            with open(filename) as f:
+                self.source_files[filename] = self._quote(f.read())
+        patch_id = str(uuid.uuid4())
+        if not patch.endswith('\n'):
+            patch += '\n'
+        self.patches[patch_id] = self._quote(patch)
+        lines = self.source_files[filename].split(self._quote('\n'))
+        lines[line_no - 1] = ''.join(('{%s:s}' % patch_id, lines[line_no - 1]))
+        self.source_files[filename] = self._quote('\n').join(lines)
+
+    def _save_changes(self, filename, source):
+        print('%s fixed' % filename)
+        with open(filename, 'w') as f:
+            f.write(source)
+
+    def apply_patches(self):
+        """Apply all patches"""
+        for filename in self.source_files:
+            patched_source = self._unquote(
+                self.source_files[filename].format(**self.patches)
+            )
+            self._save_changes(filename, patched_source)
+        self.clear()
+
+
+class TestChecker(object):
+
+    def __init__(self, package):
+        self.package = package
+        self.base_path = os.path.abspath(os.path.dirname(package.__file__))
+
+    def _path_to_package(self, path):
+        relative_path = path[len(self.base_path) + 1:]
+        if relative_path:
+            return '.'.join((self.package.__name__,) +
+                            tuple(relative_path.split('/')))
+        else:
+            return self.package.__name__
+
+    def _modules_search(self):
+        """Recursive search for python modules in base package"""
+        modules = []
+        for root, dirs, files in os.walk(self.base_path):
+            if not os.path.exists(os.path.join(root, '__init__.py')):
+                continue
+            root_package = self._path_to_package(root)
+            for item in files:
+                if item.endswith('.py'):
+                    module_name = '.'.join((root_package,
+                                           os.path.splitext(item)[0]))
+                    if not module_name.startswith(UNIT_TESTS_EXCLUDE):
+                        modules.append(module_name)
+        return modules
+
+    @staticmethod
+    def _get_idempotent_id(test_node):
+        """Return key-value dict with all metadata from @test.idempotent_id"""
+        idempotent_id = None
+        for decorator in test_node.decorator_list:
+            if (hasattr(decorator, 'func') and
+                hasattr(decorator.func, 'attr') and
+                decorator.func.attr == DECORATOR_NAME and
+                hasattr(decorator.func, 'value') and
+                decorator.func.value.id == DECORATOR_MODULE):
+                for arg in decorator.args:
+                    idempotent_id = ast.literal_eval(arg)
+        return idempotent_id
+
+    @staticmethod
+    def _is_decorator(line):
+        return line.strip().startswith('@')
+
+    @staticmethod
+    def _is_def(line):
+        return line.strip().startswith('def ')
+
+    def _add_uuid_to_test(self, patcher, test_node, source_path):
+        with open(source_path) as src:
+            src_lines = src.read().split('\n')
+        lineno = test_node.lineno
+        insert_position = lineno
+        while True:
+            if (self._is_def(src_lines[lineno - 1]) or
+                    (self._is_decorator(src_lines[lineno - 1]) and
+                        (DECORATOR_TEMPLATE.split('(')[0] <=
+                            src_lines[lineno - 1].strip().split('(')[0]))):
+                insert_position = lineno
+                break
+            lineno += 1
+        patcher.add_patch(
+            source_path,
+            ' ' * test_node.col_offset + DECORATOR_TEMPLATE % uuid.uuid4(),
+            insert_position
+        )
+
+    @staticmethod
+    def _is_test_case(module, node):
+        if (node.__class__ is ast.ClassDef and
+                hasattr(module, node.name) and
+                inspect.isclass(getattr(module, node.name))):
+            return issubclass(getattr(module, node.name), unittest.TestCase)
+
+    @staticmethod
+    def _is_test_method(node):
+        return (node.__class__ is ast.FunctionDef
+                and node.name.startswith('test_'))
+
+    @staticmethod
+    def _next_node(body, node):
+        if body.index(node) < len(body):
+            return body[body.index(node) + 1]
+
+    @staticmethod
+    def _import_name(node):
+        if isinstance(node, ast.Import):
+            return node.names[0].name
+        elif isinstance(node, ast.ImportFrom):
+            return '%s.%s' % (node.module, node.names[0].name)
+
+    def _add_import_for_test_uuid(self, patcher, src_parsed, source_path):
+        with open(source_path) as f:
+            src_lines = f.read().split('\n')
+        line_no = 0
+        tempest_imports = [node for node in src_parsed.body
+                           if self._import_name(node) and
+                           'tempest.' in self._import_name(node)]
+        if not tempest_imports:
+            import_snippet = '\n'.join(('', IMPORT_LINE, ''))
+        else:
+            for node in tempest_imports:
+                if self._import_name(node) < DECORATOR_IMPORT:
+                    continue
+                else:
+                    line_no = node.lineno
+                    import_snippet = IMPORT_LINE
+                    break
+            else:
+                line_no = tempest_imports[-1].lineno
+                while True:
+                    if (not src_lines[line_no - 1] or
+                            getattr(self._next_node(src_parsed.body,
+                                                    tempest_imports[-1]),
+                                    'lineno') == line_no or
+                            line_no == len(src_lines)):
+                        break
+                    line_no += 1
+                import_snippet = '\n'.join((IMPORT_LINE, ''))
+        patcher.add_patch(source_path, import_snippet, line_no)
+
+    def get_tests(self):
+        """Get test methods with sources from base package with metadata"""
+        tests = {}
+        for module_name in self._modules_search():
+            tests[module_name] = {}
+            module = importlib.import_module(module_name)
+            source_path = '.'.join(
+                (os.path.splitext(module.__file__)[0], 'py')
+            )
+            with open(source_path, 'r') as f:
+                source = f.read()
+            tests[module_name]['source_path'] = source_path
+            tests[module_name]['tests'] = {}
+            source_parsed = ast.parse(source)
+            tests[module_name]['ast'] = source_parsed
+            tests[module_name]['import_valid'] = (
+                hasattr(module, DECORATOR_MODULE) and
+                inspect.ismodule(getattr(module, DECORATOR_MODULE))
+            )
+            test_cases = (node for node in source_parsed.body
+                          if self._is_test_case(module, node))
+            for node in test_cases:
+                for subnode in filter(self._is_test_method, node.body):
+                        test_name = '%s.%s' % (node.name, subnode.name)
+                        tests[module_name]['tests'][test_name] = subnode
+        return tests
+
+    @staticmethod
+    def _filter_tests(function, tests):
+        """Filter tests with condition 'function(test_node) == True'"""
+        result = {}
+        for module_name in tests:
+            for test_name in tests[module_name]['tests']:
+                if function(module_name, test_name, tests):
+                    if module_name not in result:
+                        result[module_name] = {
+                            'ast': tests[module_name]['ast'],
+                            'source_path': tests[module_name]['source_path'],
+                            'import_valid': tests[module_name]['import_valid'],
+                            'tests': {}
+                        }
+                    result[module_name]['tests'][test_name] = \
+                        tests[module_name]['tests'][test_name]
+        return result
+
+    def find_untagged(self, tests):
+        """Filter all tests without uuid in metadata"""
+        def check_uuid_in_meta(module_name, test_name, tests):
+            idempotent_id = self._get_idempotent_id(
+                tests[module_name]['tests'][test_name])
+            return not idempotent_id
+        return self._filter_tests(check_uuid_in_meta, tests)
+
+    def report_collisions(self, tests):
+        """Reports collisions if there are any
+
+        Returns true if collisions exist.
+        """
+        uuids = {}
+
+        def report(module_name, test_name, tests):
+            test_uuid = self._get_idempotent_id(
+                tests[module_name]['tests'][test_name])
+            if not test_uuid:
+                return
+            if test_uuid in uuids:
+                error_str = "%s:%s\n uuid %s collision: %s<->%s\n%s:%s" % (
+                    tests[module_name]['source_path'],
+                    tests[module_name]['tests'][test_name].lineno,
+                    test_uuid,
+                    test_name,
+                    uuids[test_uuid]['test_name'],
+                    uuids[test_uuid]['source_path'],
+                    uuids[test_uuid]['test_node'].lineno,
+                )
+                print(error_str)
+                print("cannot automatically resolve the collision, please "
+                      "manually remove the duplicate value on the new test.")
+                return True
+            else:
+                uuids[test_uuid] = {
+                    'module': module_name,
+                    'test_name': test_name,
+                    'test_node': tests[module_name]['tests'][test_name],
+                    'source_path': tests[module_name]['source_path']
+                }
+        return bool(self._filter_tests(report, tests))
+
+    def report_untagged(self, tests):
+        """Reports untagged tests if there are any
+
+        Returns true if untagged tests exist.
+        """
+        def report(module_name, test_name, tests):
+            error_str = "%s:%s\nmissing @test.idempotent_id('...')\n%s\n" % (
+                tests[module_name]['source_path'],
+                tests[module_name]['tests'][test_name].lineno,
+                test_name
+            )
+            print(error_str)
+            return True
+        return bool(self._filter_tests(report, tests))
+
+    def fix_tests(self, tests):
+        """Add uuids to all specified in tests and fix it in source files"""
+        patcher = SourcePatcher()
+        for module_name in tests:
+            add_import_once = True
+            for test_name in tests[module_name]['tests']:
+                if not tests[module_name]['import_valid'] and add_import_once:
+                    self._add_import_for_test_uuid(
+                        patcher,
+                        tests[module_name]['ast'],
+                        tests[module_name]['source_path']
+                    )
+                    add_import_once = False
+                self._add_uuid_to_test(
+                    patcher, tests[module_name]['tests'][test_name],
+                    tests[module_name]['source_path'])
+        patcher.apply_patches()
+
+
+def run():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--package', action='store', dest='package',
+                        default='tempest', type=str,
+                        help='Package with tests')
+    parser.add_argument('--fix', action='store_true', dest='fix_tests',
+                        help='Attempt to fix tests without UUIDs')
+    args = parser.parse_args()
+    sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+    pkg = importlib.import_module(args.package)
+    checker = TestChecker(pkg)
+    errors = False
+    tests = checker.get_tests()
+    untagged = checker.find_untagged(tests)
+    errors = checker.report_collisions(tests) or errors
+    if args.fix_tests and untagged:
+        checker.fix_tests(untagged)
+    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.")
+
+if __name__ == '__main__':
+    run()
diff --git a/tempest/lib/cmd/skip_tracker.py b/tempest/lib/cmd/skip_tracker.py
new file mode 100755
index 0000000..b5c9b95
--- /dev/null
+++ b/tempest/lib/cmd/skip_tracker.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python2
+
+# 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.
+
+"""
+Track test skips via launchpadlib API and raise alerts if a bug
+is fixed but a skip is still in the Tempest test code
+"""
+
+import argparse
+import logging
+import os
+import re
+
+try:
+    from launchpadlib import launchpad
+except ImportError:
+    launchpad = None
+
+LPCACHEDIR = os.path.expanduser('~/.launchpadlib/cache')
+
+
+def parse_args():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('test_path', help='Path of test dir')
+    return parser.parse_args()
+
+
+def info(msg, *args, **kwargs):
+    logging.info(msg, *args, **kwargs)
+
+
+def debug(msg, *args, **kwargs):
+    logging.debug(msg, *args, **kwargs)
+
+
+def find_skips(start):
+    """Find the entire list of skiped tests.
+
+    Returns a list of tuples (method, bug) that represent
+    test methods that have been decorated to skip because of
+    a particular bug.
+    """
+    results = {}
+    debug("Searching in %s", start)
+    for root, _dirs, files in os.walk(start):
+        for name in files:
+            if name.startswith('test_') and name.endswith('py'):
+                path = os.path.join(root, name)
+                debug("Searching in %s", path)
+                temp_result = find_skips_in_file(path)
+                for method_name, bug_no in temp_result:
+                    if results.get(bug_no):
+                        result_dict = results.get(bug_no)
+                        if result_dict.get(name):
+                            result_dict[name].append(method_name)
+                        else:
+                            result_dict[name] = [method_name]
+                        results[bug_no] = result_dict
+                    else:
+                        results[bug_no] = {name: [method_name]}
+    return results
+
+
+def find_skips_in_file(path):
+    """Return the skip tuples in a test file."""
+    BUG_RE = re.compile(r'\s*@.*skip_because\(bug=[\'"](\d+)[\'"]')
+    DEF_RE = re.compile(r'\s*def (\w+)\(')
+    bug_found = False
+    results = []
+    lines = open(path, 'rb').readlines()
+    for x, line in enumerate(lines):
+        if not bug_found:
+            res = BUG_RE.match(line)
+            if res:
+                bug_no = int(res.group(1))
+                debug("Found bug skip %s on line %d", bug_no, x + 1)
+                bug_found = True
+        else:
+            res = DEF_RE.match(line)
+            if res:
+                method = res.group(1)
+                debug("Found test method %s skips for bug %d", method, bug_no)
+                results.append((method, bug_no))
+                bug_found = False
+    return results
+
+
+def get_results(result_dict):
+    results = []
+    for bug_no in result_dict.keys():
+        for method in result_dict[bug_no]:
+            results.append((method, bug_no))
+    return results
+
+
+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)]))
+    unskips = []
+    duplicates = []
+    info("Total bug skips found: %d", len(results))
+    info("Total unique bugs causing skips: %d", len(unique_bugs))
+    if launchpad is not None:
+        lp = launchpad.Launchpad.login_anonymously('grabbing bugs',
+                                                   'production',
+                                                   LPCACHEDIR)
+    else:
+        print("To check the bug status launchpadlib should be installed")
+        exit(1)
+
+    for bug_no in unique_bugs:
+        bug = lp.bugs[bug_no]
+        duplicate = bug.duplicate_of_link
+        if duplicate is not None:
+            dup_id = duplicate.split('/')[-1]
+            duplicates.append((bug_no, dup_id))
+        for task in bug.bug_tasks:
+            info("Bug #%7s (%12s - %12s)", bug_no,
+                 task.importance, task.status)
+            if task.status in ('Fix Released', 'Fix Committed'):
+                unskips.append(bug_no)
+
+    for bug_id, dup_id in duplicates:
+        if bug_id not in unskips:
+            dup_bug = lp.bugs[dup_id]
+            for task in dup_bug.bug_tasks:
+                info("Bug #%7s is a duplicate of Bug#%7s (%12s - %12s)",
+                     bug_id, dup_id, task.importance, task.status)
+                if task.status in ('Fix Released', 'Fix Committed'):
+                    unskips.append(bug_id)
+
+    unskips = sorted(set(unskips))
+    if unskips:
+        print("The following bugs have been fixed and the corresponding skips")
+        print("should be removed from the test cases:")
+        print()
+        for bug in unskips:
+            message = "  %7s in " % bug
+            locations = ["%s" % x for x in results[bug].keys()]
+            message += " and ".join(locations)
+            print(message)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/common/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/common/__init__.py
diff --git a/tempest/lib/common/http.py b/tempest/lib/common/http.py
new file mode 100644
index 0000000..b3793bc
--- /dev/null
+++ b/tempest/lib/common/http.py
@@ -0,0 +1,25 @@
+# Copyright 2013 OpenStack Foundation
+# Copyright 2013 Citrix Systems, 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 httplib2
+
+
+class ClosingHttp(httplib2.Http):
+    def request(self, *args, **kwargs):
+        original_headers = kwargs.get('headers', {})
+        new_headers = dict(original_headers, connection='close')
+        new_kwargs = dict(kwargs, headers=new_headers)
+        return super(ClosingHttp, self).request(*args, **new_kwargs)
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
new file mode 100644
index 0000000..7ce05e3
--- /dev/null
+++ b/tempest/lib/common/rest_client.py
@@ -0,0 +1,894 @@
+# 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 collections
+import logging as real_logging
+import re
+import time
+
+import jsonschema
+from oslo_log import log as logging
+from oslo_serialization import jsonutils as json
+import six
+
+from tempest.lib.common import http
+from tempest.lib.common.utils import misc as misc_utils
+from tempest.lib import exceptions
+
+# redrive rate limited calls at most twice
+MAX_RECURSION_DEPTH = 2
+
+# All the successful HTTP status codes from RFC 7231 & 4918
+HTTP_SUCCESS = (200, 201, 202, 203, 204, 205, 206, 207)
+
+# All the redirection HTTP status codes from RFC 7231 & 4918
+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
+
+
+class RestClient(object):
+    """Unified OpenStack RestClient class
+
+    This class is used for building openstack api clients on top of. It is
+    intended to provide a base layer for wrapping outgoing http requests in
+    keystone auth as well as providing response code checking and error
+    handling.
+
+    :param auth_provider: an auth provider object used to wrap requests in auth
+    :param str service: The service name to use for the catalog lookup
+    :param str region: The region to use for the catalog lookup
+    :param str endpoint_type: The endpoint type to use for the catalog lookup
+    :param int build_interval: Time in seconds between to status checks in
+                               wait loops
+    :param int build_timeout: Timeout in seconds to wait for a wait operation.
+    :param bool disable_ssl_certificate_validation: Set to true to disable ssl
+                                                    certificate validation
+    :param str ca_certs: File containing the CA Bundle to use in verifying a
+                         TLS server cert
+    :param str trace_request: Regex to use for specifying logging the entirety
+                              of the request and response payload
+    """
+    TYPE = "json"
+
+    # The version of the API this client implements
+    api_version = None
+
+    LOG = logging.getLogger(__name__)
+
+    def __init__(self, auth_provider, service, region,
+                 endpoint_type='publicURL',
+                 build_interval=1, build_timeout=60,
+                 disable_ssl_certificate_validation=False, ca_certs=None,
+                 trace_requests=''):
+        self.auth_provider = auth_provider
+        self.service = service
+        self.region = region
+        self.endpoint_type = endpoint_type
+        self.build_interval = build_interval
+        self.build_timeout = build_timeout
+        self.trace_requests = trace_requests
+
+        self._skip_path = False
+        self.general_header_lc = set(('cache-control', 'connection',
+                                      'date', 'pragma', 'trailer',
+                                      'transfer-encoding', 'via',
+                                      'warning'))
+        self.response_header_lc = set(('accept-ranges', 'age', 'etag',
+                                       'location', 'proxy-authenticate',
+                                       'retry-after', 'server',
+                                       'vary', 'www-authenticate'))
+        dscv = disable_ssl_certificate_validation
+        self.http_obj = http.ClosingHttp(
+            disable_ssl_certificate_validation=dscv, ca_certs=ca_certs)
+
+    def _get_type(self):
+        return self.TYPE
+
+    def get_headers(self, accept_type=None, send_type=None):
+        """Return the default headers which will be used with outgoing requests
+
+        :param str accept_type: The media type to use for the Accept header, if
+                                one isn't provided the object var TYPE will be
+                                used
+        :param str send_type: The media-type to use for the Content-Type
+                              header, if one isn't provided the object var
+                              TYPE will be used
+        :rtype: dict
+        :return: The dictionary of headers which can be used in the headers
+                 dict for outgoing request
+        """
+        if accept_type is None:
+            accept_type = self._get_type()
+        if send_type is None:
+            send_type = self._get_type()
+        return {'Content-Type': 'application/%s' % send_type,
+                'Accept': 'application/%s' % accept_type}
+
+    def __str__(self):
+        STRING_LIMIT = 80
+        str_format = ("service:%s, base_url:%s, "
+                      "filters: %s, build_interval:%s, build_timeout:%s"
+                      "\ntoken:%s..., \nheaders:%s...")
+        return str_format % (self.service, self.base_url,
+                             self.filters, self.build_interval,
+                             self.build_timeout,
+                             str(self.token)[0:STRING_LIMIT],
+                             str(self.get_headers())[0:STRING_LIMIT])
+
+    @property
+    def user(self):
+        """The username used for requests
+
+        :rtype: string
+        :return: The username being used for requests
+        """
+
+        return self.auth_provider.credentials.username
+
+    @property
+    def user_id(self):
+        """The user_id used for requests
+
+        :rtype: string
+        :return: The user id being used for requests
+        """
+        return self.auth_provider.credentials.user_id
+
+    @property
+    def tenant_name(self):
+        """The tenant/project being used for requests
+
+        :rtype: string
+        :return: The tenant/project name being used for requests
+        """
+        return self.auth_provider.credentials.tenant_name
+
+    @property
+    def tenant_id(self):
+        """The tenant/project id being used for requests
+
+        :rtype: string
+        :return: The tenant/project id being used for requests
+        """
+        return self.auth_provider.credentials.tenant_id
+
+    @property
+    def password(self):
+        """The password being used for requests
+
+        :rtype: string
+        :return: The password being used for requests
+        """
+        return self.auth_provider.credentials.password
+
+    @property
+    def base_url(self):
+        return self.auth_provider.base_url(filters=self.filters)
+
+    @property
+    def token(self):
+        return self.auth_provider.get_token()
+
+    @property
+    def filters(self):
+        _filters = dict(
+            service=self.service,
+            endpoint_type=self.endpoint_type,
+            region=self.region
+        )
+        if self.api_version is not None:
+            _filters['api_version'] = self.api_version
+        if self._skip_path:
+            _filters['skip_path'] = self._skip_path
+        return _filters
+
+    def skip_path(self):
+        """When set, ignore the path part of the base URL from the catalog"""
+        self._skip_path = True
+
+    def reset_path(self):
+        """When reset, use the base URL from the catalog as-is"""
+        self._skip_path = False
+
+    @classmethod
+    def expected_success(cls, expected_code, read_code):
+        """Check expected success response code against the http response
+
+        :param int expected_code: The response code that is expected.
+                                  Optionally a list of integers can be used
+                                  to specify multiple valid success codes
+        :param int read_code: The response code which was returned in the
+                              response
+        :raises AssertionError: if the expected_code isn't a valid http success
+                                response code
+        :raises exceptions.InvalidHttpSuccessCode: if the read code isn't an
+                                                   expected http success code
+        """
+        assert_msg = ("This function only allowed to use for HTTP status"
+                      "codes which explicitly defined in the RFC 7231 & 4918."
+                      "{0} is not a defined Success Code!"
+                      ).format(expected_code)
+        if isinstance(expected_code, list):
+            for code in expected_code:
+                assert code in HTTP_SUCCESS + HTTP_REDIRECTION, assert_msg
+        else:
+            assert expected_code in HTTP_SUCCESS + HTTP_REDIRECTION, assert_msg
+
+        # 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}"""
+            if ((not isinstance(expected_code, list) and
+                 (read_code != expected_code)) or
+                (isinstance(expected_code, list) and
+                 (read_code not in expected_code))):
+                details = pattern.format(read_code, expected_code)
+                raise exceptions.InvalidHttpSuccessCode(details)
+
+    def post(self, url, body, headers=None, extra_headers=False):
+        """Send a HTTP POST request using keystone auth
+
+        :param str url: the relative url to send the post request to
+        :param dict body: the request body
+        :param dict headers: The headers to use for the request
+        :param dict extra_headers: If the headers returned by the get_headers()
+                                   method are to be used but additional headers
+                                   are needed in the request pass them in as a
+                                   dict
+        :return: a tuple with the first entry containing the response headers
+                 and the second the response body
+        :rtype: tuple
+        """
+        return self.request('POST', url, extra_headers, headers, body)
+
+    def get(self, url, headers=None, extra_headers=False):
+        """Send a HTTP GET request using keystone service catalog and auth
+
+        :param str url: the relative url to send the post request to
+        :param dict headers: The headers to use for the request
+        :param dict extra_headers: If the headers returned by the get_headers()
+                                   method are to be used but additional headers
+                                   are needed in the request pass them in as a
+                                   dict
+        :return: a tuple with the first entry containing the response headers
+                 and the second the response body
+        :rtype: tuple
+        """
+        return self.request('GET', url, extra_headers, headers)
+
+    def delete(self, url, headers=None, body=None, extra_headers=False):
+        """Send a HTTP DELETE request using keystone service catalog and auth
+
+        :param str url: the relative url to send the post request to
+        :param dict headers: The headers to use for the request
+        :param dict body: the request body
+        :param dict extra_headers: If the headers returned by the get_headers()
+                                   method are to be used but additional headers
+                                   are needed in the request pass them in as a
+                                   dict
+        :return: a tuple with the first entry containing the response headers
+                 and the second the response body
+        :rtype: tuple
+        """
+        return self.request('DELETE', url, extra_headers, headers, body)
+
+    def patch(self, url, body, headers=None, extra_headers=False):
+        """Send a HTTP PATCH request using keystone service catalog and auth
+
+        :param str url: the relative url to send the post request to
+        :param dict body: the request body
+        :param dict headers: The headers to use for the request
+        :param dict extra_headers: If the headers returned by the get_headers()
+                                   method are to be used but additional headers
+                                   are needed in the request pass them in as a
+                                   dict
+        :return: a tuple with the first entry containing the response headers
+                 and the second the response body
+        :rtype: tuple
+        """
+        return self.request('PATCH', url, extra_headers, headers, body)
+
+    def put(self, url, body, headers=None, extra_headers=False):
+        """Send a HTTP PUT request using keystone service catalog and auth
+
+        :param str url: the relative url to send the post request to
+        :param dict body: the request body
+        :param dict headers: The headers to use for the request
+        :param dict extra_headers: If the headers returned by the get_headers()
+                                   method are to be used but additional headers
+                                   are needed in the request pass them in as a
+                                   dict
+        :return: a tuple with the first entry containing the response headers
+                 and the second the response body
+        :rtype: tuple
+        """
+        return self.request('PUT', url, extra_headers, headers, body)
+
+    def head(self, url, headers=None, extra_headers=False):
+        """Send a HTTP HEAD request using keystone service catalog and auth
+
+        :param str url: the relative url to send the post request to
+        :param dict headers: The headers to use for the request
+        :param dict extra_headers: If the headers returned by the get_headers()
+                                   method are to be used but additional headers
+                                   are needed in the request pass them in as a
+                                   dict
+        :return: a tuple with the first entry containing the response headers
+                 and the second the response body
+        :rtype: tuple
+        """
+        return self.request('HEAD', url, extra_headers, headers)
+
+    def copy(self, url, headers=None, extra_headers=False):
+        """Send a HTTP COPY request using keystone service catalog and auth
+
+        :param str url: the relative url to send the post request to
+        :param dict headers: The headers to use for the request
+        :param dict extra_headers: If the headers returned by the get_headers()
+                                   method are to be used but additional headers
+                                   are needed in the request pass them in as a
+                                   dict
+        :return: a tuple with the first entry containing the response headers
+                 and the second the response body
+        :rtype: tuple
+        """
+        return self.request('COPY', url, extra_headers, headers)
+
+    def get_versions(self):
+        """Get the versions on a endpoint from the keystone catalog
+
+        This method will make a GET request on the baseurl from the keystone
+        catalog to return a list of API versions. It is expected that a GET
+        on the endpoint in the catalog will return a list of supported API
+        versions.
+
+        :return tuple with response headers and list of version numbers
+        :rtype: tuple
+        """
+        resp, body = self.get('')
+        body = self._parse_resp(body)
+        versions = map(lambda x: x['id'], body)
+        return resp, versions
+
+    def _get_request_id(self, resp):
+        for i in ('x-openstack-request-id', 'x-compute-request-id'):
+            if i in resp:
+                return resp[i]
+        return ""
+
+    def _safe_body(self, body, maxlen=4096):
+        # convert a structure into a string safely
+        try:
+            text = six.text_type(body)
+        except UnicodeDecodeError:
+            # if this isn't actually text, return marker that
+            return "<BinaryData: removed>"
+        if len(text) > maxlen:
+            return text[:maxlen]
+        else:
+            return text
+
+    def _log_request_start(self, method, req_url, req_headers=None,
+                           req_body=None):
+        if req_headers is None:
+            req_headers = {}
+        caller_name = misc_utils.find_test_caller()
+        if self.trace_requests and re.search(self.trace_requests, caller_name):
+            self.LOG.debug('Starting Request (%s): %s %s' %
+                           (caller_name, method, req_url))
+
+    def _log_request_full(self, method, req_url, resp,
+                          secs="", req_headers=None,
+                          req_body=None, resp_body=None,
+                          caller_name=None, extra=None):
+        if 'X-Auth-Token' in req_headers:
+            req_headers['X-Auth-Token'] = '<omitted>'
+        log_fmt = """Request - Headers: %s
+        Body: %s
+    Response - Headers: %s
+        Body: %s"""
+
+        self.LOG.debug(
+            log_fmt % (
+                str(req_headers),
+                self._safe_body(req_body),
+                str(resp),
+                self._safe_body(resp_body)),
+            extra=extra)
+
+    def _log_request(self, method, req_url, resp,
+                     secs="", req_headers=None,
+                     req_body=None, resp_body=None):
+        if req_headers is None:
+            req_headers = {}
+        # if we have the request id, put it in the right part of the log
+        extra = dict(request_id=self._get_request_id(resp))
+        # NOTE(sdague): while we still have 6 callers to this function
+        # we're going to just provide work around on who is actually
+        # providing timings by gracefully adding no content if they don't.
+        # Once we're down to 1 caller, clean this up.
+        caller_name = misc_utils.find_test_caller()
+        if secs:
+            secs = " %.3fs" % secs
+        self.LOG.info(
+            'Request (%s): %s %s %s%s' % (
+                caller_name,
+                resp['status'],
+                method,
+                req_url,
+                secs),
+            extra=extra)
+
+        # Also look everything at DEBUG if you want to filter this
+        # out, don't run at debug.
+        if self.LOG.isEnabledFor(real_logging.DEBUG):
+            self._log_request_full(method, req_url, resp, secs, req_headers,
+                                   req_body, resp_body, caller_name, extra)
+
+    def _parse_resp(self, body):
+        try:
+            body = json.loads(body)
+        except ValueError:
+            return body
+
+        # We assume, that if the first value of the deserialized body's
+        # item set is a dict or a list, that we just return the first value
+        # of deserialized body.
+        # Essentially "cutting out" the first placeholder element in a body
+        # that looks like this:
+        #
+        #  {
+        #    "users": [
+        #      ...
+        #    ]
+        #  }
+        try:
+            # Ensure there are not more than one top-level keys
+            # NOTE(freerunner): Ensure, that JSON is not nullable to
+            # to prevent StopIteration Exception
+            if len(body.keys()) != 1:
+                return body
+            # Just return the "wrapped" element
+            first_key, first_item = six.next(six.iteritems(body))
+            if isinstance(first_item, (dict, list)):
+                return first_item
+        except (ValueError, IndexError):
+            pass
+        return body
+
+    def response_checker(self, method, resp, resp_body):
+        """A sanity check on the response from a HTTP request
+
+        This method does a sanity check on whether the response from an HTTP
+        request conforms the HTTP RFC.
+
+        :param str method: The HTTP verb of the request associated with the
+                           response being passed in.
+        :param resp: The response headers
+        :param resp_body: The body of the response
+        :raises ResponseWithNonEmptyBody: If the response with the status code
+                                          is not supposed to have a body
+        :raises ResponseWithEntity: If the response code is 205 but has an
+                                    entity
+        """
+        if (resp.status in set((204, 205, 304)) or resp.status < 200 or
+                method.upper() == 'HEAD') and resp_body:
+            raise exceptions.ResponseWithNonEmptyBody(status=resp.status)
+        # NOTE(afazekas):
+        # If the HTTP Status Code is 205
+        #   'The response MUST NOT include an entity.'
+        # A HTTP entity has an entity-body and an 'entity-header'.
+        # In the HTTP response specification (Section 6) the 'entity-header'
+        # 'generic-header' and 'response-header' are in OR relation.
+        # All headers not in the above two group are considered as entity
+        # header in every interpretation.
+
+        if (resp.status == 205 and
+            0 != len(set(resp.keys()) - set(('status',)) -
+                     self.response_header_lc - self.general_header_lc)):
+                        raise exceptions.ResponseWithEntity()
+        # NOTE(afazekas)
+        # Now the swift sometimes (delete not empty container)
+        # returns with non json error response, we can create new rest class
+        # for swift.
+        # Usually RFC2616 says error responses SHOULD contain an explanation.
+        # The warning is normal for SHOULD/SHOULD NOT case
+
+        # Likely it will cause an error
+        if method != 'HEAD' and not resp_body and resp.status >= 400:
+            self.LOG.warning("status >= 400 response with empty body")
+
+    def _request(self, method, url, headers=None, body=None):
+        """A simple HTTP request interface."""
+        # Authenticate the request with the auth provider
+        req_url, req_headers, req_body = self.auth_provider.auth_request(
+            method, url, headers, body, self.filters)
+
+        # Do the actual request, and time it
+        start = time.time()
+        self._log_request_start(method, req_url)
+        resp, resp_body = self.raw_request(
+            req_url, method, headers=req_headers, body=req_body)
+        end = time.time()
+        self._log_request(method, req_url, resp, secs=(end - start),
+                          req_headers=req_headers, req_body=req_body,
+                          resp_body=resp_body)
+
+        # Verify HTTP response codes
+        self.response_checker(method, resp, resp_body)
+
+        return resp, resp_body
+
+    def raw_request(self, url, method, headers=None, body=None):
+        """Send a raw HTTP request without the keystone catalog or auth
+
+        This method sends a HTTP request in the same manner as the request()
+        method, however it does so without using keystone auth or the catalog
+        to determine the base url. Additionally no response handling is done
+        the results from the request are just returned.
+
+        :param str url: Full url to send the request
+        :param str method: The HTTP verb to use for the request
+        :param str headers: Headers to use for the request if none are specifed
+                            the headers
+        :param str body: Body to to send with the request
+        :rtype: tuple
+        :return: a tuple with the first entry containing the response headers
+                 and the second the response body
+        """
+        if headers is None:
+            headers = self.get_headers()
+        return self.http_obj.request(url, method,
+                                     headers=headers, body=body)
+
+    def request(self, method, url, extra_headers=False, headers=None,
+                body=None):
+        """Send a HTTP request with keystone auth and using the catalog
+
+        This method will send an HTTP request using keystone auth in the
+        headers and the catalog to determine the endpoint to use for the
+        baseurl to send the request to. Additionally
+
+        When a response is received it will check it to see if an error
+        response was received. If it was an exception will be raised to enable
+        it to be handled quickly.
+
+        This method will also handle rate-limiting, if a 413 response code is
+        received it will retry the request after waiting the 'retry-after'
+        duration from the header.
+
+        :param str method: The HTTP verb to use for the request
+        :param str url: Relative url to send the request to
+        :param dict extra_headers: If specified without the headers kwarg the
+                                   headers sent with the request will be the
+                                   combination from the get_headers() method
+                                   and this kwarg
+        :param dict headers: Headers to use for the request if none are
+                             specifed the headers returned from the
+                             get_headers() method are used. If the request
+                             explicitly requires no headers use an empty dict.
+        :param str body: Body to to send with the request
+        :rtype: tuple
+        :return: a tuple with the first entry containing the response headers
+                 and the second the response body
+        :raises UnexpectedContentType: If the content-type of the response
+                                       isn't an expect type
+        :raises Unauthorized: If a 401 response code is received
+        :raises Forbidden: If a 403 response code is received
+        :raises NotFound: If a 404 response code is received
+        :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 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
+                                   over_limit is in the response body
+        :raises InvalidContentType: If a 415 response code is received
+        :raises UnprocessableEntity: If a 422 response code is received
+        :raises InvalidHTTPResponseBody: The response body wasn't valid JSON
+                                         and couldn't be parsed
+        :raises NotImplemented: If a 501 response code is received
+        :raises ServerFault: If a 500 response code is received
+        :raises UnexpectedResponseCode: If a response code above 400 is
+                                        received and it doesn't fall into any
+                                        of the handled checks
+        """
+        # if extra_headers is True
+        # default headers would be added to headers
+        retry = 0
+
+        if headers is None:
+            # NOTE(vponomaryov): if some client do not need headers,
+            # it should explicitly pass empty dict
+            headers = self.get_headers()
+        elif extra_headers:
+            try:
+                headers = headers.copy()
+                headers.update(self.get_headers())
+            except (ValueError, TypeError):
+                headers = self.get_headers()
+
+        resp, resp_body = self._request(method, url,
+                                        headers=headers, body=body)
+
+        while (resp.status == 413 and
+               'retry-after' in resp and
+                not self.is_absolute_limit(
+                    resp, self._parse_resp(resp_body)) and
+                retry < MAX_RECURSION_DEPTH):
+            retry += 1
+            delay = int(resp['retry-after'])
+            time.sleep(delay)
+            resp, resp_body = self._request(method, url,
+                                            headers=headers, body=body)
+        self._error_checker(method, url, headers, body,
+                            resp, resp_body)
+        return resp, resp_body
+
+    def _error_checker(self, method, url,
+                       headers, body, resp, resp_body):
+
+        # NOTE(mtreinish): Check for httplib response from glance_http. The
+        # object can't be used here because importing httplib breaks httplib2.
+        # If another object from a class not imported were passed here as
+        # resp this could possibly fail
+        if str(type(resp)) == "<type 'instance'>":
+            ctype = resp.getheader('content-type')
+        else:
+            try:
+                ctype = resp['content-type']
+            # NOTE(mtreinish): Keystone delete user responses doesn't have a
+            # content-type header. (They don't have a body) So just pretend it
+            # is set.
+            except KeyError:
+                ctype = 'application/json'
+
+        # It is not an error response
+        if resp.status < 400:
+            return
+
+        JSON_ENC = ['application/json', '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.
+        TXT_ENC = ['text/plain', 'text/html', 'text/html; charset=utf-8',
+                   'text/plain; charset=utf-8']
+
+        if ctype.lower() in JSON_ENC:
+            parse_resp = True
+        elif ctype.lower() in TXT_ENC:
+            parse_resp = False
+        else:
+            raise exceptions.UnexpectedContentType(str(resp.status),
+                                                   resp=resp)
+
+        if resp.status == 401:
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
+            raise exceptions.Unauthorized(resp_body, resp=resp)
+
+        if resp.status == 403:
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
+            raise exceptions.Forbidden(resp_body, resp=resp)
+
+        if resp.status == 404:
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
+            raise exceptions.NotFound(resp_body, resp=resp)
+
+        if resp.status == 400:
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
+            raise exceptions.BadRequest(resp_body, resp=resp)
+
+        if resp.status == 410:
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
+            raise exceptions.Gone(resp_body, resp=resp)
+
+        if resp.status == 409:
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
+            raise exceptions.Conflict(resp_body, resp=resp)
+
+        if resp.status == 413:
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
+            if self.is_absolute_limit(resp, resp_body):
+                raise exceptions.OverLimit(resp_body, resp=resp)
+            else:
+                raise exceptions.RateLimitExceeded(resp_body, resp=resp)
+
+        if resp.status == 415:
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
+            raise exceptions.InvalidContentType(resp_body, resp=resp)
+
+        if resp.status == 422:
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
+            raise exceptions.UnprocessableEntity(resp_body, resp=resp)
+
+        if resp.status in (500, 501):
+            message = resp_body
+            if parse_resp:
+                try:
+                    resp_body = self._parse_resp(resp_body)
+                except ValueError:
+                    # If response body is a non-json string message.
+                    # Use resp_body as is and raise InvalidResponseBody
+                    # exception.
+                    raise exceptions.InvalidHTTPResponseBody(message)
+                else:
+                    if isinstance(resp_body, dict):
+                        # I'm seeing both computeFault
+                        # and cloudServersFault come back.
+                        # Will file a bug to fix, but leave as is for now.
+                        if 'cloudServersFault' in resp_body:
+                            message = resp_body['cloudServersFault']['message']
+                        elif 'computeFault' in resp_body:
+                            message = resp_body['computeFault']['message']
+                        elif 'error' in resp_body:
+                            message = resp_body['error']['message']
+                        elif 'message' in resp_body:
+                            message = resp_body['message']
+                    else:
+                        message = resp_body
+
+            if resp.status == 501:
+                raise exceptions.NotImplemented(resp_body, resp=resp,
+                                                message=message)
+            else:
+                raise exceptions.ServerFault(resp_body, resp=resp,
+                                             message=message)
+
+        if resp.status >= 400:
+            raise exceptions.UnexpectedResponseCode(str(resp.status),
+                                                    resp=resp)
+
+    def is_absolute_limit(self, resp, resp_body):
+        if (not isinstance(resp_body, collections.Mapping) or
+                'retry-after' not in resp):
+            return True
+        over_limit = resp_body.get('overLimit', None)
+        if not over_limit:
+            return True
+        return 'exceed' in over_limit.get('message', 'blabla')
+
+    def wait_for_resource_deletion(self, id):
+        """Waits for a resource to be deleted
+
+        This method will loop over is_resource_deleted until either
+        is_resource_deleted returns True or the build timeout is reached. This
+        depends on is_resource_deleted being implemented
+
+        :param str id: The id of the resource to check
+        :raises TimeoutException: If the build_timeout has elapsed and the
+                                  resource still hasn't been deleted
+        """
+        start_time = int(time.time())
+        while True:
+            if self.is_resource_deleted(id):
+                return
+            if int(time.time()) - start_time >= self.build_timeout:
+                message = ('Failed to delete %(resource_type)s %(id)s within '
+                           'the required time (%(timeout)s s).' %
+                           {'resource_type': self.resource_type, 'id': id,
+                            'timeout': self.build_timeout})
+                caller = misc_utils.find_test_caller()
+                if caller:
+                    message = '(%s) %s' % (caller, message)
+                raise exceptions.TimeoutException(message)
+            time.sleep(self.build_interval)
+
+    def is_resource_deleted(self, id):
+        """Subclasses override with specific deletion detection."""
+        message = ('"%s" does not implement is_resource_deleted'
+                   % self.__class__.__name__)
+        raise NotImplementedError(message)
+
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'resource'
+
+    @classmethod
+    def validate_response(cls, schema, resp, body):
+        # Only check the response if the status code is a success code
+        # TODO(cyeoh): Eventually we should be able to verify that a failure
+        # code if it exists is something that we expect. This is explicitly
+        # declared in the V3 API and so we should be able to export this in
+        # the response schema. For now we'll ignore it.
+        if resp.status in HTTP_SUCCESS + HTTP_REDIRECTION:
+            cls.expected_success(schema['status_code'], resp.status)
+
+            # Check the body of a response
+            body_schema = schema.get('response_body')
+            if body_schema:
+                try:
+                    jsonschema.validate(body, body_schema,
+                                        cls=JSONSCHEMA_VALIDATOR,
+                                        format_checker=FORMAT_CHECKER)
+                except jsonschema.ValidationError as ex:
+                    msg = ("HTTP response body is invalid (%s)") % ex
+                    raise exceptions.InvalidHTTPResponseBody(msg)
+            else:
+                if body:
+                    msg = ("HTTP response body should not exist (%s)") % body
+                    raise exceptions.InvalidHTTPResponseBody(msg)
+
+            # Check the header of a response
+            header_schema = schema.get('response_header')
+            if header_schema:
+                try:
+                    jsonschema.validate(resp, header_schema,
+                                        cls=JSONSCHEMA_VALIDATOR,
+                                        format_checker=FORMAT_CHECKER)
+                except jsonschema.ValidationError as ex:
+                    msg = ("HTTP response header is invalid (%s)") % ex
+                    raise exceptions.InvalidHTTPResponseHeader(msg)
+
+
+class ResponseBody(dict):
+    """Class that wraps an http response and dict body into a single value.
+
+    Callers that receive this object will normally use it as a dict but
+    can extract the response if needed.
+    """
+
+    def __init__(self, response, body=None):
+        body_data = body or {}
+        self.update(body_data)
+        self.response = response
+
+    def __str__(self):
+        body = super(ResponseBody, self).__str__()
+        return "response: %s\nBody: %s" % (self.response, body)
+
+
+class ResponseBodyData(object):
+    """Class that wraps an http response and string data into a single value.
+
+    """
+
+    def __init__(self, response, data):
+        self.response = response
+        self.data = data
+
+    def __str__(self):
+        return "response: %s\nBody: %s" % (self.response, self.data)
+
+
+class ResponseBodyList(list):
+    """Class that wraps an http response and list body into a single value.
+
+    Callers that receive this object will normally use it as a list but
+    can extract the response if needed.
+    """
+
+    def __init__(self, response, body=None):
+        body_data = body or []
+        self.extend(body_data)
+        self.response = response
+
+    def __str__(self):
+        body = super(ResponseBodyList, self).__str__()
+        return "response: %s\nBody: %s" % (self.response, body)
diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py
new file mode 100644
index 0000000..511dd08
--- /dev/null
+++ b/tempest/lib/common/ssh.py
@@ -0,0 +1,174 @@
+# 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.
+
+
+import select
+import socket
+import time
+import warnings
+
+from oslo_log import log as logging
+import six
+
+from tempest.lib import exceptions
+
+
+with warnings.catch_warnings():
+    warnings.simplefilter("ignore")
+    import paramiko
+
+
+LOG = logging.getLogger(__name__)
+
+
+class Client(object):
+
+    def __init__(self, host, username, password=None, timeout=300, pkey=None,
+                 channel_timeout=10, look_for_keys=False, key_filename=None):
+        self.host = host
+        self.username = username
+        self.password = password
+        if isinstance(pkey, six.string_types):
+            pkey = paramiko.RSAKey.from_private_key(
+                six.StringIO(str(pkey)))
+        self.pkey = pkey
+        self.look_for_keys = look_for_keys
+        self.key_filename = key_filename
+        self.timeout = int(timeout)
+        self.channel_timeout = float(channel_timeout)
+        self.buf_size = 1024
+
+    def _get_ssh_connection(self, sleep=1.5, backoff=1):
+        """Returns an ssh connection to the specified host."""
+        bsleep = sleep
+        ssh = paramiko.SSHClient()
+        ssh.set_missing_host_key_policy(
+            paramiko.AutoAddPolicy())
+        _start_time = time.time()
+        if self.pkey is not None:
+            LOG.info("Creating ssh connection to '%s' as '%s'"
+                     " with public key authentication",
+                     self.host, self.username)
+        else:
+            LOG.info("Creating ssh connection to '%s' as '%s'"
+                     " with password %s",
+                     self.host, self.username, str(self.password))
+        attempts = 0
+        while True:
+            try:
+                ssh.connect(self.host, username=self.username,
+                            password=self.password,
+                            look_for_keys=self.look_for_keys,
+                            key_filename=self.key_filename,
+                            timeout=self.channel_timeout, pkey=self.pkey)
+                LOG.info("ssh connection to %s@%s successfully created",
+                         self.username, self.host)
+                return ssh
+            except (EOFError,
+                    socket.error,
+                    paramiko.SSHException) as e:
+                if self._is_timed_out(_start_time):
+                    LOG.exception("Failed to establish authenticated ssh"
+                                  " connection to %s@%s after %d attempts",
+                                  self.username, self.host, attempts)
+                    raise exceptions.SSHTimeout(host=self.host,
+                                                user=self.username,
+                                                password=self.password)
+                bsleep += backoff
+                attempts += 1
+                LOG.warning("Failed to establish authenticated ssh"
+                            " connection to %s@%s (%s). Number attempts: %s."
+                            " Retry after %d seconds.",
+                            self.username, self.host, e, attempts, bsleep)
+                time.sleep(bsleep)
+
+    def _is_timed_out(self, start_time):
+        return (time.time() - self.timeout) > start_time
+
+    @staticmethod
+    def _can_system_poll():
+        return hasattr(select, 'poll')
+
+    def exec_command(self, cmd, encoding="utf-8"):
+        """Execute the specified command on the server
+
+        Note that this method is reading whole command outputs to memory, thus
+        shouldn't be used for large outputs.
+
+        :param str cmd: Command to run at remote server.
+        :param str encoding: Encoding for result from paramiko.
+                             Result will not be decoded if None.
+        :returns: data read from standard output of the command.
+        :raises: SSHExecCommandFailed if command returns nonzero
+                 status. The exception contains command status stderr content.
+        :raises: TimeoutException if cmd doesn't end when timeout expires.
+        """
+        ssh = self._get_ssh_connection()
+        transport = ssh.get_transport()
+        channel = transport.open_session()
+        channel.fileno()  # Register event pipe
+        channel.exec_command(cmd)
+        channel.shutdown_write()
+        exit_status = channel.recv_exit_status()
+
+        # If the executing host is linux-based, poll the channel
+        if self._can_system_poll():
+            out_data_chunks = []
+            err_data_chunks = []
+            poll = select.poll()
+            poll.register(channel, select.POLLIN)
+            start_time = time.time()
+
+            while True:
+                ready = poll.poll(self.channel_timeout)
+                if not any(ready):
+                    if not self._is_timed_out(start_time):
+                        continue
+                    raise exceptions.TimeoutException(
+                        "Command: '{0}' executed on host '{1}'.".format(
+                            cmd, self.host))
+                if not ready[0]:  # If there is nothing to read.
+                    continue
+                out_chunk = err_chunk = None
+                if channel.recv_ready():
+                    out_chunk = channel.recv(self.buf_size)
+                    out_data_chunks += out_chunk,
+                if channel.recv_stderr_ready():
+                    err_chunk = channel.recv_stderr(self.buf_size)
+                    err_data_chunks += err_chunk,
+                if channel.closed and not err_chunk and not out_chunk:
+                    break
+            out_data = b''.join(out_data_chunks)
+            err_data = b''.join(err_data_chunks)
+        # Just read from the channels
+        else:
+            out_file = channel.makefile('rb', self.buf_size)
+            err_file = channel.makefile_stderr('rb', self.buf_size)
+            out_data = out_file.read()
+            err_data = err_file.read()
+        if encoding:
+            out_data = out_data.decode(encoding)
+            err_data = err_data.decode(encoding)
+
+        if 0 != exit_status:
+            raise exceptions.SSHExecCommandFailed(
+                command=cmd, exit_status=exit_status,
+                stderr=err_data, stdout=out_data)
+        return out_data
+
+    def test_connection_auth(self):
+        """Raises an exception when we can not connect to server via ssh."""
+        connection = self._get_ssh_connection()
+        connection.close()
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/common/utils/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/common/utils/__init__.py
diff --git a/tempest/lib/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py
new file mode 100644
index 0000000..01b6477
--- /dev/null
+++ b/tempest/lib/common/utils/data_utils.py
@@ -0,0 +1,186 @@
+# 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.
+
+import itertools
+import netaddr
+import random
+import string
+import uuid
+
+
+def rand_uuid():
+    """Generate a random UUID string
+
+    :return: a random UUID (e.g. '1dc12c7d-60eb-4b61-a7a2-17cf210155b6')
+    :rtype: string
+    """
+    return str(uuid.uuid4())
+
+
+def rand_uuid_hex():
+    """Generate a random UUID hex string
+
+    :return: a random UUID (e.g. '0b98cf96d90447bda4b46f31aeb1508c')
+    :rtype: string
+    """
+    return uuid.uuid4().hex
+
+
+def rand_name(name='', prefix=None):
+    """Generate a random name that inclues a random number
+
+    :param str name: The name that you want to include
+    :param str prefix: The prefix that you want to include
+    :return: a random name. The format is
+             '<prefix>-<random number>-<name>-<random number>'.
+             (e.g. 'prefixfoo-1308607012-namebar-154876201')
+    :rtype: string
+    """
+    randbits = str(random.randint(1, 0x7fffffff))
+    rand_name = randbits
+    if name:
+        rand_name = name + '-' + rand_name
+    if prefix:
+        rand_name = prefix + '-' + rand_name
+    return rand_name
+
+
+def rand_password(length=15):
+    """Generate a random password
+
+    :param int length: The length of password that you expect to set
+                       (If it's smaller than 3, it's same as 3.)
+    :return: a random password. The format is
+             '<random upper letter>-<random number>-<random special character>
+              -<random ascii letters or digit characters or special symbols>'
+             (e.g. 'G2*ac8&lKFFgh%2')
+    :rtype: string
+    """
+    upper = random.choice(string.ascii_uppercase)
+    ascii_char = string.ascii_letters
+    digits = string.digits
+    digit = random.choice(string.digits)
+    puncs = '~!@#$%^&*_=+'
+    punc = random.choice(puncs)
+    seed = ascii_char + digits + puncs
+    pre = upper + digit + punc
+    password = pre + ''.join(random.choice(seed) for x in range(length - 3))
+    return password
+
+
+def rand_url():
+    """Generate a random url that inclues a random number
+
+    :return: a random url. The format is 'https://url-<random number>.com'.
+             (e.g. 'https://url-154876201.com')
+    :rtype: string
+    """
+    randbits = str(random.randint(1, 0x7fffffff))
+    return 'https://url-' + randbits + '.com'
+
+
+def rand_int_id(start=0, end=0x7fffffff):
+    """Generate a random integer value
+
+    :param int start: The value that you expect to start here
+    :param int end: The value that you expect to end here
+    :return: a random integer value
+    :rtype: int
+    """
+    return random.randint(start, end)
+
+
+def rand_mac_address():
+    """Generate an Ethernet MAC address
+
+    :return: an random Ethernet MAC address
+    :rtype: string
+    """
+    # NOTE(vish): We would prefer to use 0xfe here to ensure that linux
+    #             bridge mac addresses don't change, but it appears to
+    #             conflict with libvirt, so we use the next highest octet
+    #             that has the unicast and locally administered bits set
+    #             properly: 0xfa.
+    #             Discussion: https://bugs.launchpad.net/nova/+bug/921838
+    mac = [0xfa, 0x16, 0x3e,
+           random.randint(0x00, 0xff),
+           random.randint(0x00, 0xff),
+           random.randint(0x00, 0xff)]
+    return ':'.join(["%02x" % x for x in mac])
+
+
+def parse_image_id(image_ref):
+    """Return the image id from a given image ref
+
+    This function just returns the last word of the given image ref string
+    splitting with '/'.
+    :param str image_ref: a string that includes the image id
+    :return: the image id string
+    :rtype: string
+    """
+    return image_ref.rsplit('/')[-1]
+
+
+def arbitrary_string(size=4, base_text=None):
+    """Return size characters from base_text
+
+    This generates a string with an arbitrary number of characters, generated
+    by looping the base_text string. If the size is smaller than the size of
+    base_text, returning string is shrinked to the size.
+    :param int size: a returning charactors size
+    :param str base_text: a string you want to repeat
+    :return: size string
+    :rtype: string
+    """
+    if not base_text:
+        base_text = 'test'
+    return ''.join(itertools.islice(itertools.cycle(base_text), size))
+
+
+def random_bytes(size=1024):
+    """Return size randomly selected bytes as a string
+
+    :param int size: a returning bytes size
+    :return: size randomly bytes
+    :rtype: string
+    """
+    return ''.join([chr(random.randint(0, 255))
+                    for i in range(size)])
+
+
+def get_ipv6_addr_by_EUI64(cidr, mac):
+    """Generate a IPv6 addr by EUI-64 with CIDR and MAC
+
+    :param str cidr: a IPv6 CIDR
+    :param str mac: a MAC address
+    :return: an IPv6 Address
+    :rtype: netaddr.IPAddress
+    """
+    # Check if the prefix is IPv4 address
+    is_ipv4 = netaddr.valid_ipv4(cidr)
+    if is_ipv4:
+        msg = "Unable to generate IP address by EUI64 for IPv4 prefix"
+        raise TypeError(msg)
+    try:
+        eui64 = int(netaddr.EUI(mac).eui64())
+        prefix = netaddr.IPNetwork(cidr)
+        return netaddr.IPAddress(prefix.first + eui64 ^ (1 << 57))
+    except (ValueError, netaddr.AddrFormatError):
+        raise TypeError('Bad prefix or mac format for generating IPv6 '
+                        'address by EUI-64: %(prefix)s, %(mac)s:'
+                        % {'prefix': cidr, 'mac': mac})
+    except TypeError:
+        raise TypeError('Bad prefix type for generate IPv6 address by '
+                        'EUI-64: %s' % cidr)
diff --git a/tempest/lib/common/utils/misc.py b/tempest/lib/common/utils/misc.py
new file mode 100644
index 0000000..b97dd86
--- /dev/null
+++ b/tempest/lib/common/utils/misc.py
@@ -0,0 +1,87 @@
+# 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.
+
+import inspect
+import re
+
+from oslo_log import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+def singleton(cls):
+    """Simple wrapper for classes that should only have a single instance."""
+    instances = {}
+
+    def getinstance():
+        if cls not in instances:
+            instances[cls] = cls()
+        return instances[cls]
+    return getinstance
+
+
+def find_test_caller():
+    """Find the caller class and test name.
+
+    Because we know that the interesting things that call us are
+    test_* methods, and various kinds of setUp / tearDown, we
+    can look through the call stack to find appropriate methods,
+    and the class we were in when those were called.
+    """
+    caller_name = None
+    names = []
+    frame = inspect.currentframe()
+    is_cleanup = False
+    # Start climbing the ladder until we hit a good method
+    while True:
+        try:
+            frame = frame.f_back
+            name = frame.f_code.co_name
+            names.append(name)
+            if re.search("^(test_|setUp|tearDown)", name):
+                cname = ""
+                if 'self' in frame.f_locals:
+                    cname = frame.f_locals['self'].__class__.__name__
+                if 'cls' in frame.f_locals:
+                    cname = frame.f_locals['cls'].__name__
+                caller_name = cname + ":" + name
+                break
+            elif re.search("^_run_cleanup", name):
+                is_cleanup = True
+            elif name == 'main':
+                caller_name = 'main'
+                break
+            else:
+                cname = ""
+                if 'self' in frame.f_locals:
+                    cname = frame.f_locals['self'].__class__.__name__
+                if 'cls' in frame.f_locals:
+                    cname = frame.f_locals['cls'].__name__
+
+                # the fact that we are running cleanups is indicated pretty
+                # deep in the stack, so if we see that we want to just
+                # start looking for a real class name, and declare victory
+                # once we do.
+                if is_cleanup and cname:
+                    if not re.search("^RunTest", cname):
+                        caller_name = cname + ":_run_cleanups"
+                        break
+        except Exception:
+            break
+    # prevents frame leaks
+    del frame
+    if caller_name is None:
+        LOG.debug("Sane call name not found in %s" % names)
+    return caller_name
diff --git a/tempest/lib/decorators.py b/tempest/lib/decorators.py
new file mode 100644
index 0000000..e78e624
--- /dev/null
+++ b/tempest/lib/decorators.py
@@ -0,0 +1,80 @@
+# Copyright 2015 Hewlett-Packard Development Company, L.P.
+#
+# 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 functools
+import uuid
+
+import six
+import testtools
+
+
+def skip_because(*args, **kwargs):
+    """A decorator useful to skip tests hitting known bugs
+
+    @param bug: bug number causing the test to skip
+    @param condition: optional condition to be True for the skip to have place
+    """
+    def decorator(f):
+        @functools.wraps(f)
+        def wrapper(self, *func_args, **func_kwargs):
+            skip = False
+            if "condition" in kwargs:
+                if kwargs["condition"] is True:
+                    skip = True
+            else:
+                skip = True
+            if "bug" in kwargs and skip is True:
+                if not kwargs['bug'].isdigit():
+                    raise ValueError('bug must be a valid bug number')
+                msg = "Skipped until Bug: %s is resolved." % kwargs["bug"]
+                raise testtools.TestCase.skipException(msg)
+            return f(self, *func_args, **func_kwargs)
+        return wrapper
+    return decorator
+
+
+def idempotent_id(id):
+    """Stub for metadata decorator"""
+    if not isinstance(id, six.string_types):
+        raise TypeError('Test idempotent_id must be string not %s'
+                        '' % type(id).__name__)
+    uuid.UUID(id)
+
+    def decorator(f):
+        f = testtools.testcase.attr('id-%s' % id)(f)
+        if f.__doc__:
+            f.__doc__ = 'Test idempotent id: %s\n%s' % (id, f.__doc__)
+        else:
+            f.__doc__ = 'Test idempotent id: %s' % id
+        return f
+    return decorator
+
+
+class skip_unless_attr(object):
+    """Decorator to skip tests if a specified attr does not exists or False"""
+    def __init__(self, attr, msg=None):
+        self.attr = attr
+        self.message = msg or ("Test case attribute %s not found "
+                               "or False") % attr
+
+    def __call__(self, func):
+        def _skipper(*args, **kw):
+            """Wrapped skipper function."""
+            testobj = args[0]
+            if not getattr(testobj, self.attr, False):
+                raise testtools.TestCase.skipException(self.message)
+            func(*args, **kw)
+        _skipper.__name__ = func.__name__
+        _skipper.__doc__ = func.__doc__
+        return _skipper
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
new file mode 100644
index 0000000..2bf7cdd
--- /dev/null
+++ b/tempest/lib/exceptions.py
@@ -0,0 +1,205 @@
+# 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.
+
+import testtools
+
+
+class TempestException(Exception):
+    """Base Tempest Exception
+
+    To correctly use this class, inherit from it and define
+    a 'message' property. That message will get printf'd
+    with the keyword arguments provided to the constructor.
+    """
+    message = "An unknown exception occurred"
+
+    def __init__(self, *args, **kwargs):
+        super(TempestException, self).__init__()
+        try:
+            self._error_string = self.message % kwargs
+        except Exception:
+            # at least get the core message out if something happened
+            self._error_string = self.message
+        if len(args) > 0:
+            # If there is a non-kwarg parameter, assume it's the error
+            # message or reason description and tack it on to the end
+            # of the exception message
+            # Convert all arguments into their string representations...
+            args = ["%s" % arg for arg in args]
+            self._error_string = (self._error_string +
+                                  "\nDetails: %s" % '\n'.join(args))
+
+    def __str__(self):
+        return self._error_string
+
+
+class RestClientException(TempestException,
+                          testtools.TestCase.failureException):
+    def __init__(self, resp_body=None, *args, **kwargs):
+        if 'resp' in kwargs:
+            self.resp = kwargs.get('resp')
+        self.resp_body = resp_body
+        message = kwargs.get("message", resp_body)
+        super(RestClientException, self).__init__(message, *args, **kwargs)
+
+
+class OtherRestClientException(RestClientException):
+    pass
+
+
+class ServerRestClientException(RestClientException):
+    pass
+
+
+class ClientRestClientException(RestClientException):
+    pass
+
+
+class InvalidHttpSuccessCode(OtherRestClientException):
+    message = "The success code is different than the expected one"
+
+
+class NotFound(ClientRestClientException):
+    message = "Object not found"
+
+
+class Unauthorized(ClientRestClientException):
+    message = 'Unauthorized'
+
+
+class Forbidden(ClientRestClientException):
+    message = "Forbidden"
+
+
+class TimeoutException(OtherRestClientException):
+    message = "Request timed out"
+
+
+class BadRequest(ClientRestClientException):
+    message = "Bad request"
+
+
+class UnprocessableEntity(ClientRestClientException):
+    message = "Unprocessable entity"
+
+
+class RateLimitExceeded(ClientRestClientException):
+    message = "Rate limit exceeded"
+
+
+class OverLimit(ClientRestClientException):
+    message = "Quota exceeded"
+
+
+class ServerFault(ServerRestClientException):
+    message = "Got server fault"
+
+
+class NotImplemented(ServerRestClientException):
+    message = "Got NotImplemented error"
+
+
+class Conflict(ClientRestClientException):
+    message = "An object with that identifier already exists"
+
+
+class Gone(ClientRestClientException):
+    message = "The requested resource is no longer available"
+
+
+class ResponseWithNonEmptyBody(OtherRestClientException):
+    message = ("RFC Violation! Response with %(status)d HTTP Status Code "
+               "MUST NOT have a body")
+
+
+class ResponseWithEntity(OtherRestClientException):
+    message = ("RFC Violation! Response with 205 HTTP Status Code "
+               "MUST NOT have an entity")
+
+
+class InvalidHTTPResponseBody(OtherRestClientException):
+    message = "HTTP response body is invalid json or xml"
+
+
+class InvalidHTTPResponseHeader(OtherRestClientException):
+    message = "HTTP response header is invalid"
+
+
+class InvalidContentType(ClientRestClientException):
+    message = "Invalid content type provided"
+
+
+class UnexpectedContentType(OtherRestClientException):
+    message = "Unexpected content type provided"
+
+
+class UnexpectedResponseCode(OtherRestClientException):
+    message = "Unexpected response code received"
+
+
+class InvalidStructure(TempestException):
+    message = "Invalid structure of table with details"
+
+
+class BadAltAuth(TempestException):
+    """Used when trying and failing to change to alt creds.
+
+    If alt creds end up the same as primary creds, use this
+    exception. This is often going to be the case when you assume
+    project_id is in the url, but it's not.
+
+    """
+    message = "The alt auth looks the same as primary auth for %(part)s"
+
+
+class CommandFailed(Exception):
+    def __init__(self, returncode, cmd, output, stderr):
+        super(CommandFailed, self).__init__()
+        self.returncode = returncode
+        self.cmd = cmd
+        self.stdout = output
+        self.stderr = stderr
+
+    def __str__(self):
+        return ("Command '%s' returned non-zero exit status %d.\n"
+                "stdout:\n%s\n"
+                "stderr:\n%s" % (self.cmd,
+                                 self.returncode,
+                                 self.stdout,
+                                 self.stderr))
+
+
+class IdentityError(TempestException):
+    message = "Got identity error"
+
+
+class EndpointNotFound(TempestException):
+    message = "Endpoint not found"
+
+
+class InvalidCredentials(TempestException):
+    message = "Invalid Credentials"
+
+
+class SSHTimeout(TempestException):
+    message = ("Connection to the %(host)s via SSH timed out.\n"
+               "User: %(user)s, Password: %(password)s")
+
+
+class SSHExecCommandFailed(TempestException):
+    """Raised when remotely executed command returns nonzero status."""
+    message = ("Command '%(command)s', exit status: %(exit_status)d, "
+               "stderr:\n%(stderr)s\n"
+               "stdout:\n%(stdout)s")
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/services/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/services/__init__.py
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/services/compute/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/services/compute/__init__.py
diff --git a/tempest/lib/services/compute/agents_client.py b/tempest/lib/services/compute/agents_client.py
new file mode 100644
index 0000000..8b11e64
--- /dev/null
+++ b/tempest/lib/services/compute/agents_client.py
@@ -0,0 +1,63 @@
+# Copyright 2014 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 oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
+
+from tempest.lib.api_schema.response.compute.v2_1 import agents as schema
+from tempest.lib.common import rest_client
+
+
+class AgentsClient(rest_client.RestClient):
+    """Tests Agents API"""
+
+    def list_agents(self, **params):
+        """List all agent builds."""
+        url = 'os-agents'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.list_agents, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_agent(self, **kwargs):
+        """Create an agent build.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#agentbuild
+        """
+        post_body = json.dumps({'agent': kwargs})
+        resp, body = self.post('os-agents', post_body)
+        body = json.loads(body)
+        self.validate_response(schema.create_agent, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_agent(self, agent_id):
+        """Delete an existing agent build."""
+        resp, body = self.delete("os-agents/%s" % agent_id)
+        self.validate_response(schema.delete_agent, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_agent(self, agent_id, **kwargs):
+        """Update an agent build.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#updatebuild
+        """
+        put_body = json.dumps({'para': kwargs})
+        resp, body = self.put('os-agents/%s' % agent_id, put_body)
+        body = json.loads(body)
+        self.validate_response(schema.update_agent, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/aggregates_client.py b/tempest/lib/services/compute/aggregates_client.py
new file mode 100644
index 0000000..b481674
--- /dev/null
+++ b/tempest/lib/services/compute/aggregates_client.py
@@ -0,0 +1,116 @@
+# Copyright 2013 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 oslo_serialization import jsonutils as json
+
+from tempest.lib.api_schema.response.compute.v2_1 import aggregates as schema
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
+
+
+class AggregatesClient(rest_client.RestClient):
+
+    def list_aggregates(self):
+        """Get aggregate list."""
+        resp, body = self.get("os-aggregates")
+        body = json.loads(body)
+        self.validate_response(schema.list_aggregates, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_aggregate(self, aggregate_id):
+        """Get details of the given aggregate."""
+        resp, body = self.get("os-aggregates/%s" % aggregate_id)
+        body = json.loads(body)
+        self.validate_response(schema.get_aggregate, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_aggregate(self, **kwargs):
+        """Create a new aggregate.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#createaggregate
+        """
+        post_body = json.dumps({'aggregate': kwargs})
+        resp, body = self.post('os-aggregates', post_body)
+
+        body = json.loads(body)
+        self.validate_response(schema.create_aggregate, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_aggregate(self, aggregate_id, **kwargs):
+        """Update an aggregate.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#updateaggregate
+        """
+        put_body = json.dumps({'aggregate': kwargs})
+        resp, body = self.put('os-aggregates/%s' % aggregate_id, put_body)
+
+        body = json.loads(body)
+        self.validate_response(schema.update_aggregate, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_aggregate(self, aggregate_id):
+        """Delete the given aggregate."""
+        resp, body = self.delete("os-aggregates/%s" % aggregate_id)
+        self.validate_response(schema.delete_aggregate, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def is_resource_deleted(self, id):
+        try:
+            self.show_aggregate(id)
+        except lib_exc.NotFound:
+            return True
+        return False
+
+    @property
+    def resource_type(self):
+        """Return the primary type of resource this client works with."""
+        return 'aggregate'
+
+    def add_host(self, aggregate_id, **kwargs):
+        """Add a host to the given aggregate.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#addhost
+        """
+        post_body = json.dumps({'add_host': kwargs})
+        resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
+                               post_body)
+        body = json.loads(body)
+        self.validate_response(schema.aggregate_add_remove_host, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def remove_host(self, aggregate_id, **kwargs):
+        """Remove a host from the given aggregate.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#removehost
+        """
+        post_body = json.dumps({'remove_host': kwargs})
+        resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
+                               post_body)
+        body = json.loads(body)
+        self.validate_response(schema.aggregate_add_remove_host, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def set_metadata(self, aggregate_id, **kwargs):
+        """Replace the aggregate's existing metadata with new metadata."""
+        post_body = json.dumps({'set_metadata': kwargs})
+        resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
+                               post_body)
+        body = json.loads(body)
+        self.validate_response(schema.aggregate_set_metadata, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/availability_zone_client.py b/tempest/lib/services/compute/availability_zone_client.py
new file mode 100644
index 0000000..00f66d6
--- /dev/null
+++ b/tempest/lib/services/compute/availability_zone_client.py
@@ -0,0 +1,35 @@
+# Copyright 2013 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 oslo_serialization import jsonutils as json
+
+from tempest.lib.api_schema.response.compute.v2_1 import availability_zone \
+    as schema
+from tempest.lib.common import rest_client
+
+
+class AvailabilityZoneClient(rest_client.RestClient):
+
+    def list_availability_zones(self, detail=False):
+        url = 'os-availability-zone'
+        schema_list = schema.list_availability_zone_list
+        if detail:
+            url += '/detail'
+            schema_list = schema.list_availability_zone_list_detail
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema_list, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/baremetal_nodes_client.py b/tempest/lib/services/compute/baremetal_nodes_client.py
new file mode 100644
index 0000000..d9a712e
--- /dev/null
+++ b/tempest/lib/services/compute/baremetal_nodes_client.py
@@ -0,0 +1,42 @@
+# 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.
+
+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 baremetal_nodes \
+    as schema
+from tempest.lib.common import rest_client
+
+
+class BaremetalNodesClient(rest_client.RestClient):
+    """Tests Baremetal API"""
+
+    def list_baremetal_nodes(self, **params):
+        """List all baremetal nodes."""
+        url = 'os-baremetal-nodes'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.list_baremetal_nodes, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_baremetal_node(self, baremetal_node_id):
+        """Return the details of a single baremetal node."""
+        url = 'os-baremetal-nodes/%s' % baremetal_node_id
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.get_baremetal_node, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/certificates_client.py b/tempest/lib/services/compute/certificates_client.py
new file mode 100644
index 0000000..76d830e
--- /dev/null
+++ b/tempest/lib/services/compute/certificates_client.py
@@ -0,0 +1,37 @@
+# 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.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.api_schema.response.compute.v2_1 import certificates as schema
+from tempest.lib.common import rest_client
+
+
+class CertificatesClient(rest_client.RestClient):
+
+    def show_certificate(self, certificate_id):
+        url = "os-certificates/%s" % certificate_id
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.get_certificate, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_certificate(self):
+        """Create a certificate."""
+        url = "os-certificates"
+        resp, body = self.post(url, None)
+        body = json.loads(body)
+        self.validate_response(schema.create_certificate, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/extensions_client.py b/tempest/lib/services/compute/extensions_client.py
new file mode 100644
index 0000000..85f8f0c
--- /dev/null
+++ b/tempest/lib/services/compute/extensions_client.py
@@ -0,0 +1,34 @@
+# 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 tempest.lib.api_schema.response.compute.v2_1 import extensions as schema
+from tempest.lib.common import rest_client
+
+
+class ExtensionsClient(rest_client.RestClient):
+
+    def list_extensions(self):
+        url = 'extensions'
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.list_extensions, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_extension(self, extension_alias):
+        resp, body = self.get('extensions/%s' % extension_alias)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/fixed_ips_client.py b/tempest/lib/services/compute/fixed_ips_client.py
new file mode 100644
index 0000000..76ec59f
--- /dev/null
+++ b/tempest/lib/services/compute/fixed_ips_client.py
@@ -0,0 +1,40 @@
+# 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.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.api_schema.response.compute.v2_1 import fixed_ips as schema
+from tempest.lib.common import rest_client
+
+
+class FixedIPsClient(rest_client.RestClient):
+
+    def show_fixed_ip(self, fixed_ip):
+        url = "os-fixed-ips/%s" % fixed_ip
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.get_fixed_ip, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def reserve_fixed_ip(self, fixed_ip, **kwargs):
+        """Reserve/Unreserve a fixed IP.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#reserveIP
+        """
+        url = "os-fixed-ips/%s/action" % fixed_ip
+        resp, body = self.post(url, json.dumps(kwargs))
+        self.validate_response(schema.reserve_unreserve_fixed_ip, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/flavors_client.py b/tempest/lib/services/compute/flavors_client.py
new file mode 100644
index 0000000..50f1dcc
--- /dev/null
+++ b/tempest/lib/services/compute/flavors_client.py
@@ -0,0 +1,176 @@
+# 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.api_schema.response.compute.v2_1 import flavors as schema
+from tempest.lib.api_schema.response.compute.v2_1 import flavors_access \
+    as schema_access
+from tempest.lib.api_schema.response.compute.v2_1 import flavors_extra_specs \
+    as schema_extra_specs
+from tempest.lib.common import rest_client
+
+
+class FlavorsClient(rest_client.RestClient):
+
+    def list_flavors(self, detail=False, **params):
+        url = 'flavors'
+        _schema = schema.list_flavors
+
+        if detail:
+            url += '/detail'
+            _schema = schema.list_flavors_details
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(_schema, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_flavor(self, flavor_id):
+        resp, body = self.get("flavors/%s" % flavor_id)
+        body = json.loads(body)
+        self.validate_response(schema.create_get_flavor_details, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_flavor(self, **kwargs):
+        """Create a new flavor or instance type.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#create-flavors
+        """
+        if kwargs.get('ephemeral'):
+            kwargs['OS-FLV-EXT-DATA:ephemeral'] = kwargs.pop('ephemeral')
+        if kwargs.get('is_public'):
+            kwargs['os-flavor-access:is_public'] = kwargs.pop('is_public')
+
+        post_body = json.dumps({'flavor': kwargs})
+        resp, body = self.post('flavors', post_body)
+
+        body = json.loads(body)
+        self.validate_response(schema.create_get_flavor_details, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_flavor(self, flavor_id):
+        """Delete the given flavor."""
+        resp, body = self.delete("flavors/{0}".format(flavor_id))
+        self.validate_response(schema.delete_flavor, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def is_resource_deleted(self, id):
+        # Did not use show_flavor(id) for verification as it gives
+        # 200 ok even for deleted id. LP #981263
+        # we can remove the loop here and use get by ID when bug gets sortedout
+        flavors = self.list_flavors(detail=True)['flavors']
+        for flavor in flavors:
+            if flavor['id'] == id:
+                return False
+        return True
+
+    @property
+    def resource_type(self):
+        """Return the primary type of resource this client works with."""
+        return 'flavor'
+
+    def set_flavor_extra_spec(self, flavor_id, **kwargs):
+        """Set extra Specs to the mentioned flavor.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#updateFlavorExtraSpec
+        """
+        post_body = json.dumps({'extra_specs': kwargs})
+        resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id,
+                               post_body)
+        body = json.loads(body)
+        self.validate_response(schema_extra_specs.set_get_flavor_extra_specs,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_flavor_extra_specs(self, flavor_id):
+        """Get extra Specs details of the mentioned flavor."""
+        resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id)
+        body = json.loads(body)
+        self.validate_response(schema_extra_specs.set_get_flavor_extra_specs,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_flavor_extra_spec(self, flavor_id, key):
+        """Get extra Specs key-value of the mentioned flavor and key."""
+        resp, body = self.get('flavors/%s/os-extra_specs/%s' % (flavor_id,
+                              key))
+        body = json.loads(body)
+        self.validate_response(
+            schema_extra_specs.set_get_flavor_extra_specs_key,
+            resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_flavor_extra_spec(self, flavor_id, key, **kwargs):
+        """Update specified extra Specs of the mentioned flavor and key.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#updateflavorspec
+        """
+        resp, body = self.put('flavors/%s/os-extra_specs/%s' %
+                              (flavor_id, key), json.dumps(kwargs))
+        body = json.loads(body)
+        self.validate_response(
+            schema_extra_specs.set_get_flavor_extra_specs_key,
+            resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def unset_flavor_extra_spec(self, flavor_id, key):
+        """Unset extra Specs from the mentioned flavor."""
+        resp, body = self.delete('flavors/%s/os-extra_specs/%s' %
+                                 (flavor_id, key))
+        self.validate_response(schema.unset_flavor_extra_specs, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_flavor_access(self, flavor_id):
+        """Get flavor access information given the flavor id."""
+        resp, body = self.get('flavors/%s/os-flavor-access' % flavor_id)
+        body = json.loads(body)
+        self.validate_response(schema_access.add_remove_list_flavor_access,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def add_flavor_access(self, flavor_id, tenant_id):
+        """Add flavor access for the specified tenant."""
+        post_body = {
+            'addTenantAccess': {
+                'tenant': tenant_id
+            }
+        }
+        post_body = json.dumps(post_body)
+        resp, body = self.post('flavors/%s/action' % flavor_id, post_body)
+        body = json.loads(body)
+        self.validate_response(schema_access.add_remove_list_flavor_access,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def remove_flavor_access(self, flavor_id, tenant_id):
+        """Remove flavor access from the specified tenant."""
+        post_body = {
+            'removeTenantAccess': {
+                'tenant': tenant_id
+            }
+        }
+        post_body = json.dumps(post_body)
+        resp, body = self.post('flavors/%s/action' % flavor_id, post_body)
+        body = json.loads(body)
+        self.validate_response(schema_access.add_remove_list_flavor_access,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/floating_ip_pools_client.py b/tempest/lib/services/compute/floating_ip_pools_client.py
new file mode 100644
index 0000000..d4a0193
--- /dev/null
+++ b/tempest/lib/services/compute/floating_ip_pools_client.py
@@ -0,0 +1,34 @@
+# 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.api_schema.response.compute.v2_1 import floating_ips as schema
+from tempest.lib.common import rest_client
+
+
+class FloatingIPPoolsClient(rest_client.RestClient):
+
+    def list_floating_ip_pools(self, params=None):
+        """Gets all floating IP Pools list."""
+        url = 'os-floating-ip-pools'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.list_floating_ip_pools, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/floating_ips_bulk_client.py b/tempest/lib/services/compute/floating_ips_bulk_client.py
new file mode 100644
index 0000000..bfcf74b
--- /dev/null
+++ b/tempest/lib/services/compute/floating_ips_bulk_client.py
@@ -0,0 +1,50 @@
+# 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 tempest.lib.api_schema.response.compute.v2_1 import floating_ips as schema
+from tempest.lib.common import rest_client
+
+
+class FloatingIPsBulkClient(rest_client.RestClient):
+
+    def create_floating_ips_bulk(self, ip_range, pool, interface):
+        """Allocate floating IPs in bulk."""
+        post_body = {
+            'ip_range': ip_range,
+            'pool': pool,
+            'interface': interface
+        }
+        post_body = json.dumps({'floating_ips_bulk_create': post_body})
+        resp, body = self.post('os-floating-ips-bulk', post_body)
+        body = json.loads(body)
+        self.validate_response(schema.create_floating_ips_bulk, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_floating_ips_bulk(self):
+        """Gets all floating IPs in bulk."""
+        resp, body = self.get('os-floating-ips-bulk')
+        body = json.loads(body)
+        self.validate_response(schema.list_floating_ips_bulk, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_floating_ips_bulk(self, ip_range):
+        """Deletes the provided floating IPs in bulk."""
+        post_body = json.dumps({'ip_range': ip_range})
+        resp, body = self.put('os-floating-ips-bulk/delete', post_body)
+        body = json.loads(body)
+        self.validate_response(schema.delete_floating_ips_bulk, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/floating_ips_client.py b/tempest/lib/services/compute/floating_ips_client.py
new file mode 100644
index 0000000..2569bf9
--- /dev/null
+++ b/tempest/lib/services/compute/floating_ips_client.py
@@ -0,0 +1,103 @@
+# 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.api_schema.response.compute.v2_1 import floating_ips as schema
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
+
+
+class FloatingIPsClient(rest_client.RestClient):
+
+    def list_floating_ips(self, **params):
+        """Returns a list of all floating IPs filtered by any parameters."""
+        url = 'os-floating-ips'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.list_floating_ips, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_floating_ip(self, floating_ip_id):
+        """Get the details of a floating IP."""
+        url = "os-floating-ips/%s" % floating_ip_id
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.create_get_floating_ip, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_floating_ip(self, **kwargs):
+        """Allocate a floating IP to the project.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#createFloatingIP
+        """
+        url = 'os-floating-ips'
+        post_body = json.dumps(kwargs)
+        resp, body = self.post(url, post_body)
+        body = json.loads(body)
+        self.validate_response(schema.create_get_floating_ip, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_floating_ip(self, floating_ip_id):
+        """Deletes the provided floating IP from the project."""
+        url = "os-floating-ips/%s" % floating_ip_id
+        resp, body = self.delete(url)
+        self.validate_response(schema.add_remove_floating_ip, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def associate_floating_ip_to_server(self, floating_ip, server_id):
+        """Associate the provided floating IP to a specific server."""
+        url = "servers/%s/action" % server_id
+        post_body = {
+            'addFloatingIp': {
+                'address': floating_ip,
+            }
+        }
+
+        post_body = json.dumps(post_body)
+        resp, body = self.post(url, post_body)
+        self.validate_response(schema.add_remove_floating_ip, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def disassociate_floating_ip_from_server(self, floating_ip, server_id):
+        """Disassociate the provided floating IP from a specific server."""
+        url = "servers/%s/action" % server_id
+        post_body = {
+            'removeFloatingIp': {
+                'address': floating_ip,
+            }
+        }
+
+        post_body = json.dumps(post_body)
+        resp, body = self.post(url, post_body)
+        self.validate_response(schema.add_remove_floating_ip, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def is_resource_deleted(self, id):
+        try:
+            self.show_floating_ip(id)
+        except lib_exc.NotFound:
+            return True
+        return False
+
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'floating_ip'
diff --git a/tempest/lib/services/compute/hosts_client.py b/tempest/lib/services/compute/hosts_client.py
new file mode 100644
index 0000000..269160e
--- /dev/null
+++ b/tempest/lib/services/compute/hosts_client.py
@@ -0,0 +1,85 @@
+# 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.
+
+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 hosts as schema
+from tempest.lib.common import rest_client
+
+
+class HostsClient(rest_client.RestClient):
+
+    def list_hosts(self, **params):
+        """List all hosts."""
+
+        url = 'os-hosts'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.list_hosts, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_host(self, hostname):
+        """Show detail information for the host."""
+
+        resp, body = self.get("os-hosts/%s" % hostname)
+        body = json.loads(body)
+        self.validate_response(schema.get_host_detail, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_host(self, hostname, **kwargs):
+        """Update a host.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#enablehost
+        """
+
+        request_body = {
+            'status': None,
+            'maintenance_mode': None,
+        }
+        request_body.update(**kwargs)
+        request_body = json.dumps(request_body)
+
+        resp, body = self.put("os-hosts/%s" % hostname, request_body)
+        body = json.loads(body)
+        self.validate_response(schema.update_host, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def startup_host(self, hostname):
+        """Startup a host."""
+
+        resp, body = self.get("os-hosts/%s/startup" % hostname)
+        body = json.loads(body)
+        self.validate_response(schema.startup_host, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def shutdown_host(self, hostname):
+        """Shutdown a host."""
+
+        resp, body = self.get("os-hosts/%s/shutdown" % hostname)
+        body = json.loads(body)
+        self.validate_response(schema.shutdown_host, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def reboot_host(self, hostname):
+        """Reboot a host."""
+
+        resp, body = self.get("os-hosts/%s/reboot" % hostname)
+        body = json.loads(body)
+        self.validate_response(schema.reboot_host, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/hypervisor_client.py b/tempest/lib/services/compute/hypervisor_client.py
new file mode 100644
index 0000000..2e6df1f
--- /dev/null
+++ b/tempest/lib/services/compute/hypervisor_client.py
@@ -0,0 +1,70 @@
+# Copyright 2013 IBM 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.api_schema.response.compute.v2_1 import hypervisors as schema
+from tempest.lib.common import rest_client
+
+
+class HypervisorClient(rest_client.RestClient):
+
+    def list_hypervisors(self, detail=False):
+        """List hypervisors information."""
+        url = 'os-hypervisors'
+        _schema = schema.list_search_hypervisors
+        if detail:
+            url += '/detail'
+            _schema = schema.list_hypervisors_detail
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(_schema, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_hypervisor(self, hypervisor_id):
+        """Display the details of the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s' % hypervisor_id)
+        body = json.loads(body)
+        self.validate_response(schema.get_hypervisor, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_servers_on_hypervisor(self, hypervisor_name):
+        """List instances belonging to the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s/servers' % hypervisor_name)
+        body = json.loads(body)
+        self.validate_response(schema.get_hypervisors_servers, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_hypervisor_statistics(self):
+        """Get hypervisor statistics over all compute nodes."""
+        resp, body = self.get('os-hypervisors/statistics')
+        body = json.loads(body)
+        self.validate_response(schema.get_hypervisor_statistics, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_hypervisor_uptime(self, hypervisor_id):
+        """Display the uptime of the specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s/uptime' % hypervisor_id)
+        body = json.loads(body)
+        self.validate_response(schema.get_hypervisor_uptime, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def search_hypervisor(self, hypervisor_name):
+        """Search specified hypervisor."""
+        resp, body = self.get('os-hypervisors/%s/search' % hypervisor_name)
+        body = json.loads(body)
+        self.validate_response(schema.list_search_hypervisors, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/images_client.py b/tempest/lib/services/compute/images_client.py
new file mode 100644
index 0000000..30ff484
--- /dev/null
+++ b/tempest/lib/services/compute/images_client.py
@@ -0,0 +1,142 @@
+# 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.api_schema.response.compute.v2_1 import images as schema
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
+
+
+class ImagesClient(rest_client.RestClient):
+
+    def create_image(self, server_id, **kwargs):
+        """Create an image of the original server.
+
+        Available params: see http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#createImage
+        """
+
+        post_body = {'createImage': kwargs}
+        post_body = json.dumps(post_body)
+        resp, body = self.post('servers/%s/action' % server_id,
+                               post_body)
+        self.validate_response(schema.create_image, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_images(self, detail=False, **params):
+        """Return a list of all images filtered by any parameter.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#listImages
+        """
+        url = 'images'
+        _schema = schema.list_images
+        if detail:
+            url += '/detail'
+            _schema = schema.list_images_details
+
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(_schema, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_image(self, image_id):
+        """Return the details of a single image."""
+        resp, body = self.get("images/%s" % image_id)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        self.validate_response(schema.get_image, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_image(self, image_id):
+        """Delete the provided image."""
+        resp, body = self.delete("images/%s" % image_id)
+        self.validate_response(schema.delete, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_image_metadata(self, image_id):
+        """List all metadata items for an image."""
+        resp, body = self.get("images/%s/metadata" % image_id)
+        body = json.loads(body)
+        self.validate_response(schema.image_metadata, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def set_image_metadata(self, image_id, meta):
+        """Set the metadata for an image.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#createImageMetadata
+        """
+        post_body = json.dumps({'metadata': meta})
+        resp, body = self.put('images/%s/metadata' % image_id, post_body)
+        body = json.loads(body)
+        self.validate_response(schema.image_metadata, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_image_metadata(self, image_id, meta):
+        """Update the metadata for an image.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#updateImageMetadata
+        """
+        post_body = json.dumps({'metadata': meta})
+        resp, body = self.post('images/%s/metadata' % image_id, post_body)
+        body = json.loads(body)
+        self.validate_response(schema.image_metadata, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_image_metadata_item(self, image_id, key):
+        """Return the value for a specific image metadata key."""
+        resp, body = self.get("images/%s/metadata/%s" % (image_id, key))
+        body = json.loads(body)
+        self.validate_response(schema.image_meta_item, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def set_image_metadata_item(self, image_id, key, meta):
+        """Set the value for a specific image metadata key.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#setImageMetadataItem
+        """
+        post_body = json.dumps({'meta': meta})
+        resp, body = self.put('images/%s/metadata/%s' % (image_id, key),
+                              post_body)
+        body = json.loads(body)
+        self.validate_response(schema.image_meta_item, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_image_metadata_item(self, image_id, key):
+        """Delete a single image metadata key/value pair."""
+        resp, body = self.delete("images/%s/metadata/%s" %
+                                 (image_id, key))
+        self.validate_response(schema.delete, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def is_resource_deleted(self, id):
+        try:
+            self.show_image(id)
+        except lib_exc.NotFound:
+            return True
+        return False
+
+    @property
+    def resource_type(self):
+        """Return the primary type of resource this client works with."""
+        return 'image'
diff --git a/tempest/lib/services/compute/instance_usage_audit_log_client.py b/tempest/lib/services/compute/instance_usage_audit_log_client.py
new file mode 100644
index 0000000..4651b2a
--- /dev/null
+++ b/tempest/lib/services/compute/instance_usage_audit_log_client.py
@@ -0,0 +1,38 @@
+# Copyright 2013 IBM 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.api_schema.response.compute.v2_1 import \
+    instance_usage_audit_logs as schema
+from tempest.lib.common import rest_client
+
+
+class InstanceUsagesAuditLogClient(rest_client.RestClient):
+
+    def list_instance_usage_audit_logs(self):
+        url = 'os-instance_usage_audit_log'
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.list_instance_usage_audit_log,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_instance_usage_audit_log(self, time_before):
+        url = 'os-instance_usage_audit_log/%s' % time_before
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.get_instance_usage_audit_log, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/interfaces_client.py b/tempest/lib/services/compute/interfaces_client.py
new file mode 100644
index 0000000..e7da5a1
--- /dev/null
+++ b/tempest/lib/services/compute/interfaces_client.py
@@ -0,0 +1,55 @@
+# 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.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.api_schema.response.compute.v2_1 import interfaces as schema
+from tempest.lib.common import rest_client
+
+
+class InterfacesClient(rest_client.RestClient):
+
+    def list_interfaces(self, server_id):
+        resp, body = self.get('servers/%s/os-interface' % server_id)
+        body = json.loads(body)
+        self.validate_response(schema.list_interfaces, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_interface(self, server_id, **kwargs):
+        """Create an interface.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#createAttachInterface
+        """
+        post_body = {'interfaceAttachment': kwargs}
+        post_body = json.dumps(post_body)
+        resp, body = self.post('servers/%s/os-interface' % server_id,
+                               body=post_body)
+        body = json.loads(body)
+        self.validate_response(schema.get_create_interfaces, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_interface(self, server_id, port_id):
+        resp, body = self.get('servers/%s/os-interface/%s' % (server_id,
+                                                              port_id))
+        body = json.loads(body)
+        self.validate_response(schema.get_create_interfaces, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_interface(self, server_id, port_id):
+        resp, body = self.delete('servers/%s/os-interface/%s' % (server_id,
+                                                                 port_id))
+        self.validate_response(schema.delete_interface, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/keypairs_client.py b/tempest/lib/services/compute/keypairs_client.py
new file mode 100644
index 0000000..3e3cf8d
--- /dev/null
+++ b/tempest/lib/services/compute/keypairs_client.py
@@ -0,0 +1,51 @@
+# 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 tempest.lib.api_schema.response.compute.v2_1 import keypairs as schema
+from tempest.lib.common import rest_client
+
+
+class KeyPairsClient(rest_client.RestClient):
+
+    def list_keypairs(self):
+        resp, body = self.get("os-keypairs")
+        body = json.loads(body)
+        self.validate_response(schema.list_keypairs, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_keypair(self, keypair_name):
+        resp, body = self.get("os-keypairs/%s" % keypair_name)
+        body = json.loads(body)
+        self.validate_response(schema.get_keypair, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_keypair(self, **kwargs):
+        """Create a keypair.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#createKeypair
+        """
+        post_body = json.dumps({'keypair': kwargs})
+        resp, body = self.post("os-keypairs", body=post_body)
+        body = json.loads(body)
+        self.validate_response(schema.create_keypair, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_keypair(self, keypair_name):
+        resp, body = self.delete("os-keypairs/%s" % keypair_name)
+        self.validate_response(schema.delete_keypair, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/limits_client.py b/tempest/lib/services/compute/limits_client.py
new file mode 100644
index 0000000..c7eba4e
--- /dev/null
+++ b/tempest/lib/services/compute/limits_client.py
@@ -0,0 +1,28 @@
+# 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 tempest.lib.api_schema.response.compute.v2_1 import limits as schema
+from tempest.lib.common import rest_client
+
+
+class LimitsClient(rest_client.RestClient):
+
+    def show_limits(self):
+        resp, body = self.get("limits")
+        body = json.loads(body)
+        self.validate_response(schema.get_limit, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/migrations_client.py b/tempest/lib/services/compute/migrations_client.py
new file mode 100644
index 0000000..21bc37a
--- /dev/null
+++ b/tempest/lib/services/compute/migrations_client.py
@@ -0,0 +1,38 @@
+# Copyright 2014 NEC Corporation.
+#
+#    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.api_schema.response.compute.v2_1 import migrations as schema
+from tempest.lib.common import rest_client
+
+
+class MigrationsClient(rest_client.RestClient):
+
+    def list_migrations(self, **params):
+        """List all migrations.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#returnmigrations
+        """
+
+        url = 'os-migrations'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.list_migrations, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/networks_client.py b/tempest/lib/services/compute/networks_client.py
new file mode 100644
index 0000000..c0eb5ff
--- /dev/null
+++ b/tempest/lib/services/compute/networks_client.py
@@ -0,0 +1,33 @@
+# 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 tempest.lib.common import rest_client
+
+
+class NetworksClient(rest_client.RestClient):
+
+    def list_networks(self):
+        resp, body = self.get("os-networks")
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_network(self, network_id):
+        resp, body = self.get("os-networks/%s" % network_id)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/quota_classes_client.py b/tempest/lib/services/compute/quota_classes_client.py
new file mode 100644
index 0000000..ff4eec0
--- /dev/null
+++ b/tempest/lib/services/compute/quota_classes_client.py
@@ -0,0 +1,48 @@
+# Copyright 2012 NTT Data
+# 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.api_schema.response.compute.v2_1\
+    import quota_classes as classes_schema
+from tempest.lib.common import rest_client
+
+
+class QuotaClassesClient(rest_client.RestClient):
+
+    def show_quota_class_set(self, quota_class_id):
+        """List the quota class set for a quota class."""
+
+        url = 'os-quota-class-sets/%s' % quota_class_id
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(classes_schema.get_quota_class_set, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_quota_class_set(self, quota_class_id, **kwargs):
+        """Update the quota class's limits for one or more resources.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#updatequota
+        """
+        post_body = json.dumps({'quota_class_set': kwargs})
+
+        resp, body = self.put('os-quota-class-sets/%s' % quota_class_id,
+                              post_body)
+
+        body = json.loads(body)
+        self.validate_response(classes_schema.update_quota_class_set,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/quotas_client.py b/tempest/lib/services/compute/quotas_client.py
new file mode 100644
index 0000000..697d004
--- /dev/null
+++ b/tempest/lib/services/compute/quotas_client.py
@@ -0,0 +1,68 @@
+# Copyright 2012 NTT Data
+# 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.api_schema.response.compute.v2_1 import quotas as schema
+from tempest.lib.common import rest_client
+
+
+class QuotasClient(rest_client.RestClient):
+
+    def show_quota_set(self, tenant_id, user_id=None):
+        """List the quota set for a tenant."""
+
+        url = 'os-quota-sets/%s' % tenant_id
+        if user_id:
+            url += '?user_id=%s' % user_id
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.get_quota_set, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_default_quota_set(self, tenant_id):
+        """List the default quota set for a tenant."""
+
+        url = 'os-quota-sets/%s/defaults' % tenant_id
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.get_quota_set, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_quota_set(self, tenant_id, user_id=None, **kwargs):
+        """Updates the tenant's quota limits for one or more resources.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#updatesquotatenant
+        """
+
+        post_body = json.dumps({'quota_set': kwargs})
+
+        if user_id:
+            resp, body = self.put('os-quota-sets/%s?user_id=%s' %
+                                  (tenant_id, user_id), post_body)
+        else:
+            resp, body = self.put('os-quota-sets/%s' % tenant_id,
+                                  post_body)
+
+        body = json.loads(body)
+        self.validate_response(schema.update_quota_set, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_quota_set(self, tenant_id):
+        """Delete the tenant's quota set."""
+        resp, body = self.delete('os-quota-sets/%s' % tenant_id)
+        self.validate_response(schema.delete_quota, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/security_group_default_rules_client.py b/tempest/lib/services/compute/security_group_default_rules_client.py
new file mode 100644
index 0000000..e5f291c
--- /dev/null
+++ b/tempest/lib/services/compute/security_group_default_rules_client.py
@@ -0,0 +1,64 @@
+# Copyright 2014 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 oslo_serialization import jsonutils as json
+
+from tempest.lib.api_schema.response.compute.v2_1 import \
+    security_group_default_rule as schema
+from tempest.lib.common import rest_client
+
+
+class SecurityGroupDefaultRulesClient(rest_client.RestClient):
+
+    def create_security_default_group_rule(self, **kwargs):
+        """Create security group default rule.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html
+                              #createSecGroupDefaultRule
+        """
+        post_body = json.dumps({'security_group_default_rule': kwargs})
+        url = 'os-security-group-default-rules'
+        resp, body = self.post(url, post_body)
+        body = json.loads(body)
+        self.validate_response(schema.create_get_security_group_default_rule,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_security_group_default_rule(self,
+                                           security_group_default_rule_id):
+        """Delete the provided Security Group default rule."""
+        resp, body = self.delete('os-security-group-default-rules/%s' % (
+            security_group_default_rule_id))
+        self.validate_response(schema.delete_security_group_default_rule,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_security_group_default_rules(self):
+        """List all Security Group default rules."""
+        resp, body = self.get('os-security-group-default-rules')
+        body = json.loads(body)
+        self.validate_response(schema.list_security_group_default_rules,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_security_group_default_rule(self, security_group_default_rule_id):
+        """Return the details of provided Security Group default rule."""
+        resp, body = self.get('os-security-group-default-rules/%s' %
+                              security_group_default_rule_id)
+        body = json.loads(body)
+        self.validate_response(schema.create_get_security_group_default_rule,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/security_group_rules_client.py b/tempest/lib/services/compute/security_group_rules_client.py
new file mode 100644
index 0000000..c0e1245
--- /dev/null
+++ b/tempest/lib/services/compute/security_group_rules_client.py
@@ -0,0 +1,43 @@
+# 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 tempest.lib.api_schema.response.compute.v2_1 import \
+    security_groups as schema
+from tempest.lib.common import rest_client
+
+
+class SecurityGroupRulesClient(rest_client.RestClient):
+
+    def create_security_group_rule(self, **kwargs):
+        """Create a new security group rule.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#createSecGroupRule
+        """
+        post_body = json.dumps({'security_group_rule': kwargs})
+        url = 'os-security-group-rules'
+        resp, body = self.post(url, post_body)
+        body = json.loads(body)
+        self.validate_response(schema.create_security_group_rule, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_security_group_rule(self, group_rule_id):
+        """Deletes the provided Security Group rule."""
+        resp, body = self.delete('os-security-group-rules/%s' %
+                                 group_rule_id)
+        self.validate_response(schema.delete_security_group_rule, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/security_groups_client.py b/tempest/lib/services/compute/security_groups_client.py
new file mode 100644
index 0000000..4db98c9
--- /dev/null
+++ b/tempest/lib/services/compute/security_groups_client.py
@@ -0,0 +1,89 @@
+# 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.api_schema.response.compute.v2_1 import \
+    security_groups as schema
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
+
+
+class SecurityGroupsClient(rest_client.RestClient):
+
+    def list_security_groups(self, **params):
+        """List all security groups for a user."""
+
+        url = 'os-security-groups'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.list_security_groups, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_security_group(self, security_group_id):
+        """Get the details of a Security Group."""
+        url = "os-security-groups/%s" % security_group_id
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.get_security_group, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_security_group(self, **kwargs):
+        """Create a new security group.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#createSecGroup
+        """
+        post_body = json.dumps({'security_group': kwargs})
+        resp, body = self.post('os-security-groups', post_body)
+        body = json.loads(body)
+        self.validate_response(schema.get_security_group, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_security_group(self, security_group_id, **kwargs):
+        """Update a security group.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#updateSecGroup
+        """
+        post_body = json.dumps({'security_group': kwargs})
+        resp, body = self.put('os-security-groups/%s' % security_group_id,
+                              post_body)
+        body = json.loads(body)
+        self.validate_response(schema.update_security_group, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_security_group(self, security_group_id):
+        """Delete the provided Security Group."""
+        resp, body = self.delete(
+            'os-security-groups/%s' % security_group_id)
+        self.validate_response(schema.delete_security_group, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def is_resource_deleted(self, id):
+        try:
+            self.show_security_group(id)
+        except lib_exc.NotFound:
+            return True
+        return False
+
+    @property
+    def resource_type(self):
+        """Return the primary type of resource this client works with."""
+        return 'security_group'
diff --git a/tempest/lib/services/compute/server_groups_client.py b/tempest/lib/services/compute/server_groups_client.py
new file mode 100644
index 0000000..ea60e98
--- /dev/null
+++ b/tempest/lib/services/compute/server_groups_client.py
@@ -0,0 +1,56 @@
+# Copyright 2012 OpenStack Foundation
+# Copyright 2013 Hewlett-Packard Development Company, L.P.
+# 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.api_schema.response.compute.v2_1 import servers as schema
+from tempest.lib.common import rest_client
+
+
+class ServerGroupsClient(rest_client.RestClient):
+
+    def create_server_group(self, **kwargs):
+        """Create the server group.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#createServerGroup
+        """
+        post_body = json.dumps({'server_group': kwargs})
+        resp, body = self.post('os-server-groups', post_body)
+
+        body = json.loads(body)
+        self.validate_response(schema.create_show_server_group, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_server_group(self, server_group_id):
+        """Delete the given server-group."""
+        resp, body = self.delete("os-server-groups/%s" % server_group_id)
+        self.validate_response(schema.delete_server_group, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_server_groups(self):
+        """List the server-groups."""
+        resp, body = self.get("os-server-groups")
+        body = json.loads(body)
+        self.validate_response(schema.list_server_groups, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_server_group(self, server_group_id):
+        """Get the details of given server_group."""
+        resp, body = self.get("os-server-groups/%s" % server_group_id)
+        body = json.loads(body)
+        self.validate_response(schema.create_show_server_group, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
new file mode 100644
index 0000000..46c4a49
--- /dev/null
+++ b/tempest/lib/services/compute/servers_client.py
@@ -0,0 +1,570 @@
+# Copyright 2012 OpenStack Foundation
+# Copyright 2013 Hewlett-Packard Development Company, L.P.
+# 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 copy
+
+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 servers as schema
+from tempest.lib.common import rest_client
+
+
+class ServersClient(rest_client.RestClient):
+
+    def __init__(self, auth_provider, service, region,
+                 enable_instance_password=True, **kwargs):
+        super(ServersClient, self).__init__(
+            auth_provider, service, region, **kwargs)
+        self.enable_instance_password = enable_instance_password
+
+    def create_server(self, **kwargs):
+        """Create server.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#createServer
+
+        Most parameters except the following are passed to the API without
+        any changes.
+        :param disk_config: The name is changed to OS-DCF:diskConfig
+        :param scheduler_hints: The name is changed to os:scheduler_hints and
+        the parameter is set in the same level as the parameter 'server'.
+        """
+        body = copy.deepcopy(kwargs)
+        if body.get('disk_config'):
+            body['OS-DCF:diskConfig'] = body.pop('disk_config')
+
+        hints = None
+        if body.get('scheduler_hints'):
+            hints = {'os:scheduler_hints': body.pop('scheduler_hints')}
+
+        post_body = {'server': body}
+
+        if hints:
+            post_body = dict(post_body.items() + hints.items())
+
+        post_body = json.dumps(post_body)
+        resp, body = self.post('servers', post_body)
+
+        body = json.loads(body)
+        # NOTE(maurosr): this deals with the case of multiple server create
+        # with return reservation id set True
+        if 'reservation_id' in body:
+            return rest_client.ResponseBody(resp, body)
+        if self.enable_instance_password:
+            create_schema = schema.create_server_with_admin_pass
+        else:
+            create_schema = schema.create_server
+        self.validate_response(create_schema, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_server(self, server_id, **kwargs):
+        """Update server.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#updateServer
+
+        Most parameters except the following are passed to the API without
+        any changes.
+        :param disk_config: The name is changed to OS-DCF:diskConfig
+        """
+        if kwargs.get('disk_config'):
+            kwargs['OS-DCF:diskConfig'] = kwargs.pop('disk_config')
+
+        post_body = json.dumps({'server': kwargs})
+        resp, body = self.put("servers/%s" % server_id, post_body)
+        body = json.loads(body)
+        self.validate_response(schema.update_server, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_server(self, server_id):
+        """Get server details."""
+        resp, body = self.get("servers/%s" % server_id)
+        body = json.loads(body)
+        self.validate_response(schema.get_server, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_server(self, server_id):
+        """Delete server."""
+        resp, body = self.delete("servers/%s" % server_id)
+        self.validate_response(schema.delete_server, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_servers(self, detail=False, **params):
+        """List servers.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#listServers
+                          and http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#listDetailServers
+        """
+
+        url = 'servers'
+        _schema = schema.list_servers
+
+        if detail:
+            url += '/detail'
+            _schema = schema.list_servers_detail
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(_schema, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_addresses(self, server_id):
+        """Lists all addresses for a server."""
+        resp, body = self.get("servers/%s/ips" % server_id)
+        body = json.loads(body)
+        self.validate_response(schema.list_addresses, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_addresses_by_network(self, server_id, network_id):
+        """Lists all addresses of a specific network type for a server."""
+        resp, body = self.get("servers/%s/ips/%s" %
+                              (server_id, network_id))
+        body = json.loads(body)
+        self.validate_response(schema.list_addresses_by_network, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def action(self, server_id, action_name,
+               schema=schema.server_actions_common_schema,
+               **kwargs):
+        post_body = json.dumps({action_name: kwargs})
+        resp, body = self.post('servers/%s/action' % server_id,
+                               post_body)
+        if body:
+            body = json.loads(body)
+        self.validate_response(schema, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_backup(self, server_id, **kwargs):
+        """Backup a server instance.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#createBackup
+        """
+        return self.action(server_id, "createBackup", **kwargs)
+
+    def change_password(self, server_id, **kwargs):
+        """Change the root password for the server.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#changePassword
+        """
+        return self.action(server_id, 'changePassword', **kwargs)
+
+    def show_password(self, server_id):
+        resp, body = self.get("servers/%s/os-server-password" %
+                              server_id)
+        body = json.loads(body)
+        self.validate_response(schema.show_password, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_password(self, server_id):
+        """Removes the encrypted server password from the metadata server
+
+        Note that this does not actually change the instance server
+        password.
+        """
+        resp, body = self.delete("servers/%s/os-server-password" %
+                                 server_id)
+        self.validate_response(schema.server_actions_delete_password,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def reboot_server(self, server_id, **kwargs):
+        """Reboot a server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#reboot
+        """
+        return self.action(server_id, 'reboot', **kwargs)
+
+    def rebuild_server(self, server_id, image_ref, **kwargs):
+        """Rebuild a server with a new image.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#rebuild
+
+        Most parameters except the following are passed to the API without
+        any changes.
+        :param disk_config: The name is changed to OS-DCF:diskConfig
+        """
+        kwargs['imageRef'] = image_ref
+        if 'disk_config' in kwargs:
+            kwargs['OS-DCF:diskConfig'] = kwargs.pop('disk_config')
+        if self.enable_instance_password:
+            rebuild_schema = schema.rebuild_server_with_admin_pass
+        else:
+            rebuild_schema = schema.rebuild_server
+        return self.action(server_id, 'rebuild',
+                           rebuild_schema, **kwargs)
+
+    def resize_server(self, server_id, flavor_ref, **kwargs):
+        """Change the flavor of a server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#resize
+
+        Most parameters except the following are passed to the API without
+        any changes.
+        :param disk_config: The name is changed to OS-DCF:diskConfig
+        """
+        kwargs['flavorRef'] = flavor_ref
+        if 'disk_config' in kwargs:
+            kwargs['OS-DCF:diskConfig'] = kwargs.pop('disk_config')
+        return self.action(server_id, 'resize', **kwargs)
+
+    def confirm_resize_server(self, server_id, **kwargs):
+        """Confirm the flavor change for a server.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#confirmResize
+        """
+        return self.action(server_id, 'confirmResize',
+                           schema.server_actions_confirm_resize,
+                           **kwargs)
+
+    def revert_resize_server(self, server_id, **kwargs):
+        """Revert a server back to its original flavor.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#revertResize
+        """
+        return self.action(server_id, 'revertResize', **kwargs)
+
+    def list_server_metadata(self, server_id):
+        resp, body = self.get("servers/%s/metadata" % server_id)
+        body = json.loads(body)
+        self.validate_response(schema.list_server_metadata, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def set_server_metadata(self, server_id, meta, no_metadata_field=False):
+        if no_metadata_field:
+            post_body = ""
+        else:
+            post_body = json.dumps({'metadata': meta})
+        resp, body = self.put('servers/%s/metadata' % server_id,
+                              post_body)
+        body = json.loads(body)
+        self.validate_response(schema.set_server_metadata, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_server_metadata(self, server_id, meta):
+        post_body = json.dumps({'metadata': meta})
+        resp, body = self.post('servers/%s/metadata' % server_id,
+                               post_body)
+        body = json.loads(body)
+        self.validate_response(schema.update_server_metadata,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_server_metadata_item(self, server_id, key):
+        resp, body = self.get("servers/%s/metadata/%s" % (server_id, key))
+        body = json.loads(body)
+        self.validate_response(schema.set_show_server_metadata_item,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def set_server_metadata_item(self, server_id, key, meta):
+        post_body = json.dumps({'meta': meta})
+        resp, body = self.put('servers/%s/metadata/%s' % (server_id, key),
+                              post_body)
+        body = json.loads(body)
+        self.validate_response(schema.set_show_server_metadata_item,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_server_metadata_item(self, server_id, key):
+        resp, body = self.delete("servers/%s/metadata/%s" %
+                                 (server_id, key))
+        self.validate_response(schema.delete_server_metadata_item,
+                               resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def stop_server(self, server_id, **kwargs):
+        return self.action(server_id, 'os-stop', **kwargs)
+
+    def start_server(self, server_id, **kwargs):
+        return self.action(server_id, 'os-start', **kwargs)
+
+    def attach_volume(self, server_id, **kwargs):
+        """Attaches a volume to a server instance."""
+        post_body = json.dumps({'volumeAttachment': kwargs})
+        resp, body = self.post('servers/%s/os-volume_attachments' % server_id,
+                               post_body)
+        body = json.loads(body)
+        self.validate_response(schema.attach_volume, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_attached_volume(self, server_id, attachment_id, **kwargs):
+        """Swaps a volume attached to an instance for another volume"""
+        post_body = json.dumps({'volumeAttachment': kwargs})
+        resp, body = self.put('servers/%s/os-volume_attachments/%s' %
+                              (server_id, attachment_id),
+                              post_body)
+        self.validate_response(schema.update_attached_volume, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def detach_volume(self, server_id, volume_id):  # noqa
+        """Detaches a volume from a server instance."""
+        resp, body = self.delete('servers/%s/os-volume_attachments/%s' %
+                                 (server_id, volume_id))
+        self.validate_response(schema.detach_volume, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_volume_attachment(self, server_id, volume_id):
+        """Return details about the given volume attachment."""
+        resp, body = self.get('servers/%s/os-volume_attachments/%s' % (
+            server_id, volume_id))
+        body = json.loads(body)
+        self.validate_response(schema.show_volume_attachment, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_volume_attachments(self, server_id):
+        """Returns the list of volume attachments for a given instance."""
+        resp, body = self.get('servers/%s/os-volume_attachments' % (
+            server_id))
+        body = json.loads(body)
+        self.validate_response(schema.list_volume_attachments, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def add_security_group(self, server_id, **kwargs):
+        """Add a security group to the server.
+
+        Available params: TODO
+        """
+        # 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):
+        """Remove a security group from the server.
+
+        Available params: TODO
+        """
+        # 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):
+        """This should be called with administrator privileges.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#migrateLive
+        """
+        return self.action(server_id, 'os-migrateLive', **kwargs)
+
+    def migrate_server(self, server_id, **kwargs):
+        """Migrate a server to a new host.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#migrate
+        """
+        return self.action(server_id, 'migrate', **kwargs)
+
+    def lock_server(self, server_id, **kwargs):
+        """Lock the given server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#lock
+        """
+        return self.action(server_id, 'lock', **kwargs)
+
+    def unlock_server(self, server_id, **kwargs):
+        """UNlock the given server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#unlock
+        """
+        return self.action(server_id, 'unlock', **kwargs)
+
+    def suspend_server(self, server_id, **kwargs):
+        """Suspend the provided server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#suspend
+        """
+        return self.action(server_id, 'suspend', **kwargs)
+
+    def resume_server(self, server_id, **kwargs):
+        """Un-suspend the provided server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#resume
+        """
+        return self.action(server_id, 'resume', **kwargs)
+
+    def pause_server(self, server_id, **kwargs):
+        """Pause the provided server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#pause
+        """
+        return self.action(server_id, 'pause', **kwargs)
+
+    def unpause_server(self, server_id, **kwargs):
+        """Un-pause the provided server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#unpause
+        """
+        return self.action(server_id, 'unpause', **kwargs)
+
+    def reset_state(self, server_id, **kwargs):
+        """Reset the state of a server to active/error.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#resetState
+        """
+        return self.action(server_id, 'os-resetState', **kwargs)
+
+    def shelve_server(self, server_id, **kwargs):
+        """Shelve the provided server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#shelve
+        """
+        return self.action(server_id, 'shelve', **kwargs)
+
+    def unshelve_server(self, server_id, **kwargs):
+        """Un-shelve the provided server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#unshelve
+        """
+        return self.action(server_id, 'unshelve', **kwargs)
+
+    def shelve_offload_server(self, server_id, **kwargs):
+        """Shelve-offload the provided server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#shelveOffload
+        """
+        return self.action(server_id, 'shelveOffload', **kwargs)
+
+    def get_console_output(self, server_id, **kwargs):
+        """Get console output.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#getConsoleOutput
+        """
+        return self.action(server_id, 'os-getConsoleOutput',
+                           schema.get_console_output, **kwargs)
+
+    def list_virtual_interfaces(self, server_id):
+        """List the virtual interfaces used in an instance."""
+        resp, body = self.get('/'.join(['servers', server_id,
+                              'os-virtual-interfaces']))
+        body = json.loads(body)
+        self.validate_response(schema.list_virtual_interfaces, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def rescue_server(self, server_id, **kwargs):
+        """Rescue the provided server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#rescue
+        """
+        return self.action(server_id, 'rescue', schema.rescue_server, **kwargs)
+
+    def unrescue_server(self, server_id):
+        """Unrescue the provided server."""
+        return self.action(server_id, 'unrescue')
+
+    def show_server_diagnostics(self, server_id):
+        """Get the usage data for a server."""
+        resp, body = self.get("servers/%s/diagnostics" % server_id)
+        return rest_client.ResponseBody(resp, json.loads(body))
+
+    def list_instance_actions(self, server_id):
+        """List the provided server action."""
+        resp, body = self.get("servers/%s/os-instance-actions" %
+                              server_id)
+        body = json.loads(body)
+        self.validate_response(schema.list_instance_actions, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_instance_action(self, server_id, request_id):
+        """Returns the action details of the provided server."""
+        resp, body = self.get("servers/%s/os-instance-actions/%s" %
+                              (server_id, request_id))
+        body = json.loads(body)
+        self.validate_response(schema.show_instance_action, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def force_delete_server(self, server_id, **kwargs):
+        """Force delete a server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#forceDelete
+        """
+        return self.action(server_id, 'forceDelete', **kwargs)
+
+    def restore_soft_deleted_server(self, server_id, **kwargs):
+        """Restore a soft-deleted server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#restore
+        """
+        return self.action(server_id, 'restore', **kwargs)
+
+    def reset_network(self, server_id, **kwargs):
+        """Reset the Network of a server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#resetNetwork
+        """
+        return self.action(server_id, 'resetNetwork', **kwargs)
+
+    def inject_network_info(self, server_id, **kwargs):
+        """Inject the Network Info into server.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#injectNetworkInfo
+        """
+        return self.action(server_id, 'injectNetworkInfo', **kwargs)
+
+    def get_vnc_console(self, server_id, **kwargs):
+        """Get URL of VNC console.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#getVNCConsole
+        """
+        return self.action(server_id, "os-getVNCConsole",
+                           schema.get_vnc_console, **kwargs)
+
+    def add_fixed_ip(self, server_id, **kwargs):
+        """Add a fixed IP to server instance.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#addFixedIp
+        """
+        return self.action(server_id, 'addFixedIp', **kwargs)
+
+    def remove_fixed_ip(self, server_id, **kwargs):
+        """Remove input fixed IP from input server instance.
+
+        Available params: http://developer.openstack.org/
+                          api-ref-compute-v2.1.html#removeFixedIp
+        """
+        return self.action(server_id, 'removeFixedIp', **kwargs)
diff --git a/tempest/lib/services/compute/services_client.py b/tempest/lib/services/compute/services_client.py
new file mode 100644
index 0000000..06aad77
--- /dev/null
+++ b/tempest/lib/services/compute/services_client.py
@@ -0,0 +1,58 @@
+# Copyright 2013 NEC Corporation
+# 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.
+
+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 services as schema
+from tempest.lib.common import rest_client
+
+
+class ServicesClient(rest_client.RestClient):
+
+    def list_services(self, **params):
+        url = 'os-services'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.list_services, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def enable_service(self, **kwargs):
+        """Enable service on a host.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#enableScheduling
+        """
+        post_body = json.dumps(kwargs)
+        resp, body = self.put('os-services/enable', post_body)
+        body = json.loads(body)
+        self.validate_response(schema.enable_disable_service, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def disable_service(self, **kwargs):
+        """Disable service on a host.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#disableScheduling
+        """
+        post_body = json.dumps(kwargs)
+        resp, body = self.put('os-services/disable', post_body)
+        body = json.loads(body)
+        self.validate_response(schema.enable_disable_service, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/snapshots_client.py b/tempest/lib/services/compute/snapshots_client.py
new file mode 100644
index 0000000..de776bd
--- /dev/null
+++ b/tempest/lib/services/compute/snapshots_client.py
@@ -0,0 +1,76 @@
+# Copyright 2015 Fujitsu(fnst) 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 six.moves.urllib import parse as urllib
+
+from tempest.lib.api_schema.response.compute.v2_1 import snapshots as schema
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
+
+
+class SnapshotsClient(rest_client.RestClient):
+
+    def create_snapshot(self, volume_id, **kwargs):
+        """Create a snapshot.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#createSnapshot
+        """
+        post_body = {
+            'volume_id': volume_id
+        }
+        post_body.update(kwargs)
+        post_body = json.dumps({'snapshot': post_body})
+        resp, body = self.post('os-snapshots', post_body)
+        body = json.loads(body)
+        self.validate_response(schema.create_get_snapshot, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_snapshot(self, snapshot_id):
+        url = "os-snapshots/%s" % snapshot_id
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.create_get_snapshot, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_snapshots(self, detail=False, params=None):
+        url = 'os-snapshots'
+
+        if detail:
+            url += '/detail'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.list_snapshots, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_snapshot(self, snapshot_id):
+        resp, body = self.delete("os-snapshots/%s" % snapshot_id)
+        self.validate_response(schema.delete_snapshot, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def is_resource_deleted(self, id):
+        try:
+            self.show_snapshot(id)
+        except lib_exc.NotFound:
+            return True
+        return False
+
+    @property
+    def resource_type(self):
+        """Return the primary type of resource this client works with."""
+        return 'snapshot'
diff --git a/tempest/lib/services/compute/tenant_networks_client.py b/tempest/lib/services/compute/tenant_networks_client.py
new file mode 100644
index 0000000..44a97a9
--- /dev/null
+++ b/tempest/lib/services/compute/tenant_networks_client.py
@@ -0,0 +1,34 @@
+# 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.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.api_schema.response.compute.v2_1 import tenant_networks
+from tempest.lib.common import rest_client
+
+
+class TenantNetworksClient(rest_client.RestClient):
+
+    def list_tenant_networks(self):
+        resp, body = self.get("os-tenant-networks")
+        body = json.loads(body)
+        self.validate_response(tenant_networks.list_tenant_networks, resp,
+                               body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_tenant_network(self, network_id):
+        resp, body = self.get("os-tenant-networks/%s" % network_id)
+        body = json.loads(body)
+        self.validate_response(tenant_networks.get_tenant_network, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/tenant_usages_client.py b/tempest/lib/services/compute/tenant_usages_client.py
new file mode 100644
index 0000000..e8da465
--- /dev/null
+++ b/tempest/lib/services/compute/tenant_usages_client.py
@@ -0,0 +1,43 @@
+# Copyright 2013 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 oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
+
+from tempest.lib.api_schema.response.compute.v2_1 import tenant_usages
+from tempest.lib.common import rest_client
+
+
+class TenantUsagesClient(rest_client.RestClient):
+
+    def list_tenant_usages(self, **params):
+        url = 'os-simple-tenant-usage'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(tenant_usages.list_tenant_usage, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_tenant_usage(self, tenant_id, **params):
+        url = 'os-simple-tenant-usage/%s' % tenant_id
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(tenant_usages.get_tenant_usage, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/versions_client.py b/tempest/lib/services/compute/versions_client.py
new file mode 100644
index 0000000..ed82c74
--- /dev/null
+++ b/tempest/lib/services/compute/versions_client.py
@@ -0,0 +1,60 @@
+# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
+#
+# 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 re
+
+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
+
+
+class VersionsClient(rest_client.RestClient):
+
+    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()
+        resp, body = self.raw_request(version_url, 'GET')
+        body = json.loads(body)
+        self.validate_response(schema.list_versions, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def get_version_by_url(self, version_url):
+        """Get the version document by url.
+
+        This gets the version document for a url, useful in testing
+        the contents of things like /v2/ or /v2.1/ in Nova. That
+        controller needs authenticated access, so we have to get
+        ourselves a token before making the request.
+
+        """
+        # we need a token for this request
+        resp, body = self.raw_request(version_url, 'GET',
+                                      {'X-Auth-Token': self.token})
+        body = json.loads(body)
+        self.validate_response(schema.get_one_version, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/volumes_client.py b/tempest/lib/services/compute/volumes_client.py
new file mode 100644
index 0000000..45a44de
--- /dev/null
+++ b/tempest/lib/services/compute/volumes_client.py
@@ -0,0 +1,76 @@
+# 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.api_schema.response.compute.v2_1 import volumes as schema
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
+
+
+class VolumesClient(rest_client.RestClient):
+
+    def list_volumes(self, detail=False, **params):
+        """List all the volumes created."""
+        url = 'os-volumes'
+
+        if detail:
+            url += '/detail'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.list_volumes, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_volume(self, volume_id):
+        """Return the details of a single volume."""
+        url = "os-volumes/%s" % volume_id
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(schema.create_get_volume, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_volume(self, **kwargs):
+        """Create a new Volume.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#createVolume
+        """
+        post_body = json.dumps({'volume': kwargs})
+        resp, body = self.post('os-volumes', post_body)
+        body = json.loads(body)
+        self.validate_response(schema.create_get_volume, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_volume(self, volume_id):
+        """Delete the Specified Volume."""
+        resp, body = self.delete("os-volumes/%s" % volume_id)
+        self.validate_response(schema.delete_volume, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def is_resource_deleted(self, id):
+        try:
+            self.show_volume(id)
+        except lib_exc.NotFound:
+            return True
+        return False
+
+    @property
+    def resource_type(self):
+        """Return the primary type of resource this client works with."""
+        return 'volume'
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/services/identity/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/services/identity/__init__.py
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/services/identity/v2/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/services/identity/v2/__init__.py
diff --git a/tempest/lib/services/identity/v2/token_client.py b/tempest/lib/services/identity/v2/token_client.py
new file mode 100644
index 0000000..0350175
--- /dev/null
+++ b/tempest/lib/services/identity/v2/token_client.py
@@ -0,0 +1,121 @@
+# 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.
+
+from oslo_log import log as logging
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions
+
+
+class TokenClient(rest_client.RestClient):
+
+    def __init__(self, auth_url, disable_ssl_certificate_validation=None,
+                 ca_certs=None, trace_requests=None):
+        dscv = disable_ssl_certificate_validation
+        super(TokenClient, self).__init__(
+            None, None, None, disable_ssl_certificate_validation=dscv,
+            ca_certs=ca_certs, trace_requests=trace_requests)
+
+        if auth_url is None:
+            raise exceptions.IdentityError("Couldn't determine auth_url")
+
+        # Normalize URI to ensure /tokens is in it.
+        if 'tokens' not in auth_url:
+            auth_url = auth_url.rstrip('/') + '/tokens'
+
+        self.auth_url = auth_url
+
+    def auth(self, user, password, tenant=None):
+        creds = {
+            'auth': {
+                'passwordCredentials': {
+                    'username': user,
+                    'password': password,
+                },
+            }
+        }
+
+        if tenant:
+            creds['auth']['tenantName'] = tenant
+
+        body = json.dumps(creds, sort_keys=True)
+        resp, body = self.post(self.auth_url, body=body)
+        self.expected_success(200, resp.status)
+
+        return rest_client.ResponseBody(resp, body['access'])
+
+    def auth_token(self, token_id, tenant=None):
+        creds = {
+            'auth': {
+                'token': {
+                    'id': token_id,
+                },
+            }
+        }
+
+        if tenant:
+            creds['auth']['tenantName'] = tenant
+
+        body = json.dumps(creds)
+        resp, body = self.post(self.auth_url, body=body)
+        self.expected_success(200, resp.status)
+
+        return rest_client.ResponseBody(resp, body['access'])
+
+    def request(self, method, url, extra_headers=False, headers=None,
+                body=None):
+        """A simple HTTP request interface."""
+        if headers is None:
+            headers = self.get_headers(accept_type="json")
+        elif extra_headers:
+            try:
+                headers.update(self.get_headers(accept_type="json"))
+            except (ValueError, TypeError):
+                headers = self.get_headers(accept_type="json")
+
+        resp, resp_body = self.raw_request(url, method,
+                                           headers=headers, body=body)
+        self._log_request(method, url, resp, req_headers=headers,
+                          req_body='<omitted>', resp_body=resp_body)
+
+        if resp.status in [401, 403]:
+            resp_body = json.loads(resp_body)
+            raise exceptions.Unauthorized(resp_body['error']['message'])
+        elif resp.status not in [200, 201]:
+            raise exceptions.IdentityError(
+                'Unexpected status code {0}'.format(resp.status))
+
+        return resp, json.loads(resp_body)
+
+    def get_token(self, user, password, tenant, auth_data=False):
+        """Returns (token id, token data) for supplied credentials."""
+        body = self.auth(user, password, tenant)
+
+        if auth_data:
+            return body['token']['id'], body
+        else:
+            return body['token']['id']
+
+
+class TokenClientJSON(TokenClient):
+    LOG = logging.getLogger(__name__)
+
+    def _warn(self):
+        self.LOG.warning("%s class was deprecated and renamed to %s" %
+                         (self.__class__.__name__, 'TokenClient'))
+
+    def __init__(self, *args, **kwargs):
+        self._warn()
+        super(TokenClientJSON, self).__init__(*args, **kwargs)
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/services/identity/v3/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/services/identity/v3/__init__.py
diff --git a/tempest/lib/services/identity/v3/token_client.py b/tempest/lib/services/identity/v3/token_client.py
new file mode 100644
index 0000000..f342a49
--- /dev/null
+++ b/tempest/lib/services/identity/v3/token_client.py
@@ -0,0 +1,183 @@
+# 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.
+
+from oslo_log import log as logging
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions
+
+
+class V3TokenClient(rest_client.RestClient):
+
+    def __init__(self, auth_url, disable_ssl_certificate_validation=None,
+                 ca_certs=None, trace_requests=None):
+        dscv = disable_ssl_certificate_validation
+        super(V3TokenClient, self).__init__(
+            None, None, None, disable_ssl_certificate_validation=dscv,
+            ca_certs=ca_certs, trace_requests=trace_requests)
+
+        if auth_url is None:
+            raise exceptions.IdentityError("Couldn't determine auth_url")
+
+        if 'auth/tokens' not in auth_url:
+            auth_url = auth_url.rstrip('/') + '/auth/tokens'
+
+        self.auth_url = auth_url
+
+    def auth(self, user_id=None, username=None, password=None, project_id=None,
+             project_name=None, user_domain_id=None, user_domain_name=None,
+             project_domain_id=None, project_domain_name=None, domain_id=None,
+             domain_name=None, token=None):
+        """Obtains a token from the authentication service
+
+        :param user_id: user id
+        :param username: user name
+        :param user_domain_id: the user domain id
+        :param user_domain_name: the user domain name
+        :param project_domain_id: the project domain id
+        :param project_domain_name: the project domain name
+        :param domain_id: a domain id to scope to
+        :param domain_name: a domain name to scope to
+        :param project_id: a project id to scope to
+        :param project_name: a project name to scope to
+        :param token: a token to re-scope.
+
+        Accepts different combinations of credentials.
+        Sample sample valid combinations:
+        - token
+        - token, project_name, project_domain_id
+        - user_id, password
+        - username, password, user_domain_id
+        - username, password, project_name, user_domain_id, project_domain_id
+        Validation is left to the server side.
+        """
+        creds = {
+            'auth': {
+                'identity': {
+                    'methods': [],
+                }
+            }
+        }
+        id_obj = creds['auth']['identity']
+        if token:
+            id_obj['methods'].append('token')
+            id_obj['token'] = {
+                'id': token
+            }
+
+        if (user_id or username) and password:
+            id_obj['methods'].append('password')
+            id_obj['password'] = {
+                'user': {
+                    'password': password,
+                }
+            }
+            if user_id:
+                id_obj['password']['user']['id'] = user_id
+            else:
+                id_obj['password']['user']['name'] = username
+
+            _domain = None
+            if user_domain_id is not None:
+                _domain = dict(id=user_domain_id)
+            elif user_domain_name is not None:
+                _domain = dict(name=user_domain_name)
+            if _domain:
+                id_obj['password']['user']['domain'] = _domain
+
+        if (project_id or project_name):
+            _project = dict()
+
+            if project_id:
+                _project['id'] = project_id
+            elif project_name:
+                _project['name'] = project_name
+
+            if project_domain_id is not None:
+                _project['domain'] = {'id': project_domain_id}
+            elif project_domain_name is not None:
+                _project['domain'] = {'name': project_domain_name}
+
+            creds['auth']['scope'] = dict(project=_project)
+        elif domain_id:
+            creds['auth']['scope'] = dict(domain={'id': domain_id})
+        elif domain_name:
+            creds['auth']['scope'] = dict(domain={'name': domain_name})
+
+        body = json.dumps(creds, sort_keys=True)
+        resp, body = self.post(self.auth_url, body=body)
+        self.expected_success(201, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def request(self, method, url, extra_headers=False, headers=None,
+                body=None):
+        """A simple HTTP request interface."""
+        if headers is None:
+            # Always accept 'json', for xml token client too.
+            # Because XML response is not easily
+            # converted to the corresponding JSON one
+            headers = self.get_headers(accept_type="json")
+        elif extra_headers:
+            try:
+                headers.update(self.get_headers(accept_type="json"))
+            except (ValueError, TypeError):
+                headers = self.get_headers(accept_type="json")
+
+        resp, resp_body = self.raw_request(url, method,
+                                           headers=headers, body=body)
+        self._log_request(method, url, resp, req_headers=headers,
+                          req_body='<omitted>', resp_body=resp_body)
+
+        if resp.status in [401, 403]:
+            resp_body = json.loads(resp_body)
+            raise exceptions.Unauthorized(resp_body['error']['message'])
+        elif resp.status not in [200, 201, 204]:
+            raise exceptions.IdentityError(
+                'Unexpected status code {0}'.format(resp.status))
+
+        return resp, json.loads(resp_body)
+
+    def get_token(self, **kwargs):
+        """Returns (token id, token data) for supplied credentials"""
+
+        auth_data = kwargs.pop('auth_data', False)
+
+        if not (kwargs.get('user_domain_id') or
+                kwargs.get('user_domain_name')):
+            kwargs['user_domain_name'] = 'Default'
+
+        if not (kwargs.get('project_domain_id') or
+                kwargs.get('project_domain_name')):
+            kwargs['project_domain_name'] = 'Default'
+
+        body = self.auth(**kwargs)
+
+        token = body.response.get('x-subject-token')
+        if auth_data:
+            return token, body['token']
+        else:
+            return token
+
+
+class V3TokenClientJSON(V3TokenClient):
+    LOG = logging.getLogger(__name__)
+
+    def _warn(self):
+        self.LOG.warning("%s class was deprecated and renamed to %s" %
+                         (self.__class__.__name__, 'V3TokenClient'))
+
+    def __init__(self, *args, **kwargs):
+        self._warn()
+        super(V3TokenClientJSON, self).__init__(*args, **kwargs)
diff --git a/tempest/api/messaging/__init__.py b/tempest/lib/services/network/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/lib/services/network/__init__.py
diff --git a/tempest/lib/services/network/agents_client.py b/tempest/lib/services/network/agents_client.py
new file mode 100644
index 0000000..c5d4c66
--- /dev/null
+++ b/tempest/lib/services/network/agents_client.py
@@ -0,0 +1,68 @@
+# 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.
+
+from tempest.lib.services.network import base
+
+
+class AgentsClient(base.BaseNetworkClient):
+
+    def update_agent(self, agent_id, **kwargs):
+        """Update agent."""
+        # TODO(piyush): 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.
+        # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1526673
+        uri = '/agents/%s' % agent_id
+        return self.update_resource(uri, kwargs)
+
+    def show_agent(self, agent_id, **fields):
+        uri = '/agents/%s' % agent_id
+        return self.show_resource(uri, **fields)
+
+    def list_agents(self, **filters):
+        uri = '/agents'
+        return self.list_resources(uri, **filters)
+
+    def list_routers_on_l3_agent(self, agent_id):
+        uri = '/agents/%s/l3-routers' % agent_id
+        return self.list_resources(uri)
+
+    def create_router_on_l3_agent(self, agent_id, **kwargs):
+        # TODO(piyush): 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.
+        # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1526670
+        uri = '/agents/%s/l3-routers' % agent_id
+        return self.create_resource(uri, kwargs)
+
+    def delete_router_from_l3_agent(self, agent_id, router_id):
+        uri = '/agents/%s/l3-routers/%s' % (agent_id, router_id)
+        return self.delete_resource(uri)
+
+    def list_networks_hosted_by_one_dhcp_agent(self, agent_id):
+        uri = '/agents/%s/dhcp-networks' % agent_id
+        return self.list_resources(uri)
+
+    def delete_network_from_dhcp_agent(self, agent_id, network_id):
+        uri = '/agents/%s/dhcp-networks/%s' % (agent_id,
+                                               network_id)
+        return self.delete_resource(uri)
+
+    def add_dhcp_agent_to_network(self, agent_id, **kwargs):
+        # TODO(piyush): 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.
+        # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1526212
+        uri = '/agents/%s/dhcp-networks' % agent_id
+        return self.create_resource(uri, kwargs)
diff --git a/tempest/services/network/json/base.py b/tempest/lib/services/network/base.py
similarity index 85%
rename from tempest/services/network/json/base.py
rename to tempest/lib/services/network/base.py
index 6ebc245..a6ada04 100644
--- a/tempest/services/network/json/base.py
+++ b/tempest/lib/services/network/base.py
@@ -13,10 +13,10 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class BaseNetworkClient(service_client.ServiceClient):
+class BaseNetworkClient(rest_client.RestClient):
 
     """Base class for Tempest REST clients for Neutron.
 
@@ -34,13 +34,13 @@
         resp, body = self.get(req_uri)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_resource(self, uri):
         req_uri = self.uri_prefix + uri
         resp, body = self.delete(req_uri)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_resource(self, uri, **fields):
         # fields is a dict which key is 'fields' and value is a
@@ -52,7 +52,7 @@
         resp, body = self.get(req_uri)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_resource(self, uri, post_data):
         req_uri = self.uri_prefix + uri
@@ -60,7 +60,7 @@
         resp, body = self.post(req_uri, req_post_data)
         body = json.loads(body)
         self.expected_success(201, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_resource(self, uri, post_data):
         req_uri = self.uri_prefix + uri
@@ -68,4 +68,4 @@
         resp, body = self.put(req_uri, req_post_data)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/network/extensions_client.py b/tempest/lib/services/network/extensions_client.py
new file mode 100644
index 0000000..3910c84
--- /dev/null
+++ b/tempest/lib/services/network/extensions_client.py
@@ -0,0 +1,24 @@
+#    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.network import base
+
+
+class ExtensionsClient(base.BaseNetworkClient):
+
+    def show_extension(self, ext_alias, **fields):
+        uri = '/extensions/%s' % ext_alias
+        return self.show_resource(uri, **fields)
+
+    def list_extensions(self, **filters):
+        uri = '/extensions'
+        return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/floating_ips_client.py b/tempest/lib/services/network/floating_ips_client.py
new file mode 100644
index 0000000..1968e05
--- /dev/null
+++ b/tempest/lib/services/network/floating_ips_client.py
@@ -0,0 +1,38 @@
+#    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.network import base
+
+
+class FloatingIPsClient(base.BaseNetworkClient):
+
+    def create_floatingip(self, **kwargs):
+        uri = '/floatingips'
+        post_data = {'floatingip': kwargs}
+        return self.create_resource(uri, post_data)
+
+    def update_floatingip(self, floatingip_id, **kwargs):
+        uri = '/floatingips/%s' % floatingip_id
+        post_data = {'floatingip': kwargs}
+        return self.update_resource(uri, post_data)
+
+    def show_floatingip(self, floatingip_id, **fields):
+        uri = '/floatingips/%s' % floatingip_id
+        return self.show_resource(uri, **fields)
+
+    def delete_floatingip(self, floatingip_id):
+        uri = '/floatingips/%s' % floatingip_id
+        return self.delete_resource(uri)
+
+    def list_floatingips(self, **filters):
+        uri = '/floatingips'
+        return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/metering_label_rules_client.py b/tempest/lib/services/network/metering_label_rules_client.py
new file mode 100644
index 0000000..36cf8e3
--- /dev/null
+++ b/tempest/lib/services/network/metering_label_rules_client.py
@@ -0,0 +1,33 @@
+#    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.network import base
+
+
+class MeteringLabelRulesClient(base.BaseNetworkClient):
+
+    def create_metering_label_rule(self, **kwargs):
+        uri = '/metering/metering-label-rules'
+        post_data = {'metering_label_rule': kwargs}
+        return self.create_resource(uri, post_data)
+
+    def show_metering_label_rule(self, metering_label_rule_id, **fields):
+        uri = '/metering/metering-label-rules/%s' % metering_label_rule_id
+        return self.show_resource(uri, **fields)
+
+    def delete_metering_label_rule(self, metering_label_rule_id):
+        uri = '/metering/metering-label-rules/%s' % metering_label_rule_id
+        return self.delete_resource(uri)
+
+    def list_metering_label_rules(self, **filters):
+        uri = '/metering/metering-label-rules'
+        return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/metering_labels_client.py b/tempest/lib/services/network/metering_labels_client.py
new file mode 100644
index 0000000..2350ecd
--- /dev/null
+++ b/tempest/lib/services/network/metering_labels_client.py
@@ -0,0 +1,33 @@
+#    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.network import base
+
+
+class MeteringLabelsClient(base.BaseNetworkClient):
+
+    def create_metering_label(self, **kwargs):
+        uri = '/metering/metering-labels'
+        post_data = {'metering_label': kwargs}
+        return self.create_resource(uri, post_data)
+
+    def show_metering_label(self, metering_label_id, **fields):
+        uri = '/metering/metering-labels/%s' % metering_label_id
+        return self.show_resource(uri, **fields)
+
+    def delete_metering_label(self, metering_label_id):
+        uri = '/metering/metering-labels/%s' % metering_label_id
+        return self.delete_resource(uri)
+
+    def list_metering_labels(self, **filters):
+        uri = '/metering/metering-labels'
+        return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/networks_client.py b/tempest/lib/services/network/networks_client.py
new file mode 100644
index 0000000..0926634
--- /dev/null
+++ b/tempest/lib/services/network/networks_client.py
@@ -0,0 +1,47 @@
+#    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.network import base
+
+
+class NetworksClient(base.BaseNetworkClient):
+
+    def create_network(self, **kwargs):
+        uri = '/networks'
+        post_data = {'network': kwargs}
+        return self.create_resource(uri, post_data)
+
+    def update_network(self, network_id, **kwargs):
+        uri = '/networks/%s' % network_id
+        post_data = {'network': kwargs}
+        return self.update_resource(uri, post_data)
+
+    def show_network(self, network_id, **fields):
+        uri = '/networks/%s' % network_id
+        return self.show_resource(uri, **fields)
+
+    def delete_network(self, network_id):
+        uri = '/networks/%s' % network_id
+        return self.delete_resource(uri)
+
+    def list_networks(self, **filters):
+        uri = '/networks'
+        return self.list_resources(uri, **filters)
+
+    def create_bulk_networks(self, **kwargs):
+        """Create multiple networks in a single request.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-networking-v2.html#bulkCreateNetwork
+        """
+        uri = '/networks'
+        return self.create_resource(uri, kwargs)
diff --git a/tempest/lib/services/network/ports_client.py b/tempest/lib/services/network/ports_client.py
new file mode 100644
index 0000000..1793d6a
--- /dev/null
+++ b/tempest/lib/services/network/ports_client.py
@@ -0,0 +1,47 @@
+#    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.network import base
+
+
+class PortsClient(base.BaseNetworkClient):
+
+    def create_port(self, **kwargs):
+        uri = '/ports'
+        post_data = {'port': kwargs}
+        return self.create_resource(uri, post_data)
+
+    def update_port(self, port_id, **kwargs):
+        uri = '/ports/%s' % port_id
+        post_data = {'port': kwargs}
+        return self.update_resource(uri, post_data)
+
+    def show_port(self, port_id, **fields):
+        uri = '/ports/%s' % port_id
+        return self.show_resource(uri, **fields)
+
+    def delete_port(self, port_id):
+        uri = '/ports/%s' % port_id
+        return self.delete_resource(uri)
+
+    def list_ports(self, **filters):
+        uri = '/ports'
+        return self.list_resources(uri, **filters)
+
+    def create_bulk_ports(self, **kwargs):
+        """Create multiple ports in a single request.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-networking-v2.html#bulkCreatePorts
+        """
+        uri = '/ports'
+        return self.create_resource(uri, kwargs)
diff --git a/tempest/lib/services/network/quotas_client.py b/tempest/lib/services/network/quotas_client.py
new file mode 100644
index 0000000..b5cf35b
--- /dev/null
+++ b/tempest/lib/services/network/quotas_client.py
@@ -0,0 +1,35 @@
+# 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.
+
+from tempest.lib.services.network import base
+
+
+class QuotasClient(base.BaseNetworkClient):
+
+    def update_quotas(self, tenant_id, **kwargs):
+        put_body = {'quota': kwargs}
+        uri = '/quotas/%s' % tenant_id
+        return self.update_resource(uri, put_body)
+
+    def reset_quotas(self, tenant_id):
+        uri = '/quotas/%s' % tenant_id
+        return self.delete_resource(uri)
+
+    def show_quotas(self, tenant_id, **fields):
+        uri = '/quotas/%s' % tenant_id
+        return self.show_resource(uri, **fields)
+
+    def list_quotas(self, **filters):
+        uri = '/quotas'
+        return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/security_group_rules_client.py b/tempest/lib/services/network/security_group_rules_client.py
new file mode 100644
index 0000000..944eba6
--- /dev/null
+++ b/tempest/lib/services/network/security_group_rules_client.py
@@ -0,0 +1,33 @@
+#    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.network import base
+
+
+class SecurityGroupRulesClient(base.BaseNetworkClient):
+
+    def create_security_group_rule(self, **kwargs):
+        uri = '/security-group-rules'
+        post_data = {'security_group_rule': kwargs}
+        return self.create_resource(uri, post_data)
+
+    def show_security_group_rule(self, security_group_rule_id, **fields):
+        uri = '/security-group-rules/%s' % security_group_rule_id
+        return self.show_resource(uri, **fields)
+
+    def delete_security_group_rule(self, security_group_rule_id):
+        uri = '/security-group-rules/%s' % security_group_rule_id
+        return self.delete_resource(uri)
+
+    def list_security_group_rules(self, **filters):
+        uri = '/security-group-rules'
+        return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/security_groups_client.py b/tempest/lib/services/network/security_groups_client.py
new file mode 100644
index 0000000..0e25339
--- /dev/null
+++ b/tempest/lib/services/network/security_groups_client.py
@@ -0,0 +1,38 @@
+#    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.network import base
+
+
+class SecurityGroupsClient(base.BaseNetworkClient):
+
+    def create_security_group(self, **kwargs):
+        uri = '/security-groups'
+        post_data = {'security_group': kwargs}
+        return self.create_resource(uri, post_data)
+
+    def update_security_group(self, security_group_id, **kwargs):
+        uri = '/security-groups/%s' % security_group_id
+        post_data = {'security_group': kwargs}
+        return self.update_resource(uri, post_data)
+
+    def show_security_group(self, security_group_id, **fields):
+        uri = '/security-groups/%s' % security_group_id
+        return self.show_resource(uri, **fields)
+
+    def delete_security_group(self, security_group_id):
+        uri = '/security-groups/%s' % security_group_id
+        return self.delete_resource(uri)
+
+    def list_security_groups(self, **filters):
+        uri = '/security-groups'
+        return self.list_resources(uri, **filters)
diff --git a/tempest/services/network/json/subnetpools_client.py b/tempest/lib/services/network/subnetpools_client.py
similarity index 96%
rename from tempest/services/network/json/subnetpools_client.py
rename to tempest/lib/services/network/subnetpools_client.py
index f921bb0..12349b1 100644
--- a/tempest/services/network/json/subnetpools_client.py
+++ b/tempest/lib/services/network/subnetpools_client.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.services.network.json import base
+from tempest.lib.services.network import base
 
 
 class SubnetpoolsClient(base.BaseNetworkClient):
diff --git a/tempest/lib/services/network/subnets_client.py b/tempest/lib/services/network/subnets_client.py
new file mode 100644
index 0000000..63ed13e
--- /dev/null
+++ b/tempest/lib/services/network/subnets_client.py
@@ -0,0 +1,47 @@
+#    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.network import base
+
+
+class SubnetsClient(base.BaseNetworkClient):
+
+    def create_subnet(self, **kwargs):
+        uri = '/subnets'
+        post_data = {'subnet': kwargs}
+        return self.create_resource(uri, post_data)
+
+    def update_subnet(self, subnet_id, **kwargs):
+        uri = '/subnets/%s' % subnet_id
+        post_data = {'subnet': kwargs}
+        return self.update_resource(uri, post_data)
+
+    def show_subnet(self, subnet_id, **fields):
+        uri = '/subnets/%s' % subnet_id
+        return self.show_resource(uri, **fields)
+
+    def delete_subnet(self, subnet_id):
+        uri = '/subnets/%s' % subnet_id
+        return self.delete_resource(uri)
+
+    def list_subnets(self, **filters):
+        uri = '/subnets'
+        return self.list_resources(uri, **filters)
+
+    def create_bulk_subnets(self, **kwargs):
+        """Create multiple subnets in a single request.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-networking-v2.html#bulkCreateSubnet
+        """
+        uri = '/subnets'
+        return self.create_resource(uri, kwargs)
diff --git a/tempest/manager.py b/tempest/manager.py
index 9904aa6..c97e0d1 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -13,11 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest_lib import auth
-
 from tempest.common import cred_provider
 from tempest import config
 from tempest import exceptions
+from tempest.lib import auth
 
 CONF = config.CONF
 
@@ -50,8 +49,6 @@
             creds = self.credentials
         # Creates an auth provider for the credentials
         self.auth_provider = get_auth_provider(creds, pre_auth=True)
-        # FIXME(andreaf) unused
-        self.client_attr_names = []
 
 
 def get_auth_provider_class(credentials):
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 1962286..0c16056 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -20,8 +20,6 @@
 from oslo_log import log
 from oslo_serialization import jsonutils as json
 import six
-from tempest_lib.common.utils import misc as misc_utils
-from tempest_lib import exceptions as lib_exc
 
 from tempest.common import compute
 from tempest.common.utils import data_utils
@@ -29,6 +27,8 @@
 from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
+from tempest.lib.common.utils import misc as misc_utils
+from tempest.lib import exceptions as lib_exc
 from tempest.services.network import resources as net_resources
 import tempest.test
 
@@ -66,6 +66,7 @@
         cls.network_client = cls.manager.network_client
         cls.networks_client = cls.manager.networks_client
         cls.ports_client = cls.manager.ports_client
+        cls.routers_client = cls.manager.routers_client
         cls.subnets_client = cls.manager.subnets_client
         cls.floating_ips_client = cls.manager.floating_ips_client
         cls.security_groups_client = cls.manager.security_groups_client
@@ -690,17 +691,21 @@
         cls.tenant_id = cls.manager.identity_client.tenant_id
 
     def _create_network(self, client=None, networks_client=None,
-                        tenant_id=None, namestart='network-smoke-'):
+                        routers_client=None, tenant_id=None,
+                        namestart='network-smoke-'):
         if not client:
             client = self.network_client
         if not networks_client:
             networks_client = self.networks_client
+        if not routers_client:
+            routers_client = self.routers_client
         if not tenant_id:
             tenant_id = client.tenant_id
         name = data_utils.rand_name(namestart)
         result = networks_client.create_network(name=name, tenant_id=tenant_id)
         network = net_resources.DeletableNetwork(
-            networks_client=networks_client, **result['network'])
+            networks_client=networks_client, routers_client=routers_client,
+            **result['network'])
         self.assertEqual(network.name, name)
         self.addCleanup(self.delete_wrapper, network.delete)
         return network
@@ -719,7 +724,7 @@
 
     def _list_routers(self, *args, **kwargs):
         """List routers using admin creds """
-        routers_list = self.admin_manager.network_client.list_routers(
+        routers_list = self.admin_manager.routers_client.list_routers(
             *args, **kwargs)
         return routers_list['routers']
 
@@ -736,7 +741,8 @@
         return agents_list['agents']
 
     def _create_subnet(self, network, client=None, subnets_client=None,
-                       namestart='subnet-smoke', **kwargs):
+                       routers_client=None, namestart='subnet-smoke',
+                       **kwargs):
         """Create a subnet for the given network
 
         within the cidr block configured for tenant networks.
@@ -745,6 +751,8 @@
             client = self.network_client
         if not subnets_client:
             subnets_client = self.subnets_client
+        if not routers_client:
+            routers_client = self.routers_client
 
         def cidr_in_use(cidr, tenant_id):
             """Check cidr existence
@@ -792,7 +800,7 @@
         self.assertIsNotNone(result, 'Unable to allocate tenant network')
         subnet = net_resources.DeletableSubnet(
             network_client=client, subnets_client=subnets_client,
-            **result['subnet'])
+            routers_client=routers_client, **result['subnet'])
         self.assertEqual(subnet.cidr, str_cidr)
         self.addCleanup(self.delete_wrapper, subnet.delete)
         return subnet
@@ -813,15 +821,18 @@
         return port
 
     def _get_server_port_id_and_ip4(self, server, ip_addr=None):
-        ports = self._list_ports(device_id=server['id'], status='ACTIVE',
-                                 fixed_ip=ip_addr)
+        ports = self._list_ports(device_id=server['id'], fixed_ip=ip_addr)
         # A port can have more then one IP address in some cases.
         # If the network is dual-stack (IPv4 + IPv6), this port is associated
         # with 2 subnets
         port_map = [(p["id"], fxip["ip_address"])
                     for p in ports
                     for fxip in p["fixed_ips"]
-                    if netaddr.valid_ipv4(fxip["ip_address"])]
+                    if netaddr.valid_ipv4(fxip["ip_address"])
+                    and p['status'] == 'ACTIVE']
+        inactive = [p for p in ports if p['status'] != 'ACTIVE']
+        if inactive:
+            LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
 
         self.assertNotEqual(0, len(port_map),
                             "No IPv4 addresses found in: %s" % ports)
@@ -989,7 +1000,7 @@
         sg_dict['tenant_id'] = tenant_id
         result = client.create_security_group(**sg_dict)
         secgroup = net_resources.DeletableSecurityGroup(
-            client=client,
+            client=client, routers_client=self.routers_client,
             **result['security_group']
         )
         self.assertEqual(secgroup.name, sg_name)
@@ -1125,7 +1136,7 @@
         routes traffic to the public network.
         """
         if not client:
-            client = self.network_client
+            client = self.routers_client
         if not tenant_id:
             tenant_id = client.tenant_id
         router_id = CONF.network.public_router_id
@@ -1144,14 +1155,14 @@
     def _create_router(self, client=None, tenant_id=None,
                        namestart='router-smoke'):
         if not client:
-            client = self.network_client
+            client = self.routers_client
         if not tenant_id:
             tenant_id = client.tenant_id
         name = data_utils.rand_name(namestart)
         result = client.create_router(name=name,
                                       admin_state_up=True,
                                       tenant_id=tenant_id)
-        router = net_resources.DeletableRouter(client=client,
+        router = net_resources.DeletableRouter(routers_client=client,
                                                **result['router'])
         self.assertEqual(router.name, name)
         self.addCleanup(self.delete_wrapper, router.delete)
@@ -1162,8 +1173,8 @@
         self.assertEqual(admin_state_up, router.admin_state_up)
 
     def create_networks(self, client=None, networks_client=None,
-                        subnets_client=None, tenant_id=None,
-                        dns_nameservers=None):
+                        routers_client=None, subnets_client=None,
+                        tenant_id=None, dns_nameservers=None):
         """Create a network with a subnet connected to a router.
 
         The baremetal driver is a special case since all nodes are
@@ -1191,10 +1202,12 @@
             network = self._create_network(
                 client=client, networks_client=networks_client,
                 tenant_id=tenant_id)
-            router = self._get_router(client=client, tenant_id=tenant_id)
+            router = self._get_router(client=routers_client,
+                                      tenant_id=tenant_id)
 
             subnet_kwargs = dict(network=network, client=client,
-                                 subnets_client=subnets_client)
+                                 subnets_client=subnets_client,
+                                 routers_client=routers_client)
             # use explicit check because empty list is a valid option
             if dns_nameservers is not None:
                 subnet_kwargs['dns_nameservers'] = dns_nameservers
diff --git a/tempest/scenario/test_baremetal_basic_ops.py b/tempest/scenario/test_baremetal_basic_ops.py
index 15d9b66..655d19d 100644
--- a/tempest/scenario/test_baremetal_basic_ops.py
+++ b/tempest/scenario/test_baremetal_basic_ops.py
@@ -15,7 +15,6 @@
 
 from oslo_log import log as logging
 
-from tempest.common import waiters
 from tempest import config
 from tempest.scenario import manager
 from tempest import test
@@ -37,32 +36,10 @@
         * Verifies SSH connectivity using created keypair via fixed IP
         * Associates a floating ip
         * Verifies SSH connectivity using created keypair via floating IP
-        * Verifies instance rebuild with ephemeral partition preservation
         * Deletes instance
         * Monitors the associated Ironic node for power and
           expected state transitions
     """
-    def rebuild_instance(self, preserve_ephemeral=False):
-        self.rebuild_server(server_id=self.instance['id'],
-                            preserve_ephemeral=preserve_ephemeral,
-                            wait=False)
-
-        node = self.get_node(instance_id=self.instance['id'])
-
-        # We should remain on the same node
-        self.assertEqual(self.node['uuid'], node['uuid'])
-        self.node = node
-
-        waiters.wait_for_server_status(
-            self.servers_client,
-            server_id=self.instance['id'],
-            status='REBUILD',
-            ready_wait=False)
-        waiters.wait_for_server_status(
-            self.servers_client,
-            server_id=self.instance['id'],
-            status='ACTIVE')
-
     def verify_partition(self, client, label, mount, gib_size):
         """Verify a labeled partition's mount point and size."""
         LOG.info("Looking for partition %s mounted on %s" % (label, mount))
diff --git a/tempest/scenario/test_large_ops.py b/tempest/scenario/test_large_ops.py
deleted file mode 100644
index 402077f..0000000
--- a/tempest/scenario/test_large_ops.py
+++ /dev/null
@@ -1,134 +0,0 @@
-# Copyright 2013 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 import exceptions as lib_exc
-
-from tempest.common import fixed_network
-from tempest.common.utils import data_utils
-from tempest.common import waiters
-from tempest import config
-from tempest.scenario import manager
-from tempest import test
-
-CONF = config.CONF
-
-
-class TestLargeOpsScenario(manager.ScenarioTest):
-
-    """Test large operations.
-
-    This test below:
-    * Spin up multiple instances in one nova call, and repeat three times
-    * as a regular user
-    * TODO: same thing for cinder
-
-    """
-
-    @classmethod
-    def skip_checks(cls):
-        super(TestLargeOpsScenario, cls).skip_checks()
-        if CONF.scenario.large_ops_number < 1:
-            raise cls.skipException("large_ops_number not set to multiple "
-                                    "instances")
-
-    @classmethod
-    def setup_credentials(cls):
-        cls.set_network_resources()
-        super(TestLargeOpsScenario, cls).setup_credentials()
-
-    @classmethod
-    def resource_setup(cls):
-        super(TestLargeOpsScenario, cls).resource_setup()
-        # list of cleanup calls to be executed in reverse order
-        cls._cleanup_resources = []
-
-    @classmethod
-    def resource_cleanup(cls):
-        while cls._cleanup_resources:
-            function, args, kwargs = cls._cleanup_resources.pop(-1)
-            try:
-                function(*args, **kwargs)
-            except lib_exc.NotFound:
-                pass
-        super(TestLargeOpsScenario, cls).resource_cleanup()
-
-    @classmethod
-    def addCleanupClass(cls, function, *arguments, **keywordArguments):
-        cls._cleanup_resources.append((function, arguments, keywordArguments))
-
-    def _wait_for_server_status(self, status):
-        for server in self.servers:
-            # Make sure nova list keeps working throughout the build process
-            self.servers_client.list_servers()
-            waiters.wait_for_server_status(self.servers_client,
-                                           server['id'], status)
-
-    def nova_boot(self, image):
-        name = data_utils.rand_name('scenario-server')
-        flavor_id = CONF.compute.flavor_ref
-        # Explicitly create secgroup to avoid cleanup at the end of testcases.
-        # Since no traffic is tested, we don't need to actually add rules to
-        # secgroup
-        secgroup = self.compute_security_groups_client.create_security_group(
-            name='secgroup-%s' % name,
-            description='secgroup-desc-%s' % name)['security_group']
-        self.addCleanupClass(
-            self.compute_security_groups_client.delete_security_group,
-            secgroup['id'])
-        create_kwargs = {
-            'min_count': CONF.scenario.large_ops_number,
-            'security_groups': [{'name': secgroup['name']}]
-            }
-        network = self.get_tenant_network()
-        create_kwargs = fixed_network.set_networks_kwarg(network,
-                                                         create_kwargs)
-        self.servers_client.create_server(
-            name=name,
-            imageRef=image,
-            flavorRef=flavor_id,
-            **create_kwargs)
-        # needed because of bug 1199788
-        params = {'name': name}
-        server_list = self.servers_client.list_servers(**params)
-        self.servers = server_list['servers']
-        for server in self.servers:
-            # after deleting all servers - wait for all servers to clear
-            # before cleanup continues
-            self.addCleanupClass(waiters.wait_for_server_termination,
-                                 self.servers_client,
-                                 server['id'])
-        for server in self.servers:
-            self.addCleanupClass(self.servers_client.delete_server,
-                                 server['id'])
-        self._wait_for_server_status('ACTIVE')
-
-    def _large_ops_scenario(self):
-        image = self.glance_image_create()
-        self.nova_boot(image)
-
-    @test.idempotent_id('14ba0e78-2ed9-4d17-9659-a48f4756ecb3')
-    @test.services('compute', 'image')
-    def test_large_ops_scenario_1(self):
-        self._large_ops_scenario()
-
-    @test.idempotent_id('b9b79b88-32aa-42db-8f8f-dcc8f4b4ccfe')
-    @test.services('compute', 'image')
-    def test_large_ops_scenario_2(self):
-        self._large_ops_scenario()
-
-    @test.idempotent_id('3aab7e82-2de3-419a-9da1-9f3a070668fb')
-    @test.services('compute', 'image')
-    def test_large_ops_scenario_3(self):
-        self._large_ops_scenario()
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 63c844b..9e2477e 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -626,9 +626,6 @@
             "admin_state_up of instance port to True")
 
     @test.idempotent_id('759462e1-8535-46b0-ab3a-33aa45c55aaa')
-    @testtools.skipUnless(CONF.compute_feature_enabled.preserve_ports,
-                          'Preserving ports on instance delete may not be '
-                          'supported in the version of Nova being tested.')
     @test.services('compute', 'network')
     def test_preserve_preexisting_port(self):
         """Test preserve pre-existing port
@@ -683,7 +680,7 @@
         # TODO(yfried): refactor this test to be used for other agents (dhcp)
         # as well
 
-        list_hosts = (self.admin_manager.network_client.
+        list_hosts = (self.admin_manager.routers_client.
                       list_l3_agents_hosting_router)
         schedule_router = (self.admin_manager.network_agents_client.
                            create_router_on_l3_agent)
@@ -696,7 +693,7 @@
 
         # NOTE(kevinbenton): we have to use the admin credentials to check
         # for the distributed flag because self.router only has a tenant view.
-        admin = self.admin_manager.network_client.show_router(self.router.id)
+        admin = self.admin_manager.routers_client.show_router(self.router.id)
         if admin['router'].get('distributed', False):
             msg = "Rescheduling test does not apply to distributed routers."
             raise self.skipException(msg)
@@ -741,6 +738,8 @@
             msg='After router rescheduling')
 
     @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')
     @test.services('compute', 'network')
     def test_port_security_macspoofing_port(self):
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 18bd764..058f43b 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -12,6 +12,7 @@
 #    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
 
 from tempest import clients
 from tempest.common.utils import data_utils
@@ -20,6 +21,7 @@
 from tempest import test
 
 CONF = config.CONF
+LOG = log.getLogger(__name__)
 
 
 class TestSecurityGroupsBasicOps(manager.NetworkScenarioTest):
@@ -151,6 +153,14 @@
     @classmethod
     def resource_setup(cls):
         super(TestSecurityGroupsBasicOps, cls).resource_setup()
+
+        cls.multi_node = CONF.compute.min_compute_nodes > 1 and \
+            test.is_scheduler_filter_enabled("DifferentHostFilter")
+        if cls.multi_node:
+            LOG.info("Working in Multi Node mode")
+        else:
+            LOG.info("Working in Single Node mode")
+
         cls.floating_ips = {}
         cls.tenants = {}
         creds = cls.manager.credentials
@@ -162,6 +172,12 @@
         cls.floating_ip_access = not CONF.network.public_router_id
 
     def setUp(self):
+        """Set up a single tenant with an accessible server.
+
+        If multi-host is enabled, save created server uuids.
+        """
+        self.servers = []
+
         super(TestSecurityGroupsBasicOps, self).setUp()
         self._deploy_tenant(self.primary_tenant)
         self._verify_network_details(self.primary_tenant)
@@ -233,21 +249,44 @@
         # and distributed routers; 'device_owner' is "" by default.
         return port['device_owner'].startswith('network:router_interface')
 
-    def _create_server(self, name, tenant, security_groups=None):
-        """creates a server and assigns to security group"""
+    def _create_server(self, name, tenant, security_groups=None, **kwargs):
+        """Creates a server and assigns it to security group.
+
+        If multi-host is enabled, Ensures servers are created on different
+        compute nodes, by storing created servers' ids and uses different_host
+        as scheduler_hints on creation.
+        Validates servers are created as requested, using admin client.
+        """
         if security_groups is None:
             security_groups = [tenant.security_groups['default']]
         security_groups_names = [{'name': s['name']} for s in security_groups]
+        if self.multi_node:
+            kwargs["scheduler_hints"] = {'different_host': self.servers}
         server = self.create_server(
             name=name,
             networks=[{'uuid': tenant.network.id}],
             key_name=tenant.keypair['name'],
             security_groups=security_groups_names,
             wait_until='ACTIVE',
-            clients=tenant.manager)
+            clients=tenant.manager,
+            **kwargs)
         self.assertEqual(
             sorted([s['name'] for s in security_groups]),
             sorted([s['name'] for s in server['security_groups']]))
+
+        # Verify servers are on different compute nodes
+        if self.multi_node:
+            adm_get_server = self.admin_manager.servers_client.show_server
+            new_host = adm_get_server(server["id"])["server"][
+                "OS-EXT-SRV-ATTR:host"]
+            host_list = [adm_get_server(s)["server"]["OS-EXT-SRV-ATTR:host"]
+                         for s in self.servers]
+            self.assertNotIn(new_host, host_list,
+                             message="Failed to boot servers on different "
+                                     "Compute nodes.")
+
+            self.servers.append(server["id"])
+
         return server
 
     def _create_tenant_servers(self, tenant, num=1):
@@ -284,6 +323,7 @@
         network, subnet, router = self.create_networks(
             client=tenant.manager.network_client,
             networks_client=tenant.manager.networks_client,
+            routers_client=tenant.manager.routers_client,
             subnets_client=tenant.manager.subnets_client)
         tenant.set_network(network, subnet, router)
 
@@ -348,6 +388,7 @@
         )
         self._create_security_group_rule(
             secgroup=tenant.security_groups['default'],
+            security_groups_client=tenant.manager.security_groups_client,
             **ruleset
         )
         access_point_ssh = self._connect_to_access_point(tenant)
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 1d09fe7..6121a90 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -16,13 +16,13 @@
 import time
 
 from oslo_log import log as logging
-from tempest_lib import decorators
-from tempest_lib import exceptions as lib_exc
 import testtools
 
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
 from tempest.scenario import manager
 from tempest import test
 
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 4ce57db..71bb50e 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -10,6 +10,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from oslo_log import log as logging
+
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
@@ -17,6 +19,7 @@
 from tempest import test
 
 CONF = config.CONF
+LOG = logging.getLogger(__name__)
 
 
 class TestVolumeBootPattern(manager.ScenarioTest):
@@ -32,6 +35,11 @@
      * Boot an additional instance from the new snapshot based volume
      * Check written content in the instance booted from snapshot
     """
+
+    # Boot from volume scenario is quite slow, and needs extra
+    # breathing room to get through deletes in the time allotted.
+    TIMEOUT_SCALING_FACTOR = 2
+
     @classmethod
     def skip_checks(cls):
         super(TestVolumeBootPattern, cls).skip_checks()
@@ -101,42 +109,53 @@
     @test.attr(type='smoke')
     @test.services('compute', 'volume', 'image')
     def test_volume_boot_pattern(self):
+        LOG.info("Creating keypair and security group")
         keypair = self.create_keypair()
         security_group = self._create_security_group()
 
         # 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)
+        LOG.info("Booted first instance: %s" % instance_1st)
 
         # write content to volume on instance
+        LOG.info("Setting timestamp in instance %s" % instance_1st)
         ip_instance_1st = self.get_server_ip(instance_1st)
         timestamp = self.create_timestamp(ip_instance_1st,
                                           private_key=keypair['private_key'])
 
         # delete instance
+        LOG.info("Deleting first instance: %s" % instance_1st)
         self._delete_server(instance_1st)
 
         # create a 2nd instance from volume
         instance_2nd = self._boot_instance_from_volume(volume_origin['id'],
                                                        keypair, security_group)
+        LOG.info("Booted second instance %s" % instance_2nd)
 
         # check the content of written file
+        LOG.info("Getting timestamp in instance %s" % instance_2nd)
         ip_instance_2nd = self.get_server_ip(instance_2nd)
         timestamp2 = self.get_timestamp(ip_instance_2nd,
                                         private_key=keypair['private_key'])
         self.assertEqual(timestamp, timestamp2)
 
         # snapshot a volume
+        LOG.info("Creating snapshot from volume: %s" % volume_origin['id'])
         snapshot = self._create_snapshot_from_volume(volume_origin['id'])
 
         # create a 3rd instance from snapshot
+        LOG.info("Creating third instance from snapshot: %s" % snapshot['id'])
         volume = self._create_volume_from_snapshot(snapshot['id'])
         server_from_snapshot = (
             self._boot_instance_from_volume(volume['id'],
                                             keypair, security_group))
 
         # check the content of written file
+        LOG.info("Logging into third instance to get timestamp: %s" %
+                 server_from_snapshot)
         server_from_snapshot_ip = self.get_server_ip(server_from_snapshot)
         timestamp3 = self.get_timestamp(server_from_snapshot_ip,
                                         private_key=keypair['private_key'])
diff --git a/tempest/scenario/utils.py b/tempest/scenario/utils.py
index 3cbb3bc..75fd000 100644
--- a/tempest/scenario/utils.py
+++ b/tempest/scenario/utils.py
@@ -18,14 +18,14 @@
 import unicodedata
 
 from oslo_serialization import jsonutils as json
-from tempest_lib.common.utils import misc
-from tempest_lib import exceptions as exc_lib
 import testscenarios
 import testtools
 
 from tempest import clients
 from tempest.common import credentials_factory as credentials
 from tempest import config
+from tempest.lib.common.utils import misc
+from tempest.lib import exceptions as exc_lib
 
 CONF = config.CONF
 
diff --git a/tempest/services/baremetal/base.py b/tempest/services/baremetal/base.py
index d8cb99d..6e24801 100644
--- a/tempest/services/baremetal/base.py
+++ b/tempest/services/baremetal/base.py
@@ -16,7 +16,7 @@
 import six
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
 def handle_errors(f):
@@ -39,7 +39,7 @@
     return wrapper
 
 
-class BaremetalClient(service_client.ServiceClient):
+class BaremetalClient(rest_client.RestClient):
     """Base Tempest REST client for Ironic API."""
 
     uri_prefix = ''
diff --git a/tempest/services/base_microversion_client.py b/tempest/services/base_microversion_client.py
deleted file mode 100644
index 4c750f5..0000000
--- a/tempest/services/base_microversion_client.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# 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.common import rest_client
-
-
-class BaseMicroversionClient(rest_client.RestClient):
-    """Base class to support microversion in service clients
-
-    This class is used to support microversion in service clients.
-    This provides feature to make API request with microversion.
-    Service clients derived from this class will be able to send API
-    request to server with or without microversion.
-    If api_microversion is not set on service client then API request will be
-    normal request without microversion.
-
-    """
-    def __init__(self, auth_provider, service, region,
-                 api_microversion_header_name, **kwargs):
-        """Base Microversion Client __init__
-
-        :param auth_provider: an auth provider object used to wrap requests in
-                              auth
-        :param str service: The service name to use for the catalog lookup
-        :param str region: The region to use for the catalog lookup
-        :param str api_microversion_header_name: The microversion header name
-                                                 to use for sending API
-                                                 request with microversion
-        :param kwargs: kwargs required by rest_client.RestClient
-        """
-        super(BaseMicroversionClient, self).__init__(
-            auth_provider, service, region, **kwargs)
-        self.api_microversion_header_name = api_microversion_header_name
-        self.api_microversion = None
-
-    def get_headers(self):
-        headers = super(BaseMicroversionClient, self).get_headers()
-        if self.api_microversion:
-            headers[self.api_microversion_header_name] = self.api_microversion
-        return headers
-
-    def set_api_microversion(self, microversion):
-        self.api_microversion = microversion
diff --git a/tempest/services/compute/json/base_compute_client.py b/tempest/services/compute/json/base_compute_client.py
index 5349af6..8cfde4b 100644
--- a/tempest/services/compute/json/base_compute_client.py
+++ b/tempest/services/compute/json/base_compute_client.py
@@ -11,30 +11,38 @@
 #    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.common import rest_client
 
 from tempest.common import api_version_request
 from tempest.common import api_version_utils
 from tempest import exceptions
-from tempest.services import base_microversion_client
+
+COMPUTE_MICROVERSION = None
 
 
-class BaseComputeClient(base_microversion_client.BaseMicroversionClient):
+class BaseComputeClient(rest_client.RestClient):
+    api_microversion_header_name = 'X-OpenStack-Nova-API-Version'
 
     def __init__(self, auth_provider, service, region,
-                 api_microversion_header_name='X-OpenStack-Nova-API-Version',
                  **kwargs):
         super(BaseComputeClient, self).__init__(
-            auth_provider, service, region,
-            api_microversion_header_name, **kwargs)
+            auth_provider, service, region, **kwargs)
+
+    def get_headers(self):
+        headers = super(BaseComputeClient, self).get_headers()
+        if COMPUTE_MICROVERSION:
+            headers[self.api_microversion_header_name] = COMPUTE_MICROVERSION
+        return headers
 
     def request(self, method, url, extra_headers=False, headers=None,
                 body=None):
         resp, resp_body = super(BaseComputeClient, self).request(
             method, url, extra_headers, headers, body)
-        if self.api_microversion and self.api_microversion != 'latest':
+        if (COMPUTE_MICROVERSION and
+            COMPUTE_MICROVERSION != api_version_utils.LATEST_MICROVERSION):
             api_version_utils.assert_version_header_matches_request(
                 self.api_microversion_header_name,
-                self.api_microversion,
+                COMPUTE_MICROVERSION,
                 resp)
         return resp, resp_body
 
@@ -52,7 +60,7 @@
             {'min': '2.10', 'max': None, 'schema': schemav210}]
         """
         schema = None
-        version = api_version_request.APIVersionRequest(self.api_microversion)
+        version = api_version_request.APIVersionRequest(COMPUTE_MICROVERSION)
         for items in schema_versions_info:
             min_version = api_version_request.APIVersionRequest(items['min'])
             max_version = api_version_request.APIVersionRequest(items['max'])
diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py
index ec9b1e0..045f03c 100644
--- a/tempest/services/compute/json/keypairs_client.py
+++ b/tempest/services/compute/json/keypairs_client.py
@@ -17,7 +17,7 @@
 
 from tempest.api_schema.response.compute.v2_1 import keypairs as schemav21
 from tempest.api_schema.response.compute.v2_2 import keypairs as schemav22
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 from tempest.services.compute.json import base_compute_client
 
 
@@ -31,14 +31,14 @@
         body = json.loads(body)
         schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.list_keypairs, resp, body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_keypair(self, keypair_name):
         resp, body = self.get("os-keypairs/%s" % keypair_name)
         body = json.loads(body)
         schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.get_keypair, resp, body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_keypair(self, **kwargs):
         post_body = json.dumps({'keypair': kwargs})
@@ -46,10 +46,10 @@
         body = json.loads(body)
         schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.create_keypair, resp, body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_keypair(self, keypair_name):
         resp, body = self.delete("os-keypairs/%s" % keypair_name)
         schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.delete_keypair, resp, body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/data_processing/v1_1/data_processing_client.py b/tempest/services/data_processing/v1_1/data_processing_client.py
index 5aa2622..c74672f 100644
--- a/tempest/services/data_processing/v1_1/data_processing_client.py
+++ b/tempest/services/data_processing/v1_1/data_processing_client.py
@@ -14,10 +14,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class DataProcessingClient(service_client.ServiceClient):
+class DataProcessingClient(rest_client.RestClient):
 
     def _request_and_check_resp(self, request_func, uri, resp_status):
         """Make a request and check response status code.
@@ -26,7 +26,7 @@
         """
         resp, body = request_func(uri)
         self.expected_success(resp_status, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def _request_and_check_resp_data(self, request_func, uri, resp_status):
         """Make a request and check response status code.
@@ -47,7 +47,7 @@
         resp, body = request_func(uri, headers=headers, *args, **kwargs)
         self.expected_success(resp_status, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_node_group_templates(self):
         """List all node group templates for a user."""
diff --git a/tempest/services/database/json/flavors_client.py b/tempest/services/database/json/flavors_client.py
index dbb5172..bd8ffb0 100644
--- a/tempest/services/database/json/flavors_client.py
+++ b/tempest/services/database/json/flavors_client.py
@@ -16,10 +16,10 @@
 from oslo_serialization import jsonutils as json
 from six.moves import urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class DatabaseFlavorsClient(service_client.ServiceClient):
+class DatabaseFlavorsClient(rest_client.RestClient):
 
     def list_db_flavors(self, params=None):
         url = 'flavors'
@@ -29,10 +29,10 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_db_flavor(self, db_flavor_id):
         resp, body = self.get("flavors/%s" % db_flavor_id)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/database/json/limits_client.py b/tempest/services/database/json/limits_client.py
index da495d7..a1c58c2 100644
--- a/tempest/services/database/json/limits_client.py
+++ b/tempest/services/database/json/limits_client.py
@@ -16,10 +16,10 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class DatabaseLimitsClient(service_client.ServiceClient):
+class DatabaseLimitsClient(rest_client.RestClient):
 
     def list_db_limits(self, params=None):
         """List all limits."""
@@ -29,4 +29,4 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/database/json/versions_client.py b/tempest/services/database/json/versions_client.py
index 7a560d9..2f28203 100644
--- a/tempest/services/database/json/versions_client.py
+++ b/tempest/services/database/json/versions_client.py
@@ -16,24 +16,14 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class DatabaseVersionsClient(service_client.ServiceClient):
+class DatabaseVersionsClient(rest_client.RestClient):
 
-    def __init__(self, auth_provider, service, region,
-                 endpoint_type=None, build_interval=None, build_timeout=None,
-                 disable_ssl_certificate_validation=None, ca_certs=None,
-                 trace_requests=None):
-        dscv = disable_ssl_certificate_validation
+    def __init__(self, auth_provider, service, region, **kwargs):
         super(DatabaseVersionsClient, self).__init__(
-            auth_provider, service, region,
-            endpoint_type=endpoint_type,
-            build_interval=build_interval,
-            build_timeout=build_timeout,
-            disable_ssl_certificate_validation=dscv,
-            ca_certs=ca_certs,
-            trace_requests=trace_requests)
+            auth_provider, service, region, **kwargs)
         self.skip_path()
 
     def list_db_versions(self, params=None):
@@ -45,4 +35,4 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v2/json/endpoints_client.py b/tempest/services/identity/v2/json/endpoints_client.py
index ff9907d..ba9f867 100644
--- a/tempest/services/identity/v2/json/endpoints_client.py
+++ b/tempest/services/identity/v2/json/endpoints_client.py
@@ -14,10 +14,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class EndpointsClient(service_client.ServiceClient):
+class EndpointsClient(rest_client.RestClient):
     api_version = "v2.0"
 
     def create_endpoint(self, service_id, region_id, **kwargs):
@@ -33,18 +33,18 @@
         resp, body = self.post('/endpoints', post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_endpoints(self):
         """List Endpoints - Returns Endpoints."""
         resp, body = self.get('/endpoints')
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_endpoint(self, endpoint_id):
         """Delete an endpoint."""
         url = '/endpoints/%s' % endpoint_id
         resp, body = self.delete(url)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v2/json/identity_client.py b/tempest/services/identity/v2/json/identity_client.py
index f045bb7..6caff0e 100644
--- a/tempest/services/identity/v2/json/identity_client.py
+++ b/tempest/services/identity/v2/json/identity_client.py
@@ -12,10 +12,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class IdentityClient(service_client.ServiceClient):
+class IdentityClient(rest_client.RestClient):
     api_version = "v2.0"
 
     def show_api_description(self):
@@ -24,24 +24,24 @@
         resp, body = self.get(url)
         self.expected_success([200, 203], resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_token(self, token_id):
         """Get token details."""
         resp, body = self.get("tokens/%s" % token_id)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_token(self, token_id):
         """Delete a token."""
         resp, body = self.delete("tokens/%s" % token_id)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_extensions(self):
         """List all the extensions."""
         resp, body = self.get('/extensions')
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v2/json/roles_client.py b/tempest/services/identity/v2/json/roles_client.py
index ef6dfe9..acd97c6 100644
--- a/tempest/services/identity/v2/json/roles_client.py
+++ b/tempest/services/identity/v2/json/roles_client.py
@@ -12,10 +12,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class RolesClient(service_client.ServiceClient):
+class RolesClient(rest_client.RestClient):
     api_version = "v2.0"
 
     def create_role(self, **kwargs):
@@ -28,14 +28,14 @@
         resp, body = self.post('OS-KSADM/roles', post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_role(self, role_id):
         """Get a role by its id."""
         resp, body = self.get('OS-KSADM/roles/%s' % role_id)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_role(self, role_id):
         """Delete a role."""
@@ -49,7 +49,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def assign_user_role(self, tenant_id, user_id, role_id):
         """Add roles to a user on a tenant."""
@@ -57,18 +57,18 @@
                               (tenant_id, user_id, role_id), "")
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_user_role(self, tenant_id, user_id, role_id):
         """Removes a role assignment for a user on a tenant."""
         resp, body = self.delete('/tenants/%s/users/%s/roles/OS-KSADM/%s' %
                                  (tenant_id, user_id, role_id))
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_roles(self):
         """Returns roles."""
         resp, body = self.get('OS-KSADM/roles')
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v2/json/services_client.py b/tempest/services/identity/v2/json/services_client.py
index 436d00d..d8be6c6 100644
--- a/tempest/services/identity/v2/json/services_client.py
+++ b/tempest/services/identity/v2/json/services_client.py
@@ -14,10 +14,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class ServicesClient(service_client.ServiceClient):
+class ServicesClient(rest_client.RestClient):
     api_version = "v2.0"
 
     def create_service(self, name, type, **kwargs):
@@ -31,7 +31,7 @@
         resp, body = self.post('/OS-KSADM/services', post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_service(self, service_id):
         """Get Service."""
@@ -39,18 +39,18 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_services(self):
         """List Service - Returns Services."""
         resp, body = self.get('/OS-KSADM/services')
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_service(self, service_id):
         """Delete Service."""
         url = '/OS-KSADM/services/%s' % service_id
         resp, body = self.delete(url)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v2/json/tenants_client.py b/tempest/services/identity/v2/json/tenants_client.py
index 937ae6f..034938e 100644
--- a/tempest/services/identity/v2/json/tenants_client.py
+++ b/tempest/services/identity/v2/json/tenants_client.py
@@ -14,10 +14,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class TenantsClient(service_client.ServiceClient):
+class TenantsClient(rest_client.RestClient):
     api_version = "v2.0"
 
     def create_tenant(self, name, **kwargs):
@@ -36,27 +36,27 @@
         resp, body = self.post('tenants', post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_tenant(self, tenant_id):
         """Delete a tenant."""
         resp, body = self.delete('tenants/%s' % str(tenant_id))
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_tenant(self, tenant_id):
         """Get tenant details."""
         resp, body = self.get('tenants/%s' % str(tenant_id))
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_tenants(self):
         """Returns tenants."""
         resp, body = self.get('tenants')
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_tenant(self, tenant_id, **kwargs):
         """Updates a tenant."""
@@ -74,11 +74,11 @@
         resp, body = self.post('tenants/%s' % tenant_id, post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_tenant_users(self, tenant_id):
         """List users for a Tenant."""
         resp, body = self.get('/tenants/%s/users' % tenant_id)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v2/json/users_client.py b/tempest/services/identity/v2/json/users_client.py
index 5327638..5f8127f 100644
--- a/tempest/services/identity/v2/json/users_client.py
+++ b/tempest/services/identity/v2/json/users_client.py
@@ -12,10 +12,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class UsersClient(service_client.ServiceClient):
+class UsersClient(rest_client.RestClient):
     api_version = "v2.0"
 
     def create_user(self, name, password, tenant_id, email, **kwargs):
@@ -33,7 +33,7 @@
         resp, body = self.post('users', post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_user(self, user_id, **kwargs):
         """Updates a user."""
@@ -41,27 +41,27 @@
         resp, body = self.put('users/%s' % user_id, put_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_user(self, user_id):
         """GET a user."""
         resp, body = self.get("users/%s" % user_id)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_user(self, user_id):
         """Delete a user."""
         resp, body = self.delete("users/%s" % user_id)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_users(self):
         """Get the list of users."""
         resp, body = self.get("users")
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def enable_disable_user(self, user_id, **kwargs):
         """Enables or disables a user.
@@ -77,7 +77,7 @@
         resp, body = self.put('users/%s/enabled' % user_id, put_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_user_password(self, user_id, **kwargs):
         """Update User Password."""
@@ -89,7 +89,7 @@
         resp, body = self.put('users/%s/OS-KSADM/password' % user_id, put_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_user_own_password(self, user_id, **kwargs):
         """User updates own password"""
@@ -104,7 +104,7 @@
         resp, body = self.patch('OS-KSCRUD/users/%s' % user_id, patch_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_user_ec2_credentials(self, user_id, **kwargs):
         # TODO(piyush): Current api-site doesn't contain this API description.
@@ -115,23 +115,23 @@
                                post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_user_ec2_credentials(self, user_id, access):
         resp, body = self.delete('/users/%s/credentials/OS-EC2/%s' %
                                  (user_id, access))
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_user_ec2_credentials(self, user_id):
         resp, body = self.get('/users/%s/credentials/OS-EC2' % user_id)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_user_ec2_credentials(self, user_id, access):
         resp, body = self.get('/users/%s/credentials/OS-EC2/%s' %
                               (user_id, access))
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/credentials_client.py b/tempest/services/identity/v3/json/credentials_client.py
index 753e960..6ab94d0 100644
--- a/tempest/services/identity/v3/json/credentials_client.py
+++ b/tempest/services/identity/v3/json/credentials_client.py
@@ -19,10 +19,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class CredentialsClient(service_client.ServiceClient):
+class CredentialsClient(rest_client.RestClient):
     api_version = "v3"
 
     def create_credential(self, **kwargs):
@@ -36,7 +36,7 @@
         self.expected_success(201, resp.status)
         body = json.loads(body)
         body['credential']['blob'] = json.loads(body['credential']['blob'])
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_credential(self, credential_id, **kwargs):
         """Updates a credential.
@@ -49,7 +49,7 @@
         self.expected_success(200, resp.status)
         body = json.loads(body)
         body['credential']['blob'] = json.loads(body['credential']['blob'])
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_credential(self, credential_id):
         """To GET Details of a credential."""
@@ -57,17 +57,17 @@
         self.expected_success(200, resp.status)
         body = json.loads(body)
         body['credential']['blob'] = json.loads(body['credential']['blob'])
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_credentials(self):
         """Lists out all the available credentials."""
         resp, body = self.get('credentials')
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_credential(self, credential_id):
         """Deletes a credential."""
         resp, body = self.delete('credentials/%s' % credential_id)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/domains_client.py b/tempest/services/identity/v3/json/domains_client.py
new file mode 100644
index 0000000..d129a0a
--- /dev/null
+++ b/tempest/services/identity/v3/json/domains_client.py
@@ -0,0 +1,77 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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 DomainsClient(rest_client.RestClient):
+    api_version = "v3"
+
+    def create_domain(self, name, **kwargs):
+        """Creates a domain."""
+        description = kwargs.get('description', None)
+        en = kwargs.get('enabled', True)
+        post_body = {
+            'description': description,
+            'enabled': en,
+            'name': name
+        }
+        post_body = json.dumps({'domain': post_body})
+        resp, body = self.post('domains', post_body)
+        self.expected_success(201, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_domain(self, domain_id):
+        """Deletes a domain."""
+        resp, body = self.delete('domains/%s' % str(domain_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_domains(self, params=None):
+        """List Domains."""
+        url = 'domains'
+        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 update_domain(self, domain_id, **kwargs):
+        """Updates a domain."""
+        body = self.show_domain(domain_id)['domain']
+        description = kwargs.get('description', body['description'])
+        en = kwargs.get('enabled', body['enabled'])
+        name = kwargs.get('name', body['name'])
+        post_body = {
+            'description': description,
+            'enabled': en,
+            'name': name
+        }
+        post_body = json.dumps({'domain': post_body})
+        resp, body = self.patch('domains/%s' % domain_id, post_body)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_domain(self, domain_id):
+        """Get Domain details."""
+        resp, body = self.get('domains/%s' % domain_id)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/endpoints_client.py b/tempest/services/identity/v3/json/endpoints_client.py
index 8ab7464..db30508 100644
--- a/tempest/services/identity/v3/json/endpoints_client.py
+++ b/tempest/services/identity/v3/json/endpoints_client.py
@@ -19,10 +19,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class EndPointClient(service_client.ServiceClient):
+class EndPointsClient(rest_client.RestClient):
     api_version = "v3"
 
     def list_endpoints(self):
@@ -30,7 +30,7 @@
         resp, body = self.get('endpoints')
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_endpoint(self, **kwargs):
         """Create endpoint.
@@ -42,7 +42,7 @@
         resp, body = self.post('endpoints', post_body)
         self.expected_success(201, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_endpoint(self, endpoint_id, **kwargs):
         """Updates an endpoint with given parameters.
@@ -54,17 +54,17 @@
         resp, body = self.patch('endpoints/%s' % endpoint_id, post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_endpoint(self, endpoint_id):
         """Delete endpoint."""
         resp_header, resp_body = self.delete('endpoints/%s' % endpoint_id)
         self.expected_success(204, resp_header.status)
-        return service_client.ResponseBody(resp_header, resp_body)
+        return rest_client.ResponseBody(resp_header, resp_body)
 
     def show_endpoint(self, endpoint_id):
         """Get endpoint."""
         resp_header, resp_body = self.get('endpoints/%s' % endpoint_id)
         self.expected_success(200, resp_header.status)
         resp_body = json.loads(resp_body)
-        return service_client.ResponseBody(resp_header, resp_body)
+        return rest_client.ResponseBody(resp_header, resp_body)
diff --git a/tempest/services/identity/v3/json/groups_client.py b/tempest/services/identity/v3/json/groups_client.py
index 6ed85cf..1a495f8 100644
--- a/tempest/services/identity/v3/json/groups_client.py
+++ b/tempest/services/identity/v3/json/groups_client.py
@@ -19,10 +19,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class GroupsClient(service_client.ServiceClient):
+class GroupsClient(rest_client.RestClient):
     api_version = "v3"
 
     def create_group(self, **kwargs):
@@ -35,21 +35,21 @@
         resp, body = self.post('groups', post_body)
         self.expected_success(201, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_group(self, group_id):
         """Get group details."""
         resp, body = self.get('groups/%s' % group_id)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_groups(self):
         """Lists the groups."""
         resp, body = self.get('groups')
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_group(self, group_id, **kwargs):
         """Updates a group.
@@ -61,36 +61,36 @@
         resp, body = self.patch('groups/%s' % group_id, post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_group(self, group_id):
         """Delete a group."""
         resp, body = self.delete('groups/%s' % str(group_id))
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def add_group_user(self, group_id, user_id):
         """Add user into group."""
         resp, body = self.put('groups/%s/users/%s' % (group_id, user_id),
                               None)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_group_users(self, group_id):
         """List users in group."""
         resp, body = self.get('groups/%s/users' % group_id)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_group_user(self, group_id, user_id):
         """Delete user in group."""
         resp, body = self.delete('groups/%s/users/%s' % (group_id, user_id))
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def check_group_user_existence(self, group_id, user_id):
         """Check user in group."""
         resp, body = self.head('groups/%s/users/%s' % (group_id, user_id))
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
+        return rest_client.ResponseBody(resp)
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index 252fad7..8177e35 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -14,12 +14,11 @@
 #    under the License.
 
 from oslo_serialization import jsonutils as json
-from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class IdentityV3Client(service_client.ServiceClient):
+class IdentityClient(rest_client.RestClient):
     api_version = "v3"
 
     def show_api_description(self):
@@ -28,205 +27,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def create_user(self, user_name, password=None, project_id=None,
-                    email=None, domain_id='default', **kwargs):
-        """Creates a user."""
-        en = kwargs.get('enabled', True)
-        description = kwargs.get('description', None)
-        default_project_id = kwargs.get('default_project_id')
-        post_body = {
-            'project_id': project_id,
-            'default_project_id': default_project_id,
-            'description': description,
-            'domain_id': domain_id,
-            'email': email,
-            'enabled': en,
-            'name': user_name,
-            'password': password
-        }
-        post_body = json.dumps({'user': post_body})
-        resp, body = self.post('users', post_body)
-        self.expected_success(201, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def update_user(self, user_id, name, **kwargs):
-        """Updates a user."""
-        body = self.show_user(user_id)['user']
-        email = kwargs.get('email', body['email'])
-        en = kwargs.get('enabled', body['enabled'])
-        project_id = kwargs.get('project_id', body['project_id'])
-        if 'default_project_id' in body.keys():
-            default_project_id = kwargs.get('default_project_id',
-                                            body['default_project_id'])
-        else:
-            default_project_id = kwargs.get('default_project_id')
-        description = kwargs.get('description', body['description'])
-        domain_id = kwargs.get('domain_id', body['domain_id'])
-        post_body = {
-            'name': name,
-            'email': email,
-            'enabled': en,
-            'project_id': project_id,
-            'default_project_id': default_project_id,
-            'id': user_id,
-            'domain_id': domain_id,
-            'description': description
-        }
-        post_body = json.dumps({'user': post_body})
-        resp, body = self.patch('users/%s' % user_id, post_body)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def update_user_password(self, user_id, **kwargs):
-        """Update a user password
-
-        Available params: see http://developer.openstack.org/
-                              api-ref-identity-v3.html#changeUserPassword
-        """
-        update_user = json.dumps({'user': kwargs})
-        resp, _ = self.post('users/%s/password' % user_id, update_user)
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
-
-    def list_user_projects(self, user_id):
-        """Lists the projects on which a user has roles assigned."""
-        resp, body = self.get('users/%s/projects' % user_id)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def list_users(self, params=None):
-        """Get the list of users."""
-        url = 'users'
-        if params:
-            url += '?%s' % urllib.urlencode(params)
-        resp, body = self.get(url)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def show_user(self, user_id):
-        """GET a user."""
-        resp, body = self.get("users/%s" % user_id)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def delete_user(self, user_id):
-        """Deletes a User."""
-        resp, body = self.delete("users/%s" % user_id)
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def create_role(self, **kwargs):
-        """Create a Role.
-
-        Available params: see http://developer.openstack.org/
-                              api-ref-identity-v3.html#createRole
-        """
-        post_body = json.dumps({'role': kwargs})
-        resp, body = self.post('roles', post_body)
-        self.expected_success(201, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def show_role(self, role_id):
-        """GET a Role."""
-        resp, body = self.get('roles/%s' % str(role_id))
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def list_roles(self):
-        """Get the list of Roles."""
-        resp, body = self.get("roles")
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def update_role(self, role_id, **kwargs):
-        """Update a Role.
-
-        Available params: see http://developer.openstack.org/
-                          api-ref-identity-v3.html#updateRole
-        """
-        post_body = json.dumps({'role': kwargs})
-        resp, body = self.patch('roles/%s' % str(role_id), post_body)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def delete_role(self, role_id):
-        """Delete a role."""
-        resp, body = self.delete('roles/%s' % str(role_id))
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def assign_user_role(self, project_id, user_id, role_id):
-        """Add roles to a user on a project."""
-        resp, body = self.put('projects/%s/users/%s/roles/%s' %
-                              (project_id, user_id, role_id), None)
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def create_domain(self, name, **kwargs):
-        """Creates a domain."""
-        description = kwargs.get('description', None)
-        en = kwargs.get('enabled', True)
-        post_body = {
-            'description': description,
-            'enabled': en,
-            'name': name
-        }
-        post_body = json.dumps({'domain': post_body})
-        resp, body = self.post('domains', post_body)
-        self.expected_success(201, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def delete_domain(self, domain_id):
-        """Delete a domain."""
-        resp, body = self.delete('domains/%s' % str(domain_id))
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def list_domains(self, params=None):
-        """List Domains."""
-        url = 'domains'
-        if params:
-            url += '?%s' % urllib.urlencode(params)
-        resp, body = self.get(url)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def update_domain(self, domain_id, **kwargs):
-        """Updates a domain."""
-        body = self.show_domain(domain_id)['domain']
-        description = kwargs.get('description', body['description'])
-        en = kwargs.get('enabled', body['enabled'])
-        name = kwargs.get('name', body['name'])
-        post_body = {
-            'description': description,
-            'enabled': en,
-            'name': name
-        }
-        post_body = json.dumps({'domain': post_body})
-        resp, body = self.patch('domains/%s' % domain_id, post_body)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def show_domain(self, domain_id):
-        """Get Domain details."""
-        resp, body = self.get('domains/%s' % domain_id)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_token(self, resp_token):
         """Get token details."""
@@ -234,199 +35,11 @@
         resp, body = self.get("auth/tokens", headers=headers)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_token(self, resp_token):
         """Deletes token."""
         headers = {'X-Subject-Token': resp_token}
         resp, body = self.delete("auth/tokens", headers=headers)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def list_user_groups(self, user_id):
-        """Lists groups which a user belongs to."""
-        resp, body = self.get('users/%s/groups' % user_id)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def assign_user_role_on_project(self, project_id, user_id, role_id):
-        """Add roles to a user on a project."""
-        resp, body = self.put('projects/%s/users/%s/roles/%s' %
-                              (project_id, user_id, role_id), None)
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def assign_user_role_on_domain(self, domain_id, user_id, role_id):
-        """Add roles to a user on a domain."""
-        resp, body = self.put('domains/%s/users/%s/roles/%s' %
-                              (domain_id, user_id, role_id), None)
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def list_user_roles_on_project(self, project_id, user_id):
-        """list roles of a user on a project."""
-        resp, body = self.get('projects/%s/users/%s/roles' %
-                              (project_id, user_id))
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def list_user_roles_on_domain(self, domain_id, user_id):
-        """list roles of a user on a domain."""
-        resp, body = self.get('domains/%s/users/%s/roles' %
-                              (domain_id, user_id))
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def delete_role_from_user_on_project(self, project_id, user_id, role_id):
-        """Delete role of a user on a project."""
-        resp, body = self.delete('projects/%s/users/%s/roles/%s' %
-                                 (project_id, user_id, role_id))
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def delete_role_from_user_on_domain(self, domain_id, user_id, role_id):
-        """Delete role of a user on a domain."""
-        resp, body = self.delete('domains/%s/users/%s/roles/%s' %
-                                 (domain_id, user_id, role_id))
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def check_user_role_existence_on_project(self, project_id,
-                                             user_id, role_id):
-        """Check role of a user on a project."""
-        resp, body = self.head('projects/%s/users/%s/roles/%s' %
-                               (project_id, user_id, role_id))
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
-
-    def check_user_role_existence_on_domain(self, domain_id,
-                                            user_id, role_id):
-        """Check role of a user on a domain."""
-        resp, body = self.head('domains/%s/users/%s/roles/%s' %
-                               (domain_id, user_id, role_id))
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
-
-    def assign_group_role_on_project(self, project_id, group_id, role_id):
-        """Add roles to a user on a project."""
-        resp, body = self.put('projects/%s/groups/%s/roles/%s' %
-                              (project_id, group_id, role_id), None)
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def assign_group_role_on_domain(self, domain_id, group_id, role_id):
-        """Add roles to a user on a domain."""
-        resp, body = self.put('domains/%s/groups/%s/roles/%s' %
-                              (domain_id, group_id, role_id), None)
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def list_group_roles_on_project(self, project_id, group_id):
-        """list roles of a user on a project."""
-        resp, body = self.get('projects/%s/groups/%s/roles' %
-                              (project_id, group_id))
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def list_group_roles_on_domain(self, domain_id, group_id):
-        """list roles of a user on a domain."""
-        resp, body = self.get('domains/%s/groups/%s/roles' %
-                              (domain_id, group_id))
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def delete_role_from_group_on_project(self, project_id, group_id, role_id):
-        """Delete role of a user on a project."""
-        resp, body = self.delete('projects/%s/groups/%s/roles/%s' %
-                                 (project_id, group_id, role_id))
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def delete_role_from_group_on_domain(self, domain_id, group_id, role_id):
-        """Delete role of a user on a domain."""
-        resp, body = self.delete('domains/%s/groups/%s/roles/%s' %
-                                 (domain_id, group_id, role_id))
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def check_role_from_group_on_project_existence(self, project_id,
-                                                   group_id, role_id):
-        """Check role of a user on a project."""
-        resp, body = self.head('projects/%s/groups/%s/roles/%s' %
-                               (project_id, group_id, role_id))
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
-
-    def check_role_from_group_on_domain_existence(self, domain_id,
-                                                  group_id, role_id):
-        """Check role of a user on a domain."""
-        resp, body = self.head('domains/%s/groups/%s/roles/%s' %
-                               (domain_id, group_id, role_id))
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
-
-    def create_trust(self, **kwargs):
-        """Creates a trust.
-
-        Available params: see http://developer.openstack.org/
-                              api-ref-identity-v3-ext.html#createTrust
-        """
-        post_body = json.dumps({'trust': kwargs})
-        resp, body = self.post('OS-TRUST/trusts', post_body)
-        self.expected_success(201, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def delete_trust(self, trust_id):
-        """Deletes a trust."""
-        resp, body = self.delete("OS-TRUST/trusts/%s" % trust_id)
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
-    def list_trusts(self, trustor_user_id=None, trustee_user_id=None):
-        """GET trusts."""
-        if trustor_user_id:
-            resp, body = self.get("OS-TRUST/trusts?trustor_user_id=%s"
-                                  % trustor_user_id)
-        elif trustee_user_id:
-            resp, body = self.get("OS-TRUST/trusts?trustee_user_id=%s"
-                                  % trustee_user_id)
-        else:
-            resp, body = self.get("OS-TRUST/trusts")
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def show_trust(self, trust_id):
-        """GET trust."""
-        resp, body = self.get("OS-TRUST/trusts/%s" % trust_id)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def list_trust_roles(self, trust_id):
-        """GET roles delegated by a trust."""
-        resp, body = self.get("OS-TRUST/trusts/%s/roles" % trust_id)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def show_trust_role(self, trust_id, role_id):
-        """GET role delegated by a trust."""
-        resp, body = self.get("OS-TRUST/trusts/%s/roles/%s"
-                              % (trust_id, role_id))
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def check_trust_role(self, trust_id, role_id):
-        """HEAD Check if role is delegated by a trust."""
-        resp, body = self.head("OS-TRUST/trusts/%s/roles/%s"
-                               % (trust_id, role_id))
-        self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/policies_client.py b/tempest/services/identity/v3/json/policies_client.py
index 639ed6d..f28db9a 100644
--- a/tempest/services/identity/v3/json/policies_client.py
+++ b/tempest/services/identity/v3/json/policies_client.py
@@ -19,10 +19,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class PoliciesClient(service_client.ServiceClient):
+class PoliciesClient(rest_client.RestClient):
     api_version = "v3"
 
     def create_policy(self, **kwargs):
@@ -35,14 +35,14 @@
         resp, body = self.post('policies', post_body)
         self.expected_success(201, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_policies(self):
         """Lists the policies."""
         resp, body = self.get('policies')
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_policy(self, policy_id):
         """Lists out the given policy."""
@@ -50,7 +50,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_policy(self, policy_id, **kwargs):
         """Updates a policy.
@@ -63,11 +63,11 @@
         resp, body = self.patch(url, post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_policy(self, policy_id):
         """Deletes the policy."""
         url = "policies/%s" % policy_id
         resp, body = self.delete(url)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/projects_client.py b/tempest/services/identity/v3/json/projects_client.py
index 2fa822f..dc553d0 100644
--- a/tempest/services/identity/v3/json/projects_client.py
+++ b/tempest/services/identity/v3/json/projects_client.py
@@ -16,10 +16,10 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class ProjectsClient(service_client.ServiceClient):
+class ProjectsClient(rest_client.RestClient):
     api_version = "v3"
 
     def create_project(self, name, **kwargs):
@@ -37,7 +37,7 @@
         resp, body = self.post('projects', post_body)
         self.expected_success(201, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_projects(self, params=None):
         url = "projects"
@@ -46,7 +46,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_project(self, project_id, **kwargs):
         body = self.show_project(project_id)['project']
@@ -65,17 +65,17 @@
         resp, body = self.patch('projects/%s' % project_id, post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_project(self, project_id):
         """GET a Project."""
         resp, body = self.get("projects/%s" % project_id)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_project(self, project_id):
         """Delete a project."""
         resp, body = self.delete('projects/%s' % str(project_id))
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/regions_client.py b/tempest/services/identity/v3/json/regions_client.py
index bc4b7a1..90dd9d7 100644
--- a/tempest/services/identity/v3/json/regions_client.py
+++ b/tempest/services/identity/v3/json/regions_client.py
@@ -20,10 +20,10 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class RegionsClient(service_client.ServiceClient):
+class RegionsClient(rest_client.RestClient):
     api_version = "v3"
 
     def create_region(self, region_id=None, **kwargs):
@@ -45,7 +45,7 @@
         resp, body = method(url, req_body)
         self.expected_success(201, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_region(self, region_id, **kwargs):
         """Updates a region.
@@ -57,7 +57,7 @@
         resp, body = self.patch('regions/%s' % region_id, post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_region(self, region_id):
         """Get region."""
@@ -65,7 +65,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_regions(self, params=None):
         """List regions."""
@@ -75,10 +75,10 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_region(self, region_id):
         """Delete region."""
         resp, body = self.delete('regions/%s' % region_id)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/roles_client.py b/tempest/services/identity/v3/json/roles_client.py
new file mode 100644
index 0000000..bdb0490
--- /dev/null
+++ b/tempest/services/identity/v3/json/roles_client.py
@@ -0,0 +1,315 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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 RolesClient(rest_client.RestClient):
+    api_version = "v3"
+
+    def create_role(self, **kwargs):
+        """Create a Role.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-identity-v3.html#createRole
+        """
+        post_body = json.dumps({'role': kwargs})
+        resp, body = self.post('roles', post_body)
+        self.expected_success(201, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_role(self, role_id):
+        """GET a Role."""
+        resp, body = self.get('roles/%s' % str(role_id))
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_roles(self):
+        """Get the list of Roles."""
+        resp, body = self.get("roles")
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_role(self, role_id, **kwargs):
+        """Update a Role.
+
+        Available params: see http://developer.openstack.org/
+                          api-ref-identity-v3.html#updateRole
+        """
+        post_body = json.dumps({'role': kwargs})
+        resp, body = self.patch('roles/%s' % str(role_id), post_body)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_role(self, role_id):
+        """Delete a role."""
+        resp, body = self.delete('roles/%s' % str(role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def assign_user_role_on_project(self, project_id, user_id, role_id):
+        """Add roles to a user on a project."""
+        resp, body = self.put('projects/%s/users/%s/roles/%s' %
+                              (project_id, user_id, role_id), None)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def assign_user_role_on_domain(self, domain_id, user_id, role_id):
+        """Add roles to a user on a domain."""
+        resp, body = self.put('domains/%s/users/%s/roles/%s' %
+                              (domain_id, user_id, role_id), None)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_user_roles_on_project(self, project_id, user_id):
+        """list roles of a user on a project."""
+        resp, body = self.get('projects/%s/users/%s/roles' %
+                              (project_id, user_id))
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_user_roles_on_domain(self, domain_id, user_id):
+        """list roles of a user on a domain."""
+        resp, body = self.get('domains/%s/users/%s/roles' %
+                              (domain_id, user_id))
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_role_from_user_on_project(self, project_id, user_id, role_id):
+        """Delete role of a user on a project."""
+        resp, body = self.delete('projects/%s/users/%s/roles/%s' %
+                                 (project_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_role_from_user_on_domain(self, domain_id, user_id, role_id):
+        """Delete role of a user on a domain."""
+        resp, body = self.delete('domains/%s/users/%s/roles/%s' %
+                                 (domain_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_user_role_existence_on_project(self, project_id,
+                                             user_id, role_id):
+        """Check role of a user on a project."""
+        resp, body = self.head('projects/%s/users/%s/roles/%s' %
+                               (project_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def check_user_role_existence_on_domain(self, domain_id,
+                                            user_id, role_id):
+        """Check role of a user on a domain."""
+        resp, body = self.head('domains/%s/users/%s/roles/%s' %
+                               (domain_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def assign_group_role_on_project(self, project_id, group_id, role_id):
+        """Add roles to a user on a project."""
+        resp, body = self.put('projects/%s/groups/%s/roles/%s' %
+                              (project_id, group_id, role_id), None)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def assign_group_role_on_domain(self, domain_id, group_id, role_id):
+        """Add roles to a user on a domain."""
+        resp, body = self.put('domains/%s/groups/%s/roles/%s' %
+                              (domain_id, group_id, role_id), None)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_group_roles_on_project(self, project_id, group_id):
+        """list roles of a user on a project."""
+        resp, body = self.get('projects/%s/groups/%s/roles' %
+                              (project_id, group_id))
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_group_roles_on_domain(self, domain_id, group_id):
+        """list roles of a user on a domain."""
+        resp, body = self.get('domains/%s/groups/%s/roles' %
+                              (domain_id, group_id))
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_role_from_group_on_project(self, project_id, group_id, role_id):
+        """Delete role of a user on a project."""
+        resp, body = self.delete('projects/%s/groups/%s/roles/%s' %
+                                 (project_id, group_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_role_from_group_on_domain(self, domain_id, group_id, role_id):
+        """Delete role of a user on a domain."""
+        resp, body = self.delete('domains/%s/groups/%s/roles/%s' %
+                                 (domain_id, group_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_role_from_group_on_project_existence(self, project_id,
+                                                   group_id, role_id):
+        """Check role of a user on a project."""
+        resp, body = self.head('projects/%s/groups/%s/roles/%s' %
+                               (project_id, group_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def check_role_from_group_on_domain_existence(self, domain_id,
+                                                  group_id, role_id):
+        """Check role of a user on a domain."""
+        resp, body = self.head('domains/%s/groups/%s/roles/%s' %
+                               (domain_id, group_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def assign_inherited_role_on_domains_user(
+            self, domain_id, user_id, role_id):
+        """Assigns a role to a user on projects owned by a domain."""
+        resp, body = self.put(
+            "OS-INHERIT/domains/%s/users/%s/roles/%s/inherited_to_projects"
+            % (domain_id, user_id, role_id), None)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def revoke_inherited_role_from_user_on_domain(
+            self, domain_id, user_id, role_id):
+        """Revokes an inherited project role from a user on a domain."""
+        resp, body = self.delete(
+            "OS-INHERIT/domains/%s/users/%s/roles/%s/inherited_to_projects"
+            % (domain_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_inherited_project_role_for_user_on_domain(
+            self, domain_id, user_id):
+        """Lists the inherited project roles on a domain for a user."""
+        resp, body = self.get(
+            "OS-INHERIT/domains/%s/users/%s/roles/inherited_to_projects"
+            % (domain_id, user_id))
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_user_inherited_project_role_on_domain(
+            self, domain_id, user_id, role_id):
+        """Checks whether a user has an inherited project role on a domain."""
+        resp, body = self.head(
+            "OS-INHERIT/domains/%s/users/%s/roles/%s/inherited_to_projects"
+            % (domain_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def assign_inherited_role_on_domains_group(
+            self, domain_id, group_id, role_id):
+        """Assigns a role to a group on projects owned by a domain."""
+        resp, body = self.put(
+            "OS-INHERIT/domains/%s/groups/%s/roles/%s/inherited_to_projects"
+            % (domain_id, group_id, role_id), None)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def revoke_inherited_role_from_group_on_domain(
+            self, domain_id, group_id, role_id):
+        """Revokes an inherited project role from a group on a domain."""
+        resp, body = self.delete(
+            "OS-INHERIT/domains/%s/groups/%s/roles/%s/inherited_to_projects"
+            % (domain_id, group_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_inherited_project_role_for_group_on_domain(
+            self, domain_id, group_id):
+        """Lists the inherited project roles on a domain for a group."""
+        resp, body = self.get(
+            "OS-INHERIT/domains/%s/groups/%s/roles/inherited_to_projects"
+            % (domain_id, group_id))
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_group_inherited_project_role_on_domain(
+            self, domain_id, group_id, role_id):
+        """Checks whether a group has an inherited project role on a domain."""
+        resp, body = self.head(
+            "OS-INHERIT/domains/%s/groups/%s/roles/%s/inherited_to_projects"
+            % (domain_id, group_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def assign_inherited_role_on_projects_user(
+            self, project_id, user_id, role_id):
+        """Assigns a role to a user on projects in a subtree."""
+        resp, body = self.put(
+            "OS-INHERIT/projects/%s/users/%s/roles/%s/inherited_to_projects"
+            % (project_id, user_id, role_id), None)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def revoke_inherited_role_from_user_on_project(
+            self, project_id, user_id, role_id):
+        """Revokes an inherited role from a user on a project."""
+        resp, body = self.delete(
+            "OS-INHERIT/projects/%s/users/%s/roles/%s/inherited_to_projects"
+            % (project_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_user_has_flag_on_inherited_to_project(
+            self, project_id, user_id, role_id):
+        """Checks whether a user has a role assignment"""
+        """with the inherited_to_projects flag on a project."""
+        resp, body = self.head(
+            "OS-INHERIT/projects/%s/users/%s/roles/%s/inherited_to_projects"
+            % (project_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def assign_inherited_role_on_projects_group(
+            self, project_id, group_id, role_id):
+        """Assigns a role to a group on projects in a subtree."""
+        resp, body = self.put(
+            "OS-INHERIT/projects/%s/groups/%s/roles/%s/inherited_to_projects"
+            % (project_id, group_id, role_id), None)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def revoke_inherited_role_from_group_on_project(
+            self, project_id, group_id, role_id):
+        """Revokes an inherited role from a group on a project."""
+        resp, body = self.delete(
+            "OS-INHERIT/projects/%s/groups/%s/roles/%s/inherited_to_projects"
+            % (project_id, group_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_group_has_flag_on_inherited_to_project(
+            self, project_id, group_id, role_id):
+        """Checks whether a group has a role assignment"""
+        """with the inherited_to_projects flag on a project."""
+        resp, body = self.head(
+            "OS-INHERIT/projects/%s/groups/%s/roles/%s/inherited_to_projects"
+            % (project_id, group_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
diff --git a/tempest/services/identity/v3/json/services_client.py b/tempest/services/identity/v3/json/services_client.py
index dd65f1d..e863016 100644
--- a/tempest/services/identity/v3/json/services_client.py
+++ b/tempest/services/identity/v3/json/services_client.py
@@ -19,10 +19,10 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class ServicesClient(service_client.ServiceClient):
+class ServicesClient(rest_client.RestClient):
     api_version = "v3"
 
     def update_service(self, service_id, **kwargs):
@@ -35,7 +35,7 @@
         resp, body = self.patch('services/%s' % service_id, patch_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_service(self, service_id):
         """Get Service."""
@@ -43,7 +43,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_service(self, **kwargs):
         """Creates a service.
@@ -55,16 +55,16 @@
         resp, body = self.post("services", body)
         self.expected_success(201, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_service(self, serv_id):
         url = "services/" + serv_id
         resp, body = self.delete(url)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_services(self):
         resp, body = self.get('services')
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/trusts_client.py b/tempest/services/identity/v3/json/trusts_client.py
new file mode 100644
index 0000000..dedee05
--- /dev/null
+++ b/tempest/services/identity/v3/json/trusts_client.py
@@ -0,0 +1,82 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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 TrustsClient(rest_client.RestClient):
+    api_version = "v3"
+
+    def create_trust(self, **kwargs):
+        """Creates a trust.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-identity-v3-ext.html#createTrust
+        """
+        post_body = json.dumps({'trust': kwargs})
+        resp, body = self.post('OS-TRUST/trusts', post_body)
+        self.expected_success(201, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_trust(self, trust_id):
+        """Deletes a trust."""
+        resp, body = self.delete("OS-TRUST/trusts/%s" % trust_id)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_trusts(self, trustor_user_id=None, trustee_user_id=None):
+        """GET trusts."""
+        if trustor_user_id:
+            resp, body = self.get("OS-TRUST/trusts?trustor_user_id=%s"
+                                  % trustor_user_id)
+        elif trustee_user_id:
+            resp, body = self.get("OS-TRUST/trusts?trustee_user_id=%s"
+                                  % trustee_user_id)
+        else:
+            resp, body = self.get("OS-TRUST/trusts")
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_trust(self, trust_id):
+        """GET trust."""
+        resp, body = self.get("OS-TRUST/trusts/%s" % trust_id)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_trust_roles(self, trust_id):
+        """GET roles delegated by a trust."""
+        resp, body = self.get("OS-TRUST/trusts/%s/roles" % trust_id)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_trust_role(self, trust_id, role_id):
+        """GET role delegated by a trust."""
+        resp, body = self.get("OS-TRUST/trusts/%s/roles/%s"
+                              % (trust_id, role_id))
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_trust_role(self, trust_id, role_id):
+        """HEAD Check if role is delegated by a trust."""
+        resp, body = self.head("OS-TRUST/trusts/%s/roles/%s"
+                               % (trust_id, role_id))
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/users_clients.py b/tempest/services/identity/v3/json/users_clients.py
new file mode 100644
index 0000000..3ab8eab
--- /dev/null
+++ b/tempest/services/identity/v3/json/users_clients.py
@@ -0,0 +1,121 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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 UsersClient(rest_client.RestClient):
+    api_version = "v3"
+
+    def create_user(self, user_name, password=None, project_id=None,
+                    email=None, domain_id='default', **kwargs):
+        """Creates a user."""
+        en = kwargs.get('enabled', True)
+        description = kwargs.get('description', None)
+        default_project_id = kwargs.get('default_project_id')
+        post_body = {
+            'project_id': project_id,
+            'default_project_id': default_project_id,
+            'description': description,
+            'domain_id': domain_id,
+            'email': email,
+            'enabled': en,
+            'name': user_name,
+            'password': password
+        }
+        post_body = json.dumps({'user': post_body})
+        resp, body = self.post('users', post_body)
+        self.expected_success(201, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_user(self, user_id, name, **kwargs):
+        """Updates a user."""
+        body = self.show_user(user_id)['user']
+        email = kwargs.get('email', body['email'])
+        en = kwargs.get('enabled', body['enabled'])
+        project_id = kwargs.get('project_id', body['project_id'])
+        if 'default_project_id' in body.keys():
+            default_project_id = kwargs.get('default_project_id',
+                                            body['default_project_id'])
+        else:
+            default_project_id = kwargs.get('default_project_id')
+        description = kwargs.get('description', body['description'])
+        domain_id = kwargs.get('domain_id', body['domain_id'])
+        post_body = {
+            'name': name,
+            'email': email,
+            'enabled': en,
+            'project_id': project_id,
+            'default_project_id': default_project_id,
+            'id': user_id,
+            'domain_id': domain_id,
+            'description': description
+        }
+        post_body = json.dumps({'user': post_body})
+        resp, body = self.patch('users/%s' % user_id, post_body)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_user_password(self, user_id, **kwargs):
+        """Update a user password
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-identity-v3.html#changeUserPassword
+        """
+        update_user = json.dumps({'user': kwargs})
+        resp, _ = self.post('users/%s/password' % user_id, update_user)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def list_user_projects(self, user_id):
+        """Lists the projects on which a user has roles assigned."""
+        resp, body = self.get('users/%s/projects' % user_id)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_users(self, params=None):
+        """Get the list of users."""
+        url = 'users'
+        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 show_user(self, user_id):
+        """GET a user."""
+        resp, body = self.get("users/%s" % user_id)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_user(self, user_id):
+        """Deletes a User."""
+        resp, body = self.delete("users/%s" % user_id)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_user_groups(self, user_id):
+        """Lists groups which a user belongs to."""
+        resp, body = self.get('users/%s/groups' % user_id)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/image/v1/json/images_client.py b/tempest/services/image/v1/json/images_client.py
index af2e68c..3f256ec 100644
--- a/tempest/services/image/v1/json/images_client.py
+++ b/tempest/services/image/v1/json/images_client.py
@@ -22,36 +22,24 @@
 from oslo_serialization import jsonutils as json
 import six
 from six.moves.urllib import parse as urllib
-from tempest_lib.common.utils import misc as misc_utils
-from tempest_lib import exceptions as lib_exc
 
 from tempest.common import glance_http
-from tempest.common import service_client
 from tempest import exceptions
+from tempest.lib.common import rest_client
+from tempest.lib.common.utils import misc as misc_utils
+from tempest.lib import exceptions as lib_exc
 
 LOG = logging.getLogger(__name__)
 
 
-class ImagesClient(service_client.ServiceClient):
+class ImagesClient(rest_client.RestClient):
 
-    def __init__(self, auth_provider, catalog_type, region, endpoint_type=None,
-                 build_interval=None, build_timeout=None,
-                 disable_ssl_certificate_validation=None,
-                 ca_certs=None, trace_requests=None):
+    def __init__(self, auth_provider, catalog_type, region, **kwargs):
         super(ImagesClient, self).__init__(
-            auth_provider,
-            catalog_type,
-            region,
-            endpoint_type=endpoint_type,
-            build_interval=build_interval,
-            build_timeout=build_timeout,
-            disable_ssl_certificate_validation=(
-                disable_ssl_certificate_validation),
-            ca_certs=ca_certs,
-            trace_requests=trace_requests)
+            auth_provider, catalog_type, region, **kwargs)
         self._http = None
-        self.dscv = disable_ssl_certificate_validation
-        self.ca_certs = ca_certs
+        self.dscv = kwargs.get("disable_ssl_certificate_validation")
+        self.ca_certs = kwargs.get("ca_certs")
 
     def _image_meta_from_headers(self, headers):
         meta = {'properties': {}}
@@ -130,7 +118,7 @@
         self._error_checker('POST', '/v1/images', headers, data, resp,
                             body_iter)
         body = json.loads(''.join([c for c in body_iter]))
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def _update_with_data(self, image_id, headers, data):
         url = '/v1/images/%s' % image_id
@@ -139,7 +127,7 @@
         self._error_checker('PUT', url, headers, data,
                             resp, body_iter)
         body = json.loads(''.join([c for c in body_iter]))
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     @property
     def http(self):
@@ -158,7 +146,7 @@
         resp, body = self.post('v1/images', None, headers)
         self.expected_success(201, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_image(self, image_id, **kwargs):
         headers = {}
@@ -172,13 +160,13 @@
         resp, body = self.put(url, None, headers)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_image(self, image_id):
         url = 'v1/images/%s' % image_id
         resp, body = self.delete(url)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_images(self, detail=False, **kwargs):
         """Return a list of all images filtered by input parameters.
@@ -208,20 +196,20 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def get_image_meta(self, image_id):
         url = 'v1/images/%s' % image_id
         resp, __ = self.head(url)
         self.expected_success(200, resp.status)
         body = self._image_meta_from_headers(resp)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_image(self, image_id):
         url = 'v1/images/%s' % image_id
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBodyData(resp, body)
+        return rest_client.ResponseBodyData(resp, body)
 
     def is_resource_deleted(self, id):
         try:
@@ -240,7 +228,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_shared_images(self, tenant_id):
         """List shared images with the specified tenant"""
@@ -248,7 +236,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def add_member(self, member_id, image_id, **kwargs):
         """Add a member to an image.
@@ -260,13 +248,13 @@
         body = json.dumps({'member': kwargs})
         resp, __ = self.put(url, body)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
+        return rest_client.ResponseBody(resp)
 
     def delete_member(self, member_id, image_id):
         url = 'v1/images/%s/members/%s' % (image_id, member_id)
         resp, __ = self.delete(url)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
+        return rest_client.ResponseBody(resp)
 
     # NOTE(afazekas): just for the wait function
     def _get_image_status(self, image_id):
diff --git a/tempest/services/image/v2/json/images_client.py b/tempest/services/image/v2/json/images_client.py
index 72b203a..4e037af 100644
--- a/tempest/services/image/v2/json/images_client.py
+++ b/tempest/services/image/v2/json/images_client.py
@@ -15,32 +15,20 @@
 
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
-from tempest_lib import exceptions as lib_exc
 
 from tempest.common import glance_http
-from tempest.common import service_client
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
 
 
-class ImagesClientV2(service_client.ServiceClient):
+class ImagesClientV2(rest_client.RestClient):
 
-    def __init__(self, auth_provider, catalog_type, region, endpoint_type=None,
-                 build_interval=None, build_timeout=None,
-                 disable_ssl_certificate_validation=None, ca_certs=None,
-                 trace_requests=None):
+    def __init__(self, auth_provider, catalog_type, region, **kwargs):
         super(ImagesClientV2, self).__init__(
-            auth_provider,
-            catalog_type,
-            region,
-            endpoint_type=endpoint_type,
-            build_interval=build_interval,
-            build_timeout=build_timeout,
-            disable_ssl_certificate_validation=(
-                disable_ssl_certificate_validation),
-            ca_certs=ca_certs,
-            trace_requests=trace_requests)
+            auth_provider, catalog_type, region, **kwargs)
         self._http = None
-        self.dscv = disable_ssl_certificate_validation
-        self.ca_certs = ca_certs
+        self.dscv = kwargs.get("disable_ssl_certificate_validation")
+        self.ca_certs = kwargs.get("ca_certs")
 
     def _get_http(self):
         return glance_http.HTTPClient(auth_provider=self.auth_provider,
@@ -66,7 +54,7 @@
         resp, body = self.patch('v2/images/%s' % image_id, data, headers)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_image(self, **kwargs):
         """Create an image.
@@ -78,25 +66,25 @@
         resp, body = self.post('v2/images', data)
         self.expected_success(201, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def deactivate_image(self, image_id):
         url = 'v2/images/%s/actions/deactivate' % image_id
         resp, body = self.post(url, None)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def reactivate_image(self, image_id):
         url = 'v2/images/%s/actions/reactivate' % image_id
         resp, body = self.post(url, None)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_image(self, image_id):
         url = 'v2/images/%s' % image_id
         resp, _ = self.delete(url)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
+        return rest_client.ResponseBody(resp)
 
     def list_images(self, params=None):
         url = 'v2/images'
@@ -107,14 +95,14 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_image(self, image_id):
         url = 'v2/images/%s' % image_id
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def is_resource_deleted(self, id):
         try:
@@ -134,32 +122,32 @@
         resp, body = self.http.raw_request('PUT', url, headers=headers,
                                            body=data)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_image_file(self, image_id):
         url = 'v2/images/%s/file' % image_id
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBodyData(resp, body)
+        return rest_client.ResponseBodyData(resp, body)
 
     def add_image_tag(self, image_id, tag):
         url = 'v2/images/%s/tags/%s' % (image_id, tag)
         resp, body = self.put(url, body=None)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_image_tag(self, image_id, tag):
         url = 'v2/images/%s/tags/%s' % (image_id, tag)
         resp, _ = self.delete(url)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
+        return rest_client.ResponseBody(resp)
 
     def list_image_members(self, image_id):
         url = 'v2/images/%s/members' % image_id
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_image_member(self, image_id, **kwargs):
         """Create an image member.
@@ -172,7 +160,7 @@
         resp, body = self.post(url, data)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_image_member(self, image_id, member_id, **kwargs):
         """Update an image member.
@@ -185,33 +173,33 @@
         resp, body = self.put(url, data)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_image_member(self, image_id, member_id):
         url = 'v2/images/%s/members/%s' % (image_id, member_id)
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, json.loads(body))
+        return rest_client.ResponseBody(resp, json.loads(body))
 
     def delete_image_member(self, image_id, member_id):
         url = 'v2/images/%s/members/%s' % (image_id, member_id)
         resp, _ = self.delete(url)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
+        return rest_client.ResponseBody(resp)
 
     def show_schema(self, schema):
         url = 'v2/schemas/%s' % schema
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_resource_types(self):
         url = '/v2/metadefs/resource_types'
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_namespace(self, **kwargs):
         """Create a namespace.
@@ -223,14 +211,14 @@
         resp, body = self.post('/v2/metadefs/namespaces', data)
         self.expected_success(201, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_namespace(self, namespace):
         url = '/v2/metadefs/namespaces/%s' % namespace
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_namespace(self, namespace, **kwargs):
         """Update a namespace.
@@ -247,10 +235,10 @@
         resp, body = self.put(url, body=data)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_namespace(self, namespace):
         url = '/v2/metadefs/namespaces/%s' % namespace
         resp, _ = self.delete(url)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
+        return rest_client.ResponseBody(resp)
diff --git a/tempest/services/messaging/__init__.py b/tempest/services/messaging/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/messaging/__init__.py
+++ /dev/null
diff --git a/tempest/services/messaging/json/__init__.py b/tempest/services/messaging/json/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/messaging/json/__init__.py
+++ /dev/null
diff --git a/tempest/services/messaging/json/messaging_client.py b/tempest/services/messaging/json/messaging_client.py
deleted file mode 100644
index 5a43841..0000000
--- a/tempest/services/messaging/json/messaging_client.py
+++ /dev/null
@@ -1,176 +0,0 @@
-# Copyright (c) 2014 Rackspace, Inc.
-#
-# 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 uuid
-
-from oslo_serialization import jsonutils as json
-from six.moves.urllib import parse as urllib
-
-from tempest.api_schema.response.messaging.v1 import queues as queues_schema
-from tempest.common import service_client
-
-
-class MessagingClient(service_client.ServiceClient):
-
-    def __init__(self, auth_provider, service, region,
-                 endpoint_type=None, build_interval=None, build_timeout=None,
-                 disable_ssl_certificate_validation=None, ca_certs=None,
-                 trace_requests=None):
-        dscv = disable_ssl_certificate_validation
-        super(MessagingClient, self).__init__(
-            auth_provider, service, region,
-            endpoint_type=endpoint_type,
-            build_interval=build_interval,
-            build_timeout=build_timeout,
-            disable_ssl_certificate_validation=dscv,
-            ca_certs=ca_certs,
-            trace_requests=trace_requests)
-
-        self.version = '1'
-        self.uri_prefix = 'v{0}'.format(self.version)
-
-        client_id = uuid.uuid4().hex
-        self.headers = {'Client-ID': client_id}
-
-    def list_queues(self):
-        uri = '{0}/queues'.format(self.uri_prefix)
-        resp, body = self.get(uri)
-
-        if resp['status'] != '204':
-            body = json.loads(body)
-            self.validate_response(queues_schema.list_queues, resp, body)
-        return resp, body
-
-    def create_queue(self, queue_name):
-        uri = '{0}/queues/{1}'.format(self.uri_prefix, queue_name)
-        resp, body = self.put(uri, body=None)
-        self.expected_success(201, resp.status)
-        return resp, body
-
-    def show_queue(self, queue_name):
-        uri = '{0}/queues/{1}'.format(self.uri_prefix, queue_name)
-        resp, body = self.get(uri)
-        self.expected_success(204, resp.status)
-        return resp, body
-
-    def head_queue(self, queue_name):
-        uri = '{0}/queues/{1}'.format(self.uri_prefix, queue_name)
-        resp, body = self.head(uri)
-        self.expected_success(204, resp.status)
-        return resp, body
-
-    def delete_queue(self, queue_name):
-        uri = '{0}/queues/{1}'.format(self.uri_prefix, queue_name)
-        resp, body = self.delete(uri)
-        self.expected_success(204, resp.status)
-        return resp, body
-
-    def show_queue_stats(self, queue_name):
-        uri = '{0}/queues/{1}/stats'.format(self.uri_prefix, queue_name)
-        resp, body = self.get(uri)
-        body = json.loads(body)
-        self.validate_response(queues_schema.queue_stats, resp, body)
-        return resp, body
-
-    def show_queue_metadata(self, queue_name):
-        uri = '{0}/queues/{1}/metadata'.format(self.uri_prefix, queue_name)
-        resp, body = self.get(uri)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return resp, body
-
-    def set_queue_metadata(self, queue_name, rbody):
-        uri = '{0}/queues/{1}/metadata'.format(self.uri_prefix, queue_name)
-        resp, body = self.put(uri, body=json.dumps(rbody))
-        self.expected_success(204, resp.status)
-        return resp, body
-
-    def post_messages(self, queue_name, rbody):
-        uri = '{0}/queues/{1}/messages'.format(self.uri_prefix, queue_name)
-        resp, body = self.post(uri, body=json.dumps(rbody),
-                               extra_headers=True,
-                               headers=self.headers)
-
-        body = json.loads(body)
-        self.validate_response(queues_schema.post_messages, resp, body)
-        return resp, body
-
-    def list_messages(self, queue_name):
-        uri = '{0}/queues/{1}/messages?echo=True'.format(self.uri_prefix,
-                                                         queue_name)
-        resp, body = self.get(uri, extra_headers=True, headers=self.headers)
-
-        if resp['status'] != '204':
-            body = json.loads(body)
-            self.validate_response(queues_schema.list_messages, resp, body)
-
-        return resp, body
-
-    def show_single_message(self, message_uri):
-        resp, body = self.get(message_uri, extra_headers=True,
-                              headers=self.headers)
-        if resp['status'] != '204':
-            body = json.loads(body)
-            self.validate_response(queues_schema.get_single_message, resp,
-                                   body)
-        return resp, body
-
-    def show_multiple_messages(self, message_uri):
-        resp, body = self.get(message_uri, extra_headers=True,
-                              headers=self.headers)
-
-        if resp['status'] != '204':
-            body = json.loads(body)
-            self.validate_response(queues_schema.get_multiple_messages,
-                                   resp,
-                                   body)
-
-        return resp, body
-
-    def delete_messages(self, message_uri):
-        resp, body = self.delete(message_uri)
-        self.expected_success(204, resp.status)
-        return resp, body
-
-    def post_claims(self, queue_name, rbody, url_params=False):
-        uri = '{0}/queues/{1}/claims'.format(self.uri_prefix, queue_name)
-        if url_params:
-            uri += '?%s' % urllib.urlencode(url_params)
-
-        resp, body = self.post(uri, body=json.dumps(rbody),
-                               extra_headers=True,
-                               headers=self.headers)
-
-        body = json.loads(body)
-        self.validate_response(queues_schema.claim_messages, resp, body)
-        return resp, body
-
-    def query_claim(self, claim_uri):
-        resp, body = self.get(claim_uri)
-
-        if resp['status'] != '204':
-            body = json.loads(body)
-            self.validate_response(queues_schema.query_claim, resp, body)
-        return resp, body
-
-    def update_claim(self, claim_uri, rbody):
-        resp, body = self.patch(claim_uri, body=json.dumps(rbody))
-        self.expected_success(204, resp.status)
-        return resp, body
-
-    def delete_claim(self, claim_uri):
-        resp, body = self.delete(claim_uri)
-        self.expected_success(204, resp.status)
-        return resp, body
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index c6b22df..bcef36b 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -12,11 +12,10 @@
 
 import time
 
-from tempest_lib.common.utils import misc
-from tempest_lib import exceptions as lib_exc
-
 from tempest import exceptions
-from tempest.services.network.json import base
+from tempest.lib.common.utils import misc
+from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.network import base
 
 
 class NetworkClient(base.BaseNetworkClient):
@@ -35,33 +34,6 @@
     quotas
     """
 
-    def create_bulk_network(self, **kwargs):
-        """create bulk network
-
-        Available params: see http://developer.openstack.org/
-                              api-ref-networking-v2.html#bulkCreateNetwork
-        """
-        uri = '/networks'
-        return self.create_resource(uri, kwargs)
-
-    def create_bulk_subnet(self, **kwargs):
-        """create bulk subnet
-
-        Available params: see http://developer.openstack.org/
-                              api-ref-networking-v2.html#bulkCreateSubnet
-        """
-        uri = '/subnets'
-        return self.create_resource(uri, kwargs)
-
-    def create_bulk_port(self, **kwargs):
-        """create bulk port
-
-        Available params: see http://developer.openstack.org/
-                              api-ref-networking-v2.html#bulkCreatePorts
-        """
-        uri = '/ports'
-        return self.create_resource(uri, kwargs)
-
     def wait_for_resource_deletion(self, resource_type, id, client=None):
         """Waits for a resource to be deleted."""
         start_time = int(time.time())
@@ -121,110 +93,10 @@
             message = '(%s) %s' % (caller, message)
         raise exceptions.TimeoutException(message)
 
-    def create_router(self, name, admin_state_up=True, **kwargs):
-        post_body = {'router': kwargs}
-        post_body['router']['name'] = name
-        post_body['router']['admin_state_up'] = admin_state_up
-        uri = '/routers'
-        return self.create_resource(uri, post_body)
-
-    def _update_router(self, router_id, set_enable_snat, **kwargs):
-        uri = '/routers/%s' % router_id
-        body = self.show_resource(uri)
-        update_body = {}
-        update_body['name'] = kwargs.get('name', body['router']['name'])
-        update_body['admin_state_up'] = kwargs.get(
-            'admin_state_up', body['router']['admin_state_up'])
-        cur_gw_info = body['router']['external_gateway_info']
-        if cur_gw_info:
-            # TODO(kevinbenton): setting the external gateway info is not
-            # allowed for a regular tenant. If the ability to update is also
-            # merged, a test case for this will need to be added similar to
-            # the SNAT case.
-            cur_gw_info.pop('external_fixed_ips', None)
-            if not set_enable_snat:
-                cur_gw_info.pop('enable_snat', None)
-        update_body['external_gateway_info'] = kwargs.get(
-            'external_gateway_info', body['router']['external_gateway_info'])
-        if 'distributed' in kwargs:
-            update_body['distributed'] = kwargs['distributed']
-        update_body = dict(router=update_body)
-        return self.update_resource(uri, update_body)
-
-    def update_router(self, router_id, **kwargs):
-        """Update a router leaving enable_snat to its default value."""
-        # If external_gateway_info contains enable_snat the request will fail
-        # with 404 unless executed with admin client, and therefore we instruct
-        # _update_router to not set this attribute
-        # NOTE(salv-orlando): The above applies as long as Neutron's default
-        # policy is to restrict enable_snat usage to admins only.
-        return self._update_router(router_id, set_enable_snat=False, **kwargs)
-
-    def show_router(self, router_id, **fields):
-        uri = '/routers/%s' % router_id
-        return self.show_resource(uri, **fields)
-
-    def delete_router(self, router_id):
-        uri = '/routers/%s' % router_id
-        return self.delete_resource(uri)
-
-    def list_routers(self, **filters):
-        uri = '/routers'
-        return self.list_resources(uri, **filters)
-
-    def update_router_with_snat_gw_info(self, router_id, **kwargs):
-        """Update a router passing also the enable_snat attribute.
-
-        This method must be execute with admin credentials, otherwise the API
-        call will return a 404 error.
-        """
-        return self._update_router(router_id, set_enable_snat=True, **kwargs)
-
-    def add_router_interface(self, router_id, **kwargs):
-        """Add router interface.
-
-        Available params: see http://developer.openstack.org/
-                              api-ref-networking-v2-ext.html#addRouterInterface
-        """
-        uri = '/routers/%s/add_router_interface' % router_id
-        return self.update_resource(uri, kwargs)
-
-    def remove_router_interface(self, router_id, **kwargs):
-        """Remove router interface.
-
-        Available params: see http://developer.openstack.org/
-                              api-ref-networking-v2-ext.html#removeRouterInterface
-        """
-        uri = '/routers/%s/remove_router_interface' % router_id
-        return self.update_resource(uri, kwargs)
-
     def list_router_interfaces(self, uuid):
         uri = '/ports?device_id=%s' % uuid
         return self.list_resources(uri)
 
-    def list_l3_agents_hosting_router(self, router_id):
-        uri = '/routers/%s/l3-agents' % router_id
-        return self.list_resources(uri)
-
     def list_dhcp_agent_hosting_network(self, network_id):
         uri = '/networks/%s/dhcp-agents' % network_id
         return self.list_resources(uri)
-
-    def update_extra_routes(self, router_id, **kwargs):
-        """Update Extra routes.
-
-        Available params: see http://developer.openstack.org/
-                              api-ref-networking-v2-ext.html#updateExtraRoutes
-        """
-        uri = '/routers/%s' % router_id
-        put_body = {'router': kwargs}
-        return self.update_resource(uri, put_body)
-
-    def delete_extra_routes(self, router_id):
-        uri = '/routers/%s' % router_id
-        put_body = {
-            'router': {
-                'routes': None
-            }
-        }
-        return self.update_resource(uri, put_body)
diff --git a/tempest/services/network/json/routers_client.py b/tempest/services/network/json/routers_client.py
new file mode 100644
index 0000000..18442cf
--- /dev/null
+++ b/tempest/services/network/json/routers_client.py
@@ -0,0 +1,116 @@
+#    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.network import base
+
+
+class RoutersClient(base.BaseNetworkClient):
+
+    def create_router(self, name, admin_state_up=True, **kwargs):
+        post_body = {'router': kwargs}
+        post_body['router']['name'] = name
+        post_body['router']['admin_state_up'] = admin_state_up
+        uri = '/routers'
+        return self.create_resource(uri, post_body)
+
+    def _update_router(self, router_id, set_enable_snat, **kwargs):
+        uri = '/routers/%s' % router_id
+        body = self.show_resource(uri)
+        update_body = {}
+        update_body['name'] = kwargs.get('name', body['router']['name'])
+        update_body['admin_state_up'] = kwargs.get(
+            'admin_state_up', body['router']['admin_state_up'])
+        cur_gw_info = body['router']['external_gateway_info']
+        if cur_gw_info:
+            # TODO(kevinbenton): setting the external gateway info is not
+            # allowed for a regular tenant. If the ability to update is also
+            # merged, a test case for this will need to be added similar to
+            # the SNAT case.
+            cur_gw_info.pop('external_fixed_ips', None)
+            if not set_enable_snat:
+                cur_gw_info.pop('enable_snat', None)
+        update_body['external_gateway_info'] = kwargs.get(
+            'external_gateway_info', body['router']['external_gateway_info'])
+        if 'distributed' in kwargs:
+            update_body['distributed'] = kwargs['distributed']
+        update_body = dict(router=update_body)
+        return self.update_resource(uri, update_body)
+
+    def update_router(self, router_id, **kwargs):
+        """Update a router leaving enable_snat to its default value."""
+        # If external_gateway_info contains enable_snat the request will fail
+        # with 404 unless executed with admin client, and therefore we instruct
+        # _update_router to not set this attribute
+        # NOTE(salv-orlando): The above applies as long as Neutron's default
+        # policy is to restrict enable_snat usage to admins only.
+        return self._update_router(router_id, set_enable_snat=False, **kwargs)
+
+    def show_router(self, router_id, **fields):
+        uri = '/routers/%s' % router_id
+        return self.show_resource(uri, **fields)
+
+    def delete_router(self, router_id):
+        uri = '/routers/%s' % router_id
+        return self.delete_resource(uri)
+
+    def list_routers(self, **filters):
+        uri = '/routers'
+        return self.list_resources(uri, **filters)
+
+    def update_extra_routes(self, router_id, **kwargs):
+        """Update Extra routes.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-networking-v2-ext.html#updateExtraRoutes
+        """
+        uri = '/routers/%s' % router_id
+        put_body = {'router': kwargs}
+        return self.update_resource(uri, put_body)
+
+    def delete_extra_routes(self, router_id):
+        uri = '/routers/%s' % router_id
+        put_body = {
+            'router': {
+                'routes': None
+            }
+        }
+        return self.update_resource(uri, put_body)
+
+    def update_router_with_snat_gw_info(self, router_id, **kwargs):
+        """Update a router passing also the enable_snat attribute.
+
+        This method must be execute with admin credentials, otherwise the API
+        call will return a 404 error.
+        """
+        return self._update_router(router_id, set_enable_snat=True, **kwargs)
+
+    def add_router_interface(self, router_id, **kwargs):
+        """Add router interface.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-networking-v2-ext.html#addRouterInterface
+        """
+        uri = '/routers/%s/add_router_interface' % router_id
+        return self.update_resource(uri, kwargs)
+
+    def remove_router_interface(self, router_id, **kwargs):
+        """Remove router interface.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-networking-v2-ext.html#removeRouterInterface
+        """
+        uri = '/routers/%s/remove_router_interface' % router_id
+        return self.update_resource(uri, kwargs)
+
+    def list_l3_agents_hosting_router(self, router_id):
+        uri = '/routers/%s/l3-agents' % router_id
+        return self.list_resources(uri)
diff --git a/tempest/services/network/json/security_group_rules_client.py b/tempest/services/network/json/security_group_rules_client.py
index b2ba5b2..944eba6 100644
--- a/tempest/services/network/json/security_group_rules_client.py
+++ b/tempest/services/network/json/security_group_rules_client.py
@@ -10,7 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.services.network.json import base
+from tempest.lib.services.network import base
 
 
 class SecurityGroupRulesClient(base.BaseNetworkClient):
diff --git a/tempest/services/network/resources.py b/tempest/services/network/resources.py
index 0a7da92..5512075 100644
--- a/tempest/services/network/resources.py
+++ b/tempest/services/network/resources.py
@@ -39,6 +39,7 @@
         self.client = kwargs.pop('client', None)
         self.network_client = kwargs.pop('network_client', None)
         self.networks_client = kwargs.pop('networks_client', None)
+        self.routers_client = kwargs.pop('routers_client', None)
         self.subnets_client = kwargs.pop('subnets_client', None)
         self.ports_client = kwargs.pop('ports_client', None)
         super(DeletableResource, self).__init__(*args, **kwargs)
@@ -89,12 +90,12 @@
 
     def add_to_router(self, router_id):
         self._router_ids.add(router_id)
-        self.network_client.add_router_interface(router_id,
+        self.routers_client.add_router_interface(router_id,
                                                  subnet_id=self.id)
 
     def delete(self):
         for router_id in self._router_ids.copy():
-            self.network_client.remove_router_interface(router_id,
+            self.routers_client.remove_router_interface(router_id,
                                                         subnet_id=self.id)
             self._router_ids.remove(router_id)
         self.subnets_client.delete_subnet(self.id)
@@ -109,14 +110,14 @@
         return self.update(external_gateway_info=dict())
 
     def update(self, *args, **kwargs):
-        result = self.client.update_router(self.id,
-                                           *args,
-                                           **kwargs)
+        result = self.routers_client.update_router(self.id,
+                                                   *args,
+                                                   **kwargs)
         return super(DeletableRouter, self).update(**result['router'])
 
     def delete(self):
         self.unset_gateway()
-        self.client.delete_router(self.id)
+        self.routers_client.delete_router(self.id)
 
 
 class DeletableFloatingIp(DeletableResource):
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index 2c7fe29..6012a92 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -18,10 +18,10 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class AccountClient(service_client.ServiceClient):
+class AccountClient(rest_client.RestClient):
 
     def create_account(self, data=None,
                        params=None,
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index 73c25db..5a26bfc 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -18,10 +18,10 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class ContainerClient(service_client.ServiceClient):
+class ContainerClient(rest_client.RestClient):
 
     def create_container(
             self, container_name,
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 5890e33..9ad8c27 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -17,10 +17,10 @@
 from six.moves import http_client as httplib
 from six.moves.urllib import parse as urlparse
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class ObjectClient(service_client.ServiceClient):
+class ObjectClient(rest_client.RestClient):
 
     def create_object(self, container, object_name, data,
                       params=None, metadata=None, headers=None):
diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py
index 22e53f5..6019cf5 100644
--- a/tempest/services/orchestration/json/orchestration_client.py
+++ b/tempest/services/orchestration/json/orchestration_client.py
@@ -18,13 +18,13 @@
 
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
-from tempest_lib import exceptions as lib_exc
 
-from tempest.common import service_client
 from tempest import exceptions
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
 
 
-class OrchestrationClient(service_client.ServiceClient):
+class OrchestrationClient(rest_client.RestClient):
 
     def list_stacks(self, params=None):
         """Lists all stacks for a user."""
@@ -36,7 +36,7 @@
         resp, body = self.get(uri)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_stack(self, name, disable_rollback=True, parameters=None,
                      timeout_mins=60, template=None, template_url=None,
@@ -56,7 +56,7 @@
         resp, body = self.post(uri, headers=headers, body=body)
         self.expected_success(201, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_stack(self, stack_identifier, name, disable_rollback=True,
                      parameters=None, timeout_mins=60, template=None,
@@ -75,7 +75,7 @@
         uri = "stacks/%s" % stack_identifier
         resp, body = self.put(uri, headers=headers, body=body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def _prepare_update_create(self, name, disable_rollback=True,
                                parameters=None, timeout_mins=60,
@@ -111,7 +111,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def suspend_stack(self, stack_identifier):
         """Suspend a stack."""
@@ -119,7 +119,7 @@
         body = {'suspend': None}
         resp, body = self.post(url, json.dumps(body))
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp)
+        return rest_client.ResponseBody(resp)
 
     def resume_stack(self, stack_identifier):
         """Resume a stack."""
@@ -127,7 +127,7 @@
         body = {'resume': None}
         resp, body = self.post(url, json.dumps(body))
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp)
+        return rest_client.ResponseBody(resp)
 
     def list_resources(self, stack_identifier):
         """Returns the details of a single resource."""
@@ -135,7 +135,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_resource(self, stack_identifier, resource_name):
         """Returns the details of a single resource."""
@@ -143,13 +143,13 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_stack(self, stack_identifier):
         """Deletes the specified Stack."""
         resp, _ = self.delete("stacks/%s" % str(stack_identifier))
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
+        return rest_client.ResponseBody(resp)
 
     def wait_for_resource_status(self, stack_identifier, resource_name,
                                  status, failure_pattern='^.*_FAILED$'):
@@ -224,7 +224,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_events(self, stack_identifier):
         """Returns list of all events for a stack."""
@@ -232,7 +232,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_resource_events(self, stack_identifier, resource_name):
         """Returns list of all events for a resource from stack."""
@@ -241,7 +241,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_event(self, stack_identifier, resource_name, event_id):
         """Returns the details of a single stack's event."""
@@ -250,7 +250,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_template(self, stack_identifier):
         """Returns the template for the stack."""
@@ -258,7 +258,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def _validate_template(self, post_body):
         """Returns the validation request result."""
@@ -266,7 +266,7 @@
         resp, body = self.post('validate', post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def validate_template(self, template, parameters=None):
         """Returns the validation result for a template with parameters."""
@@ -293,21 +293,21 @@
         resp, body = self.get('resource_types')
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_resource_type(self, resource_type_name):
         """Return the schema of a resource type."""
         url = 'resource_types/%s' % resource_type_name
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, json.loads(body))
+        return rest_client.ResponseBody(resp, json.loads(body))
 
     def show_resource_type_template(self, resource_type_name):
         """Return the template of a resource type."""
         url = 'resource_types/%s/template' % resource_type_name
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, json.loads(body))
+        return rest_client.ResponseBody(resp, json.loads(body))
 
     def create_software_config(self, name=None, config=None, group=None,
                                inputs=None, outputs=None, options=None):
@@ -318,7 +318,7 @@
         resp, body = self.post(url, headers=headers, body=body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_software_config(self, conf_id):
         """Returns a software configuration resource."""
@@ -326,14 +326,14 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_software_config(self, conf_id):
         """Deletes a specific software configuration."""
         url = 'software_configs/%s' % str(conf_id)
         resp, _ = self.delete(url)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
+        return rest_client.ResponseBody(resp)
 
     def create_software_deploy(self, server_id=None, config_id=None,
                                action=None, status=None,
@@ -348,7 +348,7 @@
         resp, body = self.post(url, headers=headers, body=body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_software_deploy(self, deploy_id=None, server_id=None,
                                config_id=None, action=None, status=None,
@@ -363,7 +363,7 @@
         resp, body = self.put(url, headers=headers, body=body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_software_deployments(self):
         """Returns a list of all deployments."""
@@ -371,7 +371,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_software_deployment(self, deploy_id):
         """Returns a specific software deployment."""
@@ -379,7 +379,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_software_deployment_metadata(self, server_id):
         """Return a config metadata for a specific server."""
@@ -387,14 +387,14 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_software_deploy(self, deploy_id):
         """Deletes a specific software deployment."""
         url = 'software_deployments/%s' % str(deploy_id)
         resp, _ = self.delete(url)
         self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp)
+        return rest_client.ResponseBody(resp)
 
     def _prep_software_config_create(self, name=None, conf=None, group=None,
                                      inputs=None, outputs=None, options=None):
diff --git a/tempest/services/telemetry/json/alarming_client.py b/tempest/services/telemetry/json/alarming_client.py
index ce14211..703efdf 100644
--- a/tempest/services/telemetry/json/alarming_client.py
+++ b/tempest/services/telemetry/json/alarming_client.py
@@ -16,10 +16,10 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class AlarmingClient(service_client.ServiceClient):
+class AlarmingClient(rest_client.RestClient):
 
     version = '2'
     uri_prefix = "v2"
@@ -42,21 +42,21 @@
         resp, body = self.get(uri)
         self.expected_success(200, resp.status)
         body = self.deserialize(body)
-        return service_client.ResponseBodyList(resp, body)
+        return rest_client.ResponseBodyList(resp, body)
 
     def show_alarm(self, alarm_id):
         uri = '%s/alarms/%s' % (self.uri_prefix, alarm_id)
         resp, body = self.get(uri)
         self.expected_success(200, resp.status)
         body = self.deserialize(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_alarm_history(self, alarm_id):
         uri = "%s/alarms/%s/history" % (self.uri_prefix, alarm_id)
         resp, body = self.get(uri)
         self.expected_success(200, resp.status)
         body = self.deserialize(body)
-        return service_client.ResponseBodyList(resp, body)
+        return rest_client.ResponseBodyList(resp, body)
 
     def delete_alarm(self, alarm_id):
         uri = "%s/alarms/%s" % (self.uri_prefix, alarm_id)
@@ -64,7 +64,7 @@
         self.expected_success(204, resp.status)
         if body:
             body = self.deserialize(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_alarm(self, **kwargs):
         uri = "%s/alarms" % self.uri_prefix
@@ -72,7 +72,7 @@
         resp, body = self.post(uri, body)
         self.expected_success(201, resp.status)
         body = self.deserialize(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_alarm(self, alarm_id, **kwargs):
         uri = "%s/alarms/%s" % (self.uri_prefix, alarm_id)
@@ -80,14 +80,14 @@
         resp, body = self.put(uri, body)
         self.expected_success(200, resp.status)
         body = self.deserialize(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_alarm_state(self, alarm_id):
         uri = "%s/alarms/%s/state" % (self.uri_prefix, alarm_id)
         resp, body = self.get(uri)
         self.expected_success(200, resp.status)
         body = self.deserialize(body)
-        return service_client.ResponseBodyData(resp, body)
+        return rest_client.ResponseBodyData(resp, body)
 
     def alarm_set_state(self, alarm_id, state):
         uri = "%s/alarms/%s/state" % (self.uri_prefix, alarm_id)
@@ -95,4 +95,4 @@
         resp, body = self.put(uri, body)
         self.expected_success(200, resp.status)
         body = self.deserialize(body)
-        return service_client.ResponseBodyData(resp, body)
+        return rest_client.ResponseBodyData(resp, body)
diff --git a/tempest/services/telemetry/json/telemetry_client.py b/tempest/services/telemetry/json/telemetry_client.py
index abdeba2..df7d916 100644
--- a/tempest/services/telemetry/json/telemetry_client.py
+++ b/tempest/services/telemetry/json/telemetry_client.py
@@ -16,10 +16,10 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class TelemetryClient(service_client.ServiceClient):
+class TelemetryClient(rest_client.RestClient):
 
     version = '2'
     uri_prefix = "v2"
@@ -36,7 +36,7 @@
         resp, body = self.post(uri, body)
         self.expected_success(200, resp.status)
         body = self.deserialize(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def _helper_list(self, uri, query=None, period=None):
         uri_dict = {}
@@ -51,7 +51,7 @@
         resp, body = self.get(uri)
         self.expected_success(200, resp.status)
         body = self.deserialize(body)
-        return service_client.ResponseBodyList(resp, body)
+        return rest_client.ResponseBodyList(resp, body)
 
     def list_resources(self, query=None):
         uri = '%s/resources' % self.uri_prefix
@@ -78,4 +78,4 @@
         resp, body = self.get(uri)
         self.expected_success(200, resp.status)
         body = self.deserialize(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/admin/base_hosts_client.py b/tempest/services/volume/base/admin/base_hosts_client.py
index 074f87f..382e9a8 100644
--- a/tempest/services/volume/base/admin/base_hosts_client.py
+++ b/tempest/services/volume/base/admin/base_hosts_client.py
@@ -16,10 +16,10 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class BaseHostsClient(service_client.ServiceClient):
+class BaseHostsClient(rest_client.RestClient):
     """Client class to send CRUD Volume Hosts API requests"""
 
     def list_hosts(self, **params):
@@ -32,4 +32,4 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/admin/base_quotas_client.py b/tempest/services/volume/base/admin/base_quotas_client.py
index e063a31..83816f2 100644
--- a/tempest/services/volume/base/admin/base_quotas_client.py
+++ b/tempest/services/volume/base/admin/base_quotas_client.py
@@ -15,10 +15,10 @@
 from oslo_serialization import jsonutils
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class BaseQuotasClient(service_client.ServiceClient):
+class BaseQuotasClient(rest_client.RestClient):
     """Client class to send CRUD Volume Quotas API requests"""
 
     TYPE = "json"
@@ -30,7 +30,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = jsonutils.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_quota_set(self, tenant_id, params=None):
         """List the quota set for a tenant."""
@@ -42,7 +42,7 @@
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = jsonutils.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_quota_usage(self, tenant_id):
         """List the quota set for a tenant."""
@@ -60,10 +60,10 @@
         resp, body = self.put('os-quota-sets/%s' % tenant_id, put_body)
         self.expected_success(200, resp.status)
         body = jsonutils.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_quota_set(self, tenant_id):
         """Delete the tenant's quota set."""
         resp, body = self.delete('os-quota-sets/%s' % tenant_id)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/admin/base_services_client.py b/tempest/services/volume/base/admin/base_services_client.py
index 3626469..861eb92 100644
--- a/tempest/services/volume/base/admin/base_services_client.py
+++ b/tempest/services/volume/base/admin/base_services_client.py
@@ -16,10 +16,10 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class BaseServicesClient(service_client.ServiceClient):
+class BaseServicesClient(rest_client.RestClient):
 
     def list_services(self, **params):
         url = 'os-services'
@@ -29,4 +29,4 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/admin/base_types_client.py b/tempest/services/volume/base/admin/base_types_client.py
index 867273e..95ddff6 100644
--- a/tempest/services/volume/base/admin/base_types_client.py
+++ b/tempest/services/volume/base/admin/base_types_client.py
@@ -15,12 +15,12 @@
 
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
-from tempest_lib import exceptions as lib_exc
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
 
 
-class BaseTypesClient(service_client.ServiceClient):
+class BaseTypesClient(rest_client.RestClient):
     """Client class to send CRUD Volume Types API requests"""
 
     def is_resource_deleted(self, resource):
@@ -56,7 +56,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_volume_type(self, volume_id):
         """Returns the details of a single volume_type."""
@@ -64,7 +64,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_volume_type(self, **kwargs):
         """Create volume type.
@@ -76,13 +76,13 @@
         resp, body = self.post('types', post_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_volume_type(self, volume_id):
         """Deletes the Specified Volume_type."""
         resp, body = self.delete("types/%s" % str(volume_id))
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_volume_types_extra_specs(self, vol_type_id, **params):
         """List all the volume_types extra specs created.
@@ -100,7 +100,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_volume_type_extra_specs(self, vol_type_id, extra_specs_name):
         """Returns the details of a single volume_type extra spec."""
@@ -109,7 +109,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_volume_type_extra_specs(self, vol_type_id, extra_specs):
         """Creates a new Volume_type extra spec.
@@ -122,14 +122,14 @@
         resp, body = self.post(url, post_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_volume_type_extra_specs(self, vol_id, extra_spec_name):
         """Deletes the Specified Volume_type extra spec."""
         resp, body = self.delete("types/%s/extra_specs/%s" % (
             (str(vol_id)), str(extra_spec_name)))
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_volume_type_extra_specs(self, vol_type_id, extra_spec_name,
                                        extra_specs):
@@ -146,7 +146,7 @@
         resp, body = self.put(url, put_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_encryption_type(self, vol_type_id):
         """Get the volume encryption type for the specified volume type.
@@ -157,7 +157,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_encryption_type(self, vol_type_id, **kwargs):
         """Create encryption type.
@@ -171,11 +171,11 @@
         resp, body = self.post(url, post_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_encryption_type(self, vol_type_id):
         """Delete the encryption type for the specified volume-type."""
         resp, body = self.delete(
             "/types/%s/encryption/provider" % str(vol_type_id))
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/base_availability_zone_client.py b/tempest/services/volume/base/base_availability_zone_client.py
index b63fdc2..1c2deba 100644
--- a/tempest/services/volume/base/base_availability_zone_client.py
+++ b/tempest/services/volume/base/base_availability_zone_client.py
@@ -15,13 +15,13 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class BaseAvailabilityZoneClient(service_client.ServiceClient):
+class BaseAvailabilityZoneClient(rest_client.RestClient):
 
     def list_availability_zones(self):
         resp, body = self.get('os-availability-zone')
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/base_backups_client.py b/tempest/services/volume/base/base_backups_client.py
index fc9a40a..780da7b 100644
--- a/tempest/services/volume/base/base_backups_client.py
+++ b/tempest/services/volume/base/base_backups_client.py
@@ -16,13 +16,13 @@
 import time
 
 from oslo_serialization import jsonutils as json
-from tempest_lib import exceptions as lib_exc
 
-from tempest.common import service_client
 from tempest import exceptions
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
 
 
-class BaseBackupsClient(service_client.ServiceClient):
+class BaseBackupsClient(rest_client.RestClient):
     """Client class to send CRUD Volume backup API requests"""
 
     def create_backup(self, **kwargs):
@@ -31,7 +31,7 @@
         resp, body = self.post('backups', post_body)
         body = json.loads(body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def restore_backup(self, backup_id, **kwargs):
         """Restore volume from backup."""
@@ -39,13 +39,13 @@
         resp, body = self.post('backups/%s/restore' % (backup_id), post_body)
         body = json.loads(body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_backup(self, backup_id):
         """Delete a backup of volume."""
         resp, body = self.delete('backups/%s' % (str(backup_id)))
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_backup(self, backup_id):
         """Returns the details of a single backup."""
@@ -53,7 +53,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_backups(self, detail=False):
         """Information for all the tenant's backups."""
@@ -63,7 +63,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def export_backup(self, backup_id):
         """Export backup metadata record."""
@@ -71,7 +71,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def import_backup(self, **kwargs):
         """Import backup metadata record."""
@@ -79,7 +79,7 @@
         resp, body = self.post("backups/import_record", post_body)
         body = json.loads(body)
         self.expected_success(201, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def wait_for_backup_status(self, backup_id, status):
         """Waits for a Backup to reach a given status."""
diff --git a/tempest/services/volume/base/base_extensions_client.py b/tempest/services/volume/base/base_extensions_client.py
index afc3f6b..b90fe94 100644
--- a/tempest/services/volume/base/base_extensions_client.py
+++ b/tempest/services/volume/base/base_extensions_client.py
@@ -15,14 +15,14 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.common import service_client
+from tempest.lib.common import rest_client
 
 
-class BaseExtensionsClient(service_client.ServiceClient):
+class BaseExtensionsClient(rest_client.RestClient):
 
     def list_extensions(self):
         url = 'extensions'
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/base_qos_client.py b/tempest/services/volume/base/base_qos_client.py
index 697e902..2d9f02a 100644
--- a/tempest/services/volume/base/base_qos_client.py
+++ b/tempest/services/volume/base/base_qos_client.py
@@ -15,13 +15,13 @@
 import time
 
 from oslo_serialization import jsonutils as json
-from tempest_lib import exceptions as lib_exc
 
-from tempest.common import service_client
 from tempest import exceptions
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
 
 
-class BaseQosSpecsClient(service_client.ServiceClient):
+class BaseQosSpecsClient(rest_client.RestClient):
     """Client class to send CRUD QoS API requests"""
 
     def is_resource_deleted(self, qos_id):
@@ -77,14 +77,14 @@
         resp, body = self.post('qos-specs', post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_qos(self, qos_id, force=False):
         """Delete the specified QoS specification."""
         resp, body = self.delete(
             "qos-specs/%s?force=%s" % (str(qos_id), force))
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_qos(self):
         """List all the QoS specifications created."""
@@ -92,7 +92,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_qos(self, qos_id):
         """Get the specified QoS specification."""
@@ -100,7 +100,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def set_qos_key(self, qos_id, **kwargs):
         """Set the specified keys/values of QoS specification.
@@ -112,7 +112,7 @@
         resp, body = self.put('qos-specs/%s' % qos_id, put_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def unset_qos_key(self, qos_id, keys):
         """Unset the specified keys of QoS specification.
@@ -124,7 +124,7 @@
         put_body = json.dumps({'keys': keys})
         resp, body = self.put('qos-specs/%s/delete_keys' % qos_id, put_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def associate_qos(self, qos_id, vol_type_id):
         """Associate the specified QoS with specified volume-type."""
@@ -132,7 +132,7 @@
         url += "?vol_type_id=%s" % vol_type_id
         resp, body = self.get(url)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_association_qos(self, qos_id):
         """Get the association of the specified QoS specification."""
@@ -140,7 +140,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def disassociate_qos(self, qos_id, vol_type_id):
         """Disassociate the specified QoS with specified volume-type."""
@@ -148,11 +148,11 @@
         url += "?vol_type_id=%s" % vol_type_id
         resp, body = self.get(url)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def disassociate_all_qos(self, qos_id):
         """Disassociate the specified QoS with all associations."""
         url = "qos-specs/%s/disassociate_all" % str(qos_id)
         resp, body = self.get(url)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/base_snapshots_client.py b/tempest/services/volume/base/base_snapshots_client.py
index 1388e9c..5e5637a 100644
--- a/tempest/services/volume/base/base_snapshots_client.py
+++ b/tempest/services/volume/base/base_snapshots_client.py
@@ -15,16 +15,16 @@
 from oslo_log import log as logging
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
-from tempest_lib import exceptions as lib_exc
 
-from tempest.common import service_client
 from tempest import exceptions
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
 
 
 LOG = logging.getLogger(__name__)
 
 
-class BaseSnapshotsClient(service_client.ServiceClient):
+class BaseSnapshotsClient(rest_client.RestClient):
     """Base Client class to send CRUD Volume API requests."""
 
     create_resp = 200
@@ -40,7 +40,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_snapshot(self, snapshot_id):
         """Returns the details of a single snapshot."""
@@ -48,7 +48,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_snapshot(self, **kwargs):
         """Creates a new snapshot.
@@ -60,7 +60,7 @@
         resp, body = self.post('snapshots', post_body)
         body = json.loads(body)
         self.expected_success(self.create_resp, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_snapshot(self, snapshot_id, **kwargs):
         """Updates a snapshot."""
@@ -68,7 +68,7 @@
         resp, body = self.put('snapshots/%s' % snapshot_id, put_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     # NOTE(afazekas): just for the wait function
     def _get_snapshot_status(self, snapshot_id):
@@ -111,7 +111,7 @@
         """Delete Snapshot."""
         resp, body = self.delete("snapshots/%s" % str(snapshot_id))
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def is_resource_deleted(self, id):
         try:
@@ -130,7 +130,7 @@
         post_body = json.dumps({'os-reset_status': {"status": status}})
         resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_snapshot_status(self, snapshot_id, **kwargs):
         """Update the specified snapshot's status."""
@@ -143,7 +143,7 @@
         url = 'snapshots/%s/action' % str(snapshot_id)
         resp, body = self.post(url, post_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_snapshot_metadata(self, snapshot_id, metadata):
         """Create metadata for the snapshot."""
@@ -152,7 +152,7 @@
         resp, body = self.post(url, put_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_snapshot_metadata(self, snapshot_id):
         """Get metadata of the snapshot."""
@@ -160,7 +160,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_snapshot_metadata(self, snapshot_id, **kwargs):
         """Update metadata for the snapshot."""
@@ -173,7 +173,7 @@
         resp, body = self.put(url, put_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_snapshot_metadata_item(self, snapshot_id, id, **kwargs):
         """Update metadata item for the snapshot."""
@@ -186,18 +186,18 @@
         resp, body = self.put(url, put_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_snapshot_metadata_item(self, snapshot_id, id):
         """Delete metadata item for the snapshot."""
         url = "snapshots/%s/metadata/%s" % (str(snapshot_id), str(id))
         resp, body = self.delete(url)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def force_delete_snapshot(self, snapshot_id):
         """Force Delete Snapshot."""
         post_body = json.dumps({'os-force_delete': {}})
         resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/base_volumes_client.py b/tempest/services/volume/base/base_volumes_client.py
index d4435bc..f638bb6 100644
--- a/tempest/services/volume/base/base_volumes_client.py
+++ b/tempest/services/volume/base/base_volumes_client.py
@@ -16,13 +16,13 @@
 from oslo_serialization import jsonutils as json
 import six
 from six.moves.urllib import parse as urllib
-from tempest_lib import exceptions as lib_exc
 
-from tempest.common import service_client
 from tempest.common import waiters
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
 
 
-class BaseVolumesClient(service_client.ServiceClient):
+class BaseVolumesClient(rest_client.RestClient):
     """Base client class to send CRUD Volume API requests"""
 
     create_resp = 200
@@ -61,7 +61,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_volume(self, volume_id):
         """Returns the details of a single volume."""
@@ -69,7 +69,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_volume(self, **kwargs):
         """Creates a new Volume.
@@ -83,7 +83,7 @@
         resp, body = self.post('volumes', post_body)
         body = json.loads(body)
         self.expected_success(self.create_resp, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_volume(self, volume_id, **kwargs):
         """Updates the Specified Volume."""
@@ -91,13 +91,13 @@
         resp, body = self.put('volumes/%s' % volume_id, put_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_volume(self, volume_id):
         """Deletes the Specified Volume."""
         resp, body = self.delete("volumes/%s" % str(volume_id))
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def upload_volume(self, volume_id, **kwargs):
         """Uploads a volume in Glance."""
@@ -106,7 +106,7 @@
         resp, body = self.post(url, post_body)
         body = json.loads(body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def attach_volume(self, volume_id, **kwargs):
         """Attaches a volume to a given instance on a given mountpoint."""
@@ -114,7 +114,7 @@
         url = 'volumes/%s/action' % (volume_id)
         resp, body = self.post(url, post_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def set_bootable_volume(self, volume_id, **kwargs):
         """set a bootable flag for a volume - true or false."""
@@ -122,7 +122,7 @@
         url = 'volumes/%s/action' % (volume_id)
         resp, body = self.post(url, post_body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def detach_volume(self, volume_id):
         """Detaches a volume from an instance."""
@@ -130,7 +130,7 @@
         url = 'volumes/%s/action' % (volume_id)
         resp, body = self.post(url, post_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def reserve_volume(self, volume_id):
         """Reserves a volume."""
@@ -138,7 +138,7 @@
         url = 'volumes/%s/action' % (volume_id)
         resp, body = self.post(url, post_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def unreserve_volume(self, volume_id):
         """Restore a reserved volume ."""
@@ -146,7 +146,7 @@
         url = 'volumes/%s/action' % (volume_id)
         resp, body = self.post(url, post_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def wait_for_volume_status(self, volume_id, status):
         """Waits for a Volume to reach a given status."""
@@ -170,14 +170,14 @@
         url = 'volumes/%s/action' % (volume_id)
         resp, body = self.post(url, post_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def reset_volume_status(self, volume_id, **kwargs):
         """Reset the Specified Volume's Status."""
         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 service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def volume_begin_detaching(self, volume_id):
         """Volume Begin Detaching."""
@@ -185,7 +185,7 @@
         post_body = json.dumps({'os-begin_detaching': {}})
         resp, body = self.post('volumes/%s/action' % volume_id, post_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def volume_roll_detaching(self, volume_id):
         """Volume Roll Detaching."""
@@ -193,7 +193,7 @@
         post_body = json.dumps({'os-roll_detaching': {}})
         resp, body = self.post('volumes/%s/action' % volume_id, post_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_volume_transfer(self, **kwargs):
         """Create a volume transfer."""
@@ -201,7 +201,7 @@
         resp, body = self.post('os-volume-transfer', post_body)
         body = json.loads(body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_volume_transfer(self, transfer_id):
         """Returns the details of a volume transfer."""
@@ -209,7 +209,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def list_volume_transfers(self, **params):
         """List all the volume transfers created."""
@@ -219,13 +219,13 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        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" % str(transfer_id))
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def accept_volume_transfer(self, transfer_id, **kwargs):
         """Accept a volume transfer."""
@@ -234,7 +234,7 @@
         resp, body = self.post(url, post_body)
         body = json.loads(body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_volume_readonly(self, volume_id, **kwargs):
         """Update the Specified Volume readonly."""
@@ -242,14 +242,14 @@
         url = 'volumes/%s/action' % (volume_id)
         resp, body = self.post(url, post_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def force_delete_volume(self, volume_id):
         """Force Delete Volume."""
         post_body = json.dumps({'os-force_delete': {}})
         resp, body = self.post('volumes/%s/action' % volume_id, post_body)
         self.expected_success(202, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def create_volume_metadata(self, volume_id, metadata):
         """Create metadata for the volume."""
@@ -258,7 +258,7 @@
         resp, body = self.post(url, put_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def show_volume_metadata(self, volume_id):
         """Get metadata of the volume."""
@@ -266,7 +266,7 @@
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_volume_metadata(self, volume_id, metadata):
         """Update metadata for the volume."""
@@ -275,7 +275,7 @@
         resp, body = self.put(url, put_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def update_volume_metadata_item(self, volume_id, id, meta_item):
         """Update metadata item for the volume."""
@@ -284,14 +284,14 @@
         resp, body = self.put(url, put_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def delete_volume_metadata_item(self, volume_id, id):
         """Delete metadata item for the volume."""
         url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
         resp, body = self.delete(url)
         self.expected_success(200, resp.status)
-        return service_client.ResponseBody(resp, body)
+        return rest_client.ResponseBody(resp, body)
 
     def retype_volume(self, volume_id, **kwargs):
         """Updates volume with new volume type."""
diff --git a/tempest/stress/__init__.py b/tempest/stress/__init__.py
index e69de29..987a023 100644
--- a/tempest/stress/__init__.py
+++ b/tempest/stress/__init__.py
@@ -0,0 +1,22 @@
+# 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 warnings
+
+warnings.simplefilter('once', category=DeprecationWarning)
+warnings.warn(
+    'Stress tests are deprecated and will be removed from Tempest '
+    'in the Newton release.',
+    DeprecationWarning)
+warnings.resetwarnings()
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index 1f9df5e..382b851 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -21,7 +21,6 @@
 from oslo_utils import importutils
 import six
 from six import moves
-from tempest_lib.common import ssh
 
 
 from tempest import clients
@@ -30,6 +29,7 @@
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
+from tempest.lib.common import ssh
 from tempest.stress import cleanup
 
 CONF = config.CONF
@@ -149,16 +149,18 @@
                     projects_client = admin_manager.tenants_client
                     roles_client = admin_manager.roles_client
                     users_client = admin_manager.users_client
+                    domains_client = None
                 else:
                     identity_client = admin_manager.identity_v3_client
                     projects_client = admin_manager.projects_client
-                    roles_client = None
-                    users_client = None
+                    roles_client = admin_manager.roles_v3_client
+                    users_client = admin_manager.users_v3_client
+                    domains_client = admin_manager.domains_client
                 domain = (identity_client.auth_provider.credentials.
                           get('project_domain_name', 'Default'))
                 credentials_client = cred_client.get_creds_client(
-                    identity_client, projects_client, roles_client,
-                    users_client, project_domain_name=domain)
+                    identity_client, projects_client, users_client,
+                    roles_client, domains_client, project_domain_name=domain)
                 project = credentials_client.create_project(
                     name=tenant_name, description=tenant_name)
                 user = credentials_client.create_user(username, password,
diff --git a/tempest/stress/stressaction.py b/tempest/stress/stressaction.py
index c8bd652..cf0a08a 100644
--- a/tempest/stress/stressaction.py
+++ b/tempest/stress/stressaction.py
@@ -85,8 +85,8 @@
             finally:
                 shared_statistic['runs'] += 1
                 if self.stop_on_error and (shared_statistic['fails'] > 1):
-                    self.logger.warn("Stop process due to"
-                                     "\"stop-on-error\" argument")
+                    self.logger.warning("Stop process due to"
+                                        "\"stop-on-error\" argument")
                     self.tearDown()
                     sys.exit(1)
 
diff --git a/tempest/test.py b/tempest/test.py
index 6a0095f..fe3c770 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -27,7 +27,6 @@
 from oslo_utils import importutils
 import six
 from six.moves import urllib
-from tempest_lib import decorators
 import testscenarios
 import testtools
 
@@ -39,6 +38,7 @@
 import tempest.common.validation_resources as vresources
 from tempest import config
 from tempest import exceptions
+from tempest.lib import decorators
 
 LOG = logging.getLogger(__name__)
 
@@ -180,6 +180,19 @@
     return False
 
 
+def is_scheduler_filter_enabled(filter_name):
+    """Check the list of enabled compute scheduler filters from config. """
+
+    filters = CONF.compute_feature_enabled.scheduler_available_filters
+    if len(filters) == 0:
+        return False
+    if 'all' in filters:
+        return True
+    if filter_name in filters:
+        return True
+    return False
+
+
 at_exit_set = set()
 
 
@@ -226,7 +239,6 @@
     # Resources required to validate a server using ssh
     validation_resources = {}
     network_resources = {}
-    services_microversion = {}
 
     # NOTE(sdague): log_format is defined inline here instead of using the oslo
     # default because going through the config path recouples config to the
@@ -234,6 +246,12 @@
     log_format = ('%(asctime)s %(process)d %(levelname)-8s '
                   '[%(name)s] %(message)s')
 
+    # Client manager class to use in this test case.
+    client_manager = clients.Manager
+
+    # A way to adjust slow test classes
+    TIMEOUT_SCALING_FACTOR = 1
+
     @classmethod
     def setUpClass(cls):
         # It should never be overridden by descendants
@@ -404,7 +422,7 @@
         at_exit_set.add(self.__class__)
         test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
         try:
-            test_timeout = int(test_timeout)
+            test_timeout = int(test_timeout) * self.TIMEOUT_SCALING_FACTOR
         except ValueError:
             test_timeout = 0
         if test_timeout > 0:
@@ -437,14 +455,16 @@
         """
         if CONF.identity.auth_version == 'v2':
             client = self.os_admin.identity_client
+            users_client = self.os_admin.users_client
             project_client = self.os_admin.tenants_client
             roles_client = self.os_admin.roles_client
-            users_client = self.os_admin.users_client
+            domains_client = None
         else:
             client = self.os_admin.identity_v3_client
-            project_client = self.os_adm.projects_client
-            roles_client = None
-            users_client = None
+            users_client = self.os_admin.users_v3_client
+            project_client = self.os_admin.projects_client
+            roles_client = self.os_admin.roles_v3_client
+            domains_client = self.os_admin.domains_client
 
         try:
             domain = client.auth_provider.credentials.project_domain_name
@@ -452,8 +472,9 @@
             domain = 'Default'
 
         return cred_client.get_creds_client(client, project_client,
-                                            roles_client,
                                             users_client,
+                                            roles_client,
+                                            domains_client,
                                             project_domain_name=domain)
 
     @classmethod
@@ -519,8 +540,7 @@
             else:
                 raise exceptions.InvalidCredentials(
                     "Invalid credentials type %s" % credential_type)
-        return clients.Manager(credentials=creds, service=cls._service,
-                               api_microversions=cls.services_microversion)
+        return cls.client_manager(credentials=creds, service=cls._service)
 
     @classmethod
     def clear_credentials(cls):
@@ -607,8 +627,7 @@
                 credentials.is_admin_available(
                     identity_version=cls.get_identity_version())):
             admin_creds = cred_provider.get_admin_creds()
-            admin_manager = clients.Manager(
-                admin_creds, api_microversions=cls.services_microversion)
+            admin_manager = clients.Manager(admin_creds)
             networks_client = admin_manager.compute_networks_client
         return fixed_network.get_tenant_network(
             cred_provider, networks_client, CONF.compute.fixed_network_name)
diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py
index 108b50d..d604b28 100644
--- a/tempest/test_discover/plugins.py
+++ b/tempest/test_discover/plugins.py
@@ -17,8 +17,8 @@
 
 import six
 import stevedore
-from tempest_lib.common.utils import misc
 
+from tempest.lib.common.utils import misc
 
 LOG = logging.getLogger(__name__)
 
diff --git a/tempest/tests/cmd/test_javelin.py b/tempest/tests/cmd/test_javelin.py
index ab6a7a0..dc7b434 100644
--- a/tempest/tests/cmd/test_javelin.py
+++ b/tempest/tests/cmd/test_javelin.py
@@ -14,9 +14,9 @@
 
 import mock
 from oslotest import mockpatch
-from tempest_lib import exceptions as lib_exc
 
 from tempest.cmd import javelin
+from tempest.lib import exceptions as lib_exc
 from tempest.tests import base
 
 
@@ -250,7 +250,7 @@
 
     def test_create_router(self):
 
-        self.fake_client.networks.list_routers.return_value = {'routers': []}
+        self.fake_client.routers.list_routers.return_value = {'routers': []}
         self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
                                               return_value=self.fake_client))
 
@@ -260,7 +260,7 @@
         mocked_function.assert_called_once_with(self.fake_object['name'])
 
     def test_create_router_existing(self):
-        self.fake_client.networks.list_routers.return_value = {
+        self.fake_client.routers.list_routers.return_value = {
             'routers': [self.fake_object]}
         self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
                                               return_value=self.fake_client))
@@ -405,7 +405,7 @@
 
         javelin.destroy_routers([self.fake_object])
 
-        mocked_function = self.fake_client.networks.delete_router
+        mocked_function = self.fake_client.routers.delete_router
         mocked_function.assert_called_once_with(
             self.fake_object['router_id'])
 
diff --git a/tempest/tests/common/test_configured_creds.py b/tempest/tests/common/test_configured_creds.py
index 96b75fd..be24595 100644
--- a/tempest/tests/common/test_configured_creds.py
+++ b/tempest/tests/common/test_configured_creds.py
@@ -13,14 +13,14 @@
 #    under the License.
 
 from oslo_config import cfg
-from tempest_lib import auth
-from tempest_lib import exceptions as lib_exc
-from tempest_lib.services.identity.v2 import token_client as v2_client
-from tempest_lib.services.identity.v3 import token_client as v3_client
 
 from tempest.common import credentials_factory as common_creds
 from tempest.common import tempest_fixtures as fixtures
 from tempest import config
+from tempest.lib import auth
+from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.identity.v2 import token_client as v2_client
+from tempest.lib.services.identity.v3 import token_client as v3_client
 from tempest.tests import base
 from tempest.tests import fake_config
 from tempest.tests import fake_identity
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index 7a21d96..be4a6ee 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -15,13 +15,13 @@
 import mock
 from oslo_config import cfg
 from oslotest import mockpatch
-from tempest_lib.services.identity.v2 import token_client as json_token_client
 
 from tempest.common import credentials_factory as credentials
 from tempest.common import dynamic_creds
-from tempest.common import service_client
 from tempest import config
 from tempest import exceptions
+from tempest.lib.common import rest_client
+from tempest.lib.services.identity.v2 import token_client as json_token_client
 from tempest.services.identity.v2.json import identity_client as \
     json_iden_client
 from tempest.services.identity.v2.json import roles_client as \
@@ -31,6 +31,7 @@
 from tempest.services.identity.v2.json import users_client as \
     json_users_client
 from tempest.services.network.json import network_client as json_network_client
+from tempest.services.network.json import routers_client
 from tempest.tests import base
 from tempest.tests import fake_config
 from tempest.tests import fake_http
@@ -74,7 +75,7 @@
         user_fix = self.useFixture(mockpatch.PatchObject(
             json_users_client.UsersClient,
             'create_user',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200, {'user': {'id': id, 'name': name}}))))
         return user_fix
 
@@ -82,7 +83,7 @@
         tenant_fix = self.useFixture(mockpatch.PatchObject(
             json_tenants_client.TenantsClient,
             'create_tenant',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200, {'tenant': {'id': id, 'name': name}}))))
         return tenant_fix
 
@@ -90,7 +91,7 @@
         roles_fix = self.useFixture(mockpatch.PatchObject(
             json_roles_client.RolesClient,
             'list_roles',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200,
                            {'roles': [{'id': id, 'name': name},
                             {'id': '1', 'name': 'FakeRole'},
@@ -101,7 +102,7 @@
         roles_fix = self.useFixture(mockpatch.PatchObject(
             json_roles_client.RolesClient,
             'list_roles',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200,
                            {'roles': [{'id': '1234', 'name': 'role1'},
                             {'id': '1', 'name': 'FakeRole'},
@@ -112,7 +113,7 @@
         tenant_fix = self.useFixture(mockpatch.PatchObject(
             json_roles_client.RolesClient,
             'assign_user_role',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200, {}))))
         return tenant_fix
 
@@ -120,7 +121,7 @@
         roles_fix = self.useFixture(mockpatch.PatchObject(
             json_roles_client.RolesClient,
             'list_roles',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200, {'roles': [{'id': '1',
                                  'name': 'FakeRole'}]}))))
         return roles_fix
@@ -129,7 +130,7 @@
         ec2_creds_fix = self.useFixture(mockpatch.PatchObject(
             json_users_client.UsersClient,
             'list_user_ec2_credentials',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200, {'credentials': [{
                                  'access': 'fake_access',
                                  'secret': 'fake_secret',
@@ -154,12 +155,12 @@
 
     def _mock_router_create(self, id, name):
         router_fix = self.useFixture(mockpatch.PatchObject(
-            json_network_client.NetworkClient,
+            routers_client.RoutersClient,
             'create_router',
             return_value={'router': {'id': id, 'name': name}}))
         return router_fix
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_primary_creds(self, MockRestClient):
         cfg.CONF.set_default('neutron', False, 'service_available')
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
@@ -174,7 +175,7 @@
         self.assertEqual(primary_creds.tenant_id, '1234')
         self.assertEqual(primary_creds.user_id, '1234')
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_admin_creds(self, MockRestClient):
         cfg.CONF.set_default('neutron', False, 'service_available')
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
@@ -197,7 +198,7 @@
         self.assertEqual(admin_creds.tenant_id, '1234')
         self.assertEqual(admin_creds.user_id, '1234')
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_role_creds(self, MockRestClient):
         cfg.CONF.set_default('neutron', False, 'service_available')
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
@@ -226,7 +227,7 @@
         self.assertEqual(role_creds.tenant_id, '1234')
         self.assertEqual(role_creds.user_id, '1234')
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_all_cred_cleanup(self, MockRestClient):
         cfg.CONF.set_default('neutron', False, 'service_available')
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
@@ -266,7 +267,7 @@
         self.assertIn('12345', args)
         self.assertIn('123456', args)
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_alt_creds(self, MockRestClient):
         cfg.CONF.set_default('neutron', False, 'service_available')
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
@@ -281,7 +282,7 @@
         self.assertEqual(alt_creds.tenant_id, '1234')
         self.assertEqual(alt_creds.user_id, '1234')
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_no_network_creation_with_config_set(self, MockRestClient):
         cfg.CONF.set_default('create_isolated_networks', False, group='auth')
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
@@ -295,7 +296,7 @@
         subnet = mock.patch.object(creds.subnets_admin_client,
                                    'delete_subnet')
         subnet_mock = subnet.start()
-        router = mock.patch.object(creds.network_admin_client,
+        router = mock.patch.object(creds.routers_admin_client,
                                    'delete_router')
         router_mock = router.start()
 
@@ -310,7 +311,7 @@
         self.assertIsNone(subnet)
         self.assertIsNone(router)
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_network_creation(self, MockRestClient):
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
         self._mock_assign_user_role()
@@ -321,7 +322,7 @@
         self._mock_subnet_create(creds, '1234', 'fake_subnet')
         self._mock_router_create('1234', 'fake_router')
         router_interface_mock = self.patch(
-            'tempest.services.network.json.network_client.NetworkClient.'
+            'tempest.services.network.json.routers_client.RoutersClient.'
             'add_router_interface')
         primary_creds = creds.get_primary_creds()
         router_interface_mock.assert_called_once_with('1234', subnet_id='1234')
@@ -335,7 +336,7 @@
         self.assertEqual(router['id'], '1234')
         self.assertEqual(router['name'], 'fake_router')
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_network_cleanup(self, MockRestClient):
         def side_effect(**args):
             return {"security_groups": [{"tenant_id": args['tenant_id'],
@@ -353,7 +354,7 @@
         self._mock_subnet_create(creds, '1234', 'fake_subnet')
         self._mock_router_create('1234', 'fake_router')
         router_interface_mock = self.patch(
-            'tempest.services.network.json.network_client.NetworkClient.'
+            'tempest.services.network.json.routers_client.RoutersClient.'
             'add_router_interface')
         creds.get_primary_creds()
         router_interface_mock.assert_called_once_with('1234', subnet_id='1234')
@@ -386,11 +387,11 @@
         subnet = mock.patch.object(creds.subnets_admin_client,
                                    'delete_subnet')
         subnet_mock = subnet.start()
-        router = mock.patch.object(creds.network_admin_client,
+        router = mock.patch.object(creds.routers_admin_client,
                                    'delete_router')
         router_mock = router.start()
         remove_router_interface_mock = self.patch(
-            'tempest.services.network.json.network_client.NetworkClient.'
+            'tempest.services.network.json.routers_client.RoutersClient.'
             'remove_router_interface')
         return_values = ({'status': 200}, {'ports': []})
         port_list_mock = mock.patch.object(creds.ports_admin_client,
@@ -406,7 +407,7 @@
 
         return_values = (fake_http.fake_httplib({}, status=204), {})
         remove_secgroup_mock = self.patch(
-            'tempest_lib.services.network.security_groups_client.'
+            'tempest.lib.services.network.security_groups_client.'
             'SecurityGroupsClient.delete', return_value=return_values)
         creds.clear_creds()
         # Verify default security group delete
@@ -450,7 +451,7 @@
         self.assertIn('12345', args)
         self.assertIn('123456', args)
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_network_alt_creation(self, MockRestClient):
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
         self._mock_assign_user_role()
@@ -461,7 +462,7 @@
         self._mock_subnet_create(creds, '1234', 'fake_alt_subnet')
         self._mock_router_create('1234', 'fake_alt_router')
         router_interface_mock = self.patch(
-            'tempest.services.network.json.network_client.NetworkClient.'
+            'tempest.services.network.json.routers_client.RoutersClient.'
             'add_router_interface')
         alt_creds = creds.get_alt_creds()
         router_interface_mock.assert_called_once_with('1234', subnet_id='1234')
@@ -475,7 +476,7 @@
         self.assertEqual(router['id'], '1234')
         self.assertEqual(router['name'], 'fake_alt_router')
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_network_admin_creation(self, MockRestClient):
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
         self._mock_assign_user_role()
@@ -485,7 +486,7 @@
         self._mock_subnet_create(creds, '1234', 'fake_admin_subnet')
         self._mock_router_create('1234', 'fake_admin_router')
         router_interface_mock = self.patch(
-            'tempest.services.network.json.network_client.NetworkClient.'
+            'tempest.services.network.json.routers_client.RoutersClient.'
             'add_router_interface')
         self._mock_list_roles('123456', 'admin')
         admin_creds = creds.get_admin_creds()
@@ -500,7 +501,7 @@
         self.assertEqual(router['id'], '1234')
         self.assertEqual(router['name'], 'fake_admin_router')
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_no_network_resources(self, MockRestClient):
         net_dict = {
             'network': False,
@@ -521,7 +522,7 @@
         subnet = mock.patch.object(creds.subnets_admin_client,
                                    'delete_subnet')
         subnet_mock = subnet.start()
-        router = mock.patch.object(creds.network_admin_client,
+        router = mock.patch.object(creds.routers_admin_client,
                                    'delete_router')
         router_mock = router.start()
 
@@ -536,7 +537,7 @@
         self.assertIsNone(subnet)
         self.assertIsNone(router)
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_router_without_network(self, MockRestClient):
         net_dict = {
             'network': False,
@@ -554,7 +555,7 @@
         self.assertRaises(exceptions.InvalidConfiguration,
                           creds.get_primary_creds)
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_subnet_without_network(self, MockRestClient):
         net_dict = {
             'network': False,
@@ -572,7 +573,7 @@
         self.assertRaises(exceptions.InvalidConfiguration,
                           creds.get_primary_creds)
 
-    @mock.patch('tempest_lib.common.rest_client.RestClient')
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_dhcp_without_subnet(self, MockRestClient):
         net_dict = {
             'network': False,
diff --git a/tempest/tests/common/test_preprov_creds.py b/tempest/tests/common/test_preprov_creds.py
index fd7df16..7188e5f 100644
--- a/tempest/tests/common/test_preprov_creds.py
+++ b/tempest/tests/common/test_preprov_creds.py
@@ -21,13 +21,13 @@
 from oslotest import mockpatch
 import shutil
 import six
-from tempest_lib import auth
-from tempest_lib import exceptions as lib_exc
-from tempest_lib.services.identity.v2 import token_client
 
 from tempest.common import cred_provider
 from tempest.common import preprov_creds
 from tempest import config
+from tempest.lib import auth
+from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.identity.v2 import token_client
 from tempest.tests import base
 from tempest.tests import fake_config
 from tempest.tests import fake_http
@@ -319,7 +319,7 @@
             return_value=test_accounts))
         test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
             **self.fixed_params)
-        with mock.patch('tempest_lib.services.compute.networks_client.'
+        with mock.patch('tempest.lib.services.compute.networks_client.'
                         'NetworksClient.list_networks',
                         return_value={'networks': [{'name': 'network-2',
                                                     'id': 'fake-id',
diff --git a/tempest/tests/common/test_service_clients.py b/tempest/tests/common/test_service_clients.py
deleted file mode 100644
index f248957..0000000
--- a/tempest/tests/common/test_service_clients.py
+++ /dev/null
@@ -1,144 +0,0 @@
-# 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.
-
-import mock
-import random
-import six
-
-from tempest.services.baremetal.v1.json import baremetal_client
-from tempest.services.data_processing.v1_1 import data_processing_client
-from tempest.services.database.json import flavors_client as db_flavor_client
-from tempest.services.database.json import versions_client as db_version_client
-from tempest.services.identity.v2.json import identity_client as \
-    identity_v2_identity_client
-from tempest.services.identity.v3.json import credentials_client
-from tempest.services.identity.v3.json import endpoints_client
-from tempest.services.identity.v3.json import identity_client as \
-    identity_v3_identity_client
-from tempest.services.identity.v3.json import policies_client
-from tempest.services.identity.v3.json import regions_client
-from tempest.services.identity.v3.json import services_client
-from tempest.services.image.v1.json import images_client
-from tempest.services.image.v2.json import images_client as images_v2_client
-from tempest.services.messaging.json import messaging_client
-from tempest.services.network.json import network_client
-from tempest.services.object_storage import account_client
-from tempest.services.object_storage import container_client
-from tempest.services.object_storage import object_client
-from tempest.services.orchestration.json import orchestration_client
-from tempest.services.telemetry.json import alarming_client
-from tempest.services.telemetry.json import telemetry_client
-from tempest.services.volume.v1.json.admin import hosts_client \
-    as volume_hosts_client
-from tempest.services.volume.v1.json.admin import quotas_client \
-    as volume_quotas_client
-from tempest.services.volume.v1.json.admin import services_client \
-    as volume_services_client
-from tempest.services.volume.v1.json.admin import types_client \
-    as volume_types_client
-from tempest.services.volume.v1.json import availability_zone_client \
-    as volume_az_client
-from tempest.services.volume.v1.json import backups_client
-from tempest.services.volume.v1.json import extensions_client \
-    as volume_extensions_client
-from tempest.services.volume.v1.json import qos_client
-from tempest.services.volume.v1.json import snapshots_client
-from tempest.services.volume.v1.json import volumes_client
-from tempest.services.volume.v2.json.admin import hosts_client \
-    as volume_v2_hosts_client
-from tempest.services.volume.v2.json.admin import quotas_client \
-    as volume_v2_quotas_client
-from tempest.services.volume.v2.json.admin import services_client \
-    as volume_v2_services_client
-from tempest.services.volume.v2.json.admin import types_client \
-    as volume_v2_types_client
-from tempest.services.volume.v2.json import availability_zone_client \
-    as volume_v2_az_client
-from tempest.services.volume.v2.json import backups_client \
-    as volume_v2_backups_client
-from tempest.services.volume.v2.json import extensions_client \
-    as volume_v2_extensions_client
-from tempest.services.volume.v2.json import qos_client as volume_v2_qos_client
-from tempest.services.volume.v2.json import snapshots_client \
-    as volume_v2_snapshots_client
-from tempest.services.volume.v2.json import volumes_client as \
-    volume_v2_volumes_client
-from tempest.tests import base
-
-
-class TestServiceClient(base.TestCase):
-
-    @mock.patch('tempest_lib.common.rest_client.RestClient.__init__')
-    def test_service_client_creations_with_specified_args(self, mock_init):
-        test_clients = [
-            baremetal_client.BaremetalClient,
-            data_processing_client.DataProcessingClient,
-            db_flavor_client.DatabaseFlavorsClient,
-            db_version_client.DatabaseVersionsClient,
-            messaging_client.MessagingClient,
-            network_client.NetworkClient,
-            account_client.AccountClient,
-            container_client.ContainerClient,
-            object_client.ObjectClient,
-            orchestration_client.OrchestrationClient,
-            telemetry_client.TelemetryClient,
-            alarming_client.AlarmingClient,
-            qos_client.QosSpecsClient,
-            volume_hosts_client.HostsClient,
-            volume_quotas_client.QuotasClient,
-            volume_services_client.ServicesClient,
-            volume_types_client.TypesClient,
-            volume_az_client.AvailabilityZoneClient,
-            backups_client.BackupsClient,
-            volume_extensions_client.ExtensionsClient,
-            snapshots_client.SnapshotsClient,
-            volumes_client.VolumesClient,
-            volume_v2_hosts_client.HostsClient,
-            volume_v2_quotas_client.QuotasClient,
-            volume_v2_services_client.ServicesClient,
-            volume_v2_types_client.TypesClient,
-            volume_v2_az_client.AvailabilityZoneClient,
-            volume_v2_backups_client.BackupsClient,
-            volume_v2_extensions_client.ExtensionsClient,
-            volume_v2_qos_client.QosSpecsClient,
-            volume_v2_snapshots_client.SnapshotsClient,
-            volume_v2_volumes_client.VolumesClient,
-            identity_v2_identity_client.IdentityClient,
-            credentials_client.CredentialsClient,
-            endpoints_client.EndPointClient,
-            identity_v3_identity_client.IdentityV3Client,
-            policies_client.PoliciesClient,
-            regions_client.RegionsClient,
-            services_client.ServicesClient,
-            images_client.ImagesClient,
-            images_v2_client.ImagesClientV2
-        ]
-
-        for client in test_clients:
-            fake_string = six.text_type(random.randint(1, 0x7fffffff))
-            auth = 'auth' + fake_string
-            service = 'service' + fake_string
-            region = 'region' + fake_string
-            params = {
-                'endpoint_type': 'URL' + fake_string,
-                'build_interval': random.randint(1, 100),
-                'build_timeout': random.randint(1, 100),
-                'disable_ssl_certificate_validation':
-                    True if random.randint(0, 1) else False,
-                'ca_certs': None,
-                'trace_requests': 'foo' + fake_string
-            }
-            client(auth, service, region, **params)
-            mock_init.assert_called_once_with(auth, service, region, **params)
-            mock_init.reset_mock()
diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py
index c7cc638..492bdca 100644
--- a/tempest/tests/common/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -20,6 +20,7 @@
 from tempest import exceptions
 from tempest.services.volume.base import base_volumes_client
 from tempest.tests import base
+import tempest.tests.utils as utils
 
 
 class TestImageWaiters(base.TestCase):
@@ -37,17 +38,24 @@
         # Ensure waiter returns before build_timeout
         self.assertTrue((end_time - start_time) < 10)
 
-    def test_wait_for_image_status_timeout(self):
+    @mock.patch('time.sleep')
+    def test_wait_for_image_status_timeout(self, mock_sleep):
+        time_mock = self.patch('time.time')
+        time_mock.side_effect = utils.generate_timeout_series(1)
+
         self.client.show_image.return_value = ({'status': 'saving'})
         self.assertRaises(exceptions.TimeoutException,
                           waiters.wait_for_image_status,
                           self.client, 'fake_image_id', 'active')
+        mock_sleep.assert_called_once_with(1)
 
-    def test_wait_for_image_status_error_on_image_create(self):
+    @mock.patch('time.sleep')
+    def test_wait_for_image_status_error_on_image_create(self, mock_sleep):
         self.client.show_image.return_value = ({'status': 'ERROR'})
         self.assertRaises(exceptions.AddImageException,
                           waiters.wait_for_image_status,
                           self.client, 'fake_image_id', 'active')
+        mock_sleep.assert_called_once_with(1)
 
     @mock.patch.object(time, 'sleep')
     def test_wait_for_volume_status_error_restoring(self, mock_sleep):
diff --git a/tempest/api/messaging/__init__.py b/tempest/tests/lib/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/tests/lib/__init__.py
diff --git a/tempest/tests/lib/base.py b/tempest/tests/lib/base.py
new file mode 100644
index 0000000..fe9268e
--- /dev/null
+++ b/tempest/tests/lib/base.py
@@ -0,0 +1,44 @@
+# 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 mock
+from oslotest import base
+from oslotest import moxstubout
+
+
+class TestCase(base.BaseTestCase):
+
+    def setUp(self):
+        super(TestCase, self).setUp()
+        mox_fixture = self.useFixture(moxstubout.MoxStubout())
+        self.mox = mox_fixture.mox
+        self.stubs = mox_fixture.stubs
+
+    def patch(self, target, **kwargs):
+        """Returns a started `mock.patch` object for the supplied target.
+
+        The caller may then call the returned patcher to create a mock object.
+
+        The caller does not need to call stop() on the returned
+        patcher object, as this method automatically adds a cleanup
+        to the test class to stop the patcher.
+
+        :param target: String module.class or module.object expression to patch
+        :param **kwargs: Passed as-is to `mock.patch`. See mock documentation
+                         for details.
+        """
+        p = mock.patch(target, **kwargs)
+        m = p.start()
+        self.addCleanup(p.stop)
+        return m
diff --git a/tempest/api/messaging/__init__.py b/tempest/tests/lib/cli/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/tests/lib/cli/__init__.py
diff --git a/tempest/tests/lib/cli/test_command_failed.py b/tempest/tests/lib/cli/test_command_failed.py
new file mode 100644
index 0000000..8ce34c2
--- /dev/null
+++ b/tempest/tests/lib/cli/test_command_failed.py
@@ -0,0 +1,30 @@
+#    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 import exceptions
+from tempest.tests.lib import base
+
+
+class TestOutputParser(base.TestCase):
+
+    def test_command_failed_exception(self):
+        returncode = 1
+        cmd = "foo"
+        stdout = "output"
+        stderr = "error"
+        try:
+            raise exceptions.CommandFailed(returncode, cmd, stdout, stderr)
+        except exceptions.CommandFailed as e:
+            self.assertIn(str(returncode), str(e))
+            self.assertIn(cmd, str(e))
+            self.assertIn(stdout, str(e))
+            self.assertIn(stderr, str(e))
diff --git a/tempest/tests/lib/cli/test_execute.py b/tempest/tests/lib/cli/test_execute.py
new file mode 100644
index 0000000..b5f7145
--- /dev/null
+++ b/tempest/tests/lib/cli/test_execute.py
@@ -0,0 +1,37 @@
+#
+#    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.cli import base as cli_base
+from tempest.lib import exceptions
+from tempest.tests.lib import base
+
+
+class TestExecute(base.TestCase):
+    def test_execute_success(self):
+        result = cli_base.execute("/bin/ls", action="tempest",
+                                  flags="-l -a")
+        self.assertIsInstance(result, str)
+        self.assertIn("__init__.py", result)
+
+    def test_execute_failure(self):
+        result = cli_base.execute("/bin/ls", action="tempest.lib",
+                                  flags="--foobar", merge_stderr=True,
+                                  fail_ok=True)
+        self.assertIsInstance(result, str)
+        self.assertIn("--foobar", result)
+
+    def test_execute_failure_raise_exception(self):
+        self.assertRaises(exceptions.CommandFailed, cli_base.execute,
+                          "/bin/ls", action="tempest", flags="--foobar",
+                          merge_stderr=True)
diff --git a/tempest/tests/lib/cli/test_output_parser.py b/tempest/tests/lib/cli/test_output_parser.py
new file mode 100644
index 0000000..a2c1b2d
--- /dev/null
+++ b/tempest/tests/lib/cli/test_output_parser.py
@@ -0,0 +1,177 @@
+# Copyright 2014 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.cli import output_parser
+from tempest.lib import exceptions
+from tempest.tests.lib import base
+
+
+class TestOutputParser(base.TestCase):
+    OUTPUT_LINES = """
++----+------+---------+
+| ID | Name | Status  |
++----+------+---------+
+| 11 | foo  | BUILD   |
+| 21 | bar  | ERROR   |
+| 31 | bee  | None    |
++----+------+---------+
+"""
+    OUTPUT_LINES2 = """
++----+-------+---------+
+| ID | Name2 | Status2 |
++----+-------+---------+
+| 41 | aaa   | SSSSS   |
+| 51 | bbb   | TTTTT   |
+| 61 | ccc   | AAAAA   |
++----+-------+---------+
+"""
+
+    EXPECTED_TABLE = {'headers': ['ID', 'Name', 'Status'],
+                      'values': [['11', 'foo', 'BUILD'],
+                                 ['21', 'bar', 'ERROR'],
+                                 ['31', 'bee', 'None']]}
+    EXPECTED_TABLE2 = {'headers': ['ID', 'Name2', 'Status2'],
+                       'values': [['41', 'aaa', 'SSSSS'],
+                                  ['51', 'bbb', 'TTTTT'],
+                                  ['61', 'ccc', 'AAAAA']]}
+
+    def test_table_with_normal_values(self):
+        actual = output_parser.table(self.OUTPUT_LINES)
+        self.assertIsInstance(actual, dict)
+        self.assertEqual(self.EXPECTED_TABLE, actual)
+
+    def test_table_with_list(self):
+        output_lines = self.OUTPUT_LINES.split('\n')
+        actual = output_parser.table(output_lines)
+        self.assertIsInstance(actual, dict)
+        self.assertEqual(self.EXPECTED_TABLE, actual)
+
+    def test_table_with_invalid_line(self):
+        output_lines = self.OUTPUT_LINES + "aaaa"
+        actual = output_parser.table(output_lines)
+        self.assertIsInstance(actual, dict)
+        self.assertEqual(self.EXPECTED_TABLE, actual)
+
+    def test_tables_with_normal_values(self):
+        output_lines = ('test' + self.OUTPUT_LINES +
+                        'test2' + self.OUTPUT_LINES2)
+        expected = [{'headers': self.EXPECTED_TABLE['headers'],
+                     'label': 'test',
+                     'values': self.EXPECTED_TABLE['values']},
+                    {'headers': self.EXPECTED_TABLE2['headers'],
+                     'label': 'test2',
+                     'values': self.EXPECTED_TABLE2['values']}]
+        actual = output_parser.tables(output_lines)
+        self.assertIsInstance(actual, list)
+        self.assertEqual(expected, actual)
+
+    def test_tables_with_invalid_values(self):
+        output_lines = ('test' + self.OUTPUT_LINES +
+                        'test2' + self.OUTPUT_LINES2 + '\n')
+        expected = [{'headers': self.EXPECTED_TABLE['headers'],
+                     'label': 'test',
+                     'values': self.EXPECTED_TABLE['values']},
+                    {'headers': self.EXPECTED_TABLE2['headers'],
+                     'label': 'test2',
+                     'values': self.EXPECTED_TABLE2['values']}]
+        actual = output_parser.tables(output_lines)
+        self.assertIsInstance(actual, list)
+        self.assertEqual(expected, actual)
+
+    def test_tables_with_invalid_line(self):
+        output_lines = ('test' + self.OUTPUT_LINES +
+                        'test2' + self.OUTPUT_LINES2 +
+                        '+----+-------+---------+')
+        expected = [{'headers': self.EXPECTED_TABLE['headers'],
+                     'label': 'test',
+                     'values': self.EXPECTED_TABLE['values']},
+                    {'headers': self.EXPECTED_TABLE2['headers'],
+                     'label': 'test2',
+                     'values': self.EXPECTED_TABLE2['values']}]
+
+        actual = output_parser.tables(output_lines)
+        self.assertIsInstance(actual, list)
+        self.assertEqual(expected, actual)
+
+    LISTING_OUTPUT = """
++----+
+| ID |
++----+
+| 11 |
+| 21 |
+| 31 |
++----+
+"""
+
+    def test_listing(self):
+        expected = [{'ID': '11'}, {'ID': '21'}, {'ID': '31'}]
+        actual = output_parser.listing(self.LISTING_OUTPUT)
+        self.assertIsInstance(actual, list)
+        self.assertEqual(expected, actual)
+
+    def test_details_multiple_with_invalid_line(self):
+        self.assertRaises(exceptions.InvalidStructure,
+                          output_parser.details_multiple,
+                          self.OUTPUT_LINES)
+
+    DETAILS_LINES1 = """First Table
++----------+--------+
+| Property | Value  |
++----------+--------+
+| foo      | BUILD  |
+| bar      | ERROR  |
+| bee      | None   |
++----------+--------+
+"""
+    DETAILS_LINES2 = """Second Table
++----------+--------+
+| Property | Value  |
++----------+--------+
+| aaa      | VVVVV  |
+| bbb      | WWWWW  |
+| ccc      | XXXXX  |
++----------+--------+
+"""
+
+    def test_details_with_normal_line_label_false(self):
+        expected = {'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'}
+        actual = output_parser.details(self.DETAILS_LINES1)
+        self.assertEqual(expected, actual)
+
+    def test_details_with_normal_line_label_true(self):
+        expected = {'__label': 'First Table',
+                    'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'}
+        actual = output_parser.details(self.DETAILS_LINES1, with_label=True)
+        self.assertEqual(expected, actual)
+
+    def test_details_multiple_with_normal_line_label_false(self):
+        expected = [{'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'},
+                    {'aaa': 'VVVVV', 'bbb': 'WWWWW', 'ccc': 'XXXXX'}]
+        actual = output_parser.details_multiple(self.DETAILS_LINES1 +
+                                                self.DETAILS_LINES2)
+        self.assertIsInstance(actual, list)
+        self.assertEqual(expected, actual)
+
+    def test_details_multiple_with_normal_line_label_true(self):
+        expected = [{'__label': 'First Table',
+                     'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'},
+                    {'__label': 'Second Table',
+                     'aaa': 'VVVVV', 'bbb': 'WWWWW', 'ccc': 'XXXXX'}]
+        actual = output_parser.details_multiple(self.DETAILS_LINES1 +
+                                                self.DETAILS_LINES2,
+                                                with_label=True)
+        self.assertIsInstance(actual, list)
+        self.assertEqual(expected, actual)
diff --git a/tempest/api/messaging/__init__.py b/tempest/tests/lib/common/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/tests/lib/common/__init__.py
diff --git a/tempest/api/messaging/__init__.py b/tempest/tests/lib/common/utils/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/tests/lib/common/utils/__init__.py
diff --git a/tempest/tests/lib/common/utils/test_data_utils.py b/tempest/tests/lib/common/utils/test_data_utils.py
new file mode 100644
index 0000000..07502d0
--- /dev/null
+++ b/tempest/tests/lib/common/utils/test_data_utils.py
@@ -0,0 +1,162 @@
+# Copyright 2014 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 netaddr
+
+from tempest.lib.common.utils import data_utils
+from tempest.tests.lib import base
+
+
+class TestDataUtils(base.TestCase):
+
+    def test_rand_uuid(self):
+        actual = data_utils.rand_uuid()
+        self.assertIsInstance(actual, str)
+        self.assertRegexpMatches(actual, "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]"
+                                         "{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
+        actual2 = data_utils.rand_uuid()
+        self.assertNotEqual(actual, actual2)
+
+    def test_rand_uuid_hex(self):
+        actual = data_utils.rand_uuid_hex()
+        self.assertIsInstance(actual, str)
+        self.assertRegexpMatches(actual, "^[0-9a-f]{32}$")
+
+        actual2 = data_utils.rand_uuid_hex()
+        self.assertNotEqual(actual, actual2)
+
+    def test_rand_name(self):
+        actual = data_utils.rand_name()
+        self.assertIsInstance(actual, str)
+        actual2 = data_utils.rand_name()
+        self.assertNotEqual(actual, actual2)
+
+        actual = data_utils.rand_name('foo')
+        self.assertTrue(actual.startswith('foo'))
+        actual2 = data_utils.rand_name('foo')
+        self.assertTrue(actual.startswith('foo'))
+        self.assertNotEqual(actual, actual2)
+
+    def test_rand_name_with_prefix(self):
+        actual = data_utils.rand_name(prefix='prefix-str')
+        self.assertIsInstance(actual, str)
+        self.assertRegexpMatches(actual, "^prefix-str-")
+        actual2 = data_utils.rand_name(prefix='prefix-str')
+        self.assertNotEqual(actual, actual2)
+
+    def test_rand_password(self):
+        actual = data_utils.rand_password()
+        self.assertIsInstance(actual, str)
+        self.assertRegexpMatches(actual, "[A-Za-z0-9~!@#$%^&*_=+]{15,}")
+        actual2 = data_utils.rand_password()
+        self.assertNotEqual(actual, actual2)
+
+    def test_rand_password_with_len(self):
+        actual = data_utils.rand_password(8)
+        self.assertIsInstance(actual, str)
+        self.assertEqual(len(actual), 8)
+        self.assertRegexpMatches(actual, "[A-Za-z0-9~!@#$%^&*_=+]{8}")
+        actual2 = data_utils.rand_password(8)
+        self.assertNotEqual(actual, actual2)
+
+    def test_rand_password_with_len_2(self):
+        actual = data_utils.rand_password(2)
+        self.assertIsInstance(actual, str)
+        self.assertEqual(len(actual), 3)
+        self.assertRegexpMatches(actual, "[A-Za-z0-9~!@#$%^&*_=+]{3}")
+        actual2 = data_utils.rand_password(2)
+        self.assertNotEqual(actual, actual2)
+
+    def test_rand_url(self):
+        actual = data_utils.rand_url()
+        self.assertIsInstance(actual, str)
+        self.assertRegexpMatches(actual, "^https://url-[0-9]*\.com$")
+        actual2 = data_utils.rand_url()
+        self.assertNotEqual(actual, actual2)
+
+    def test_rand_int(self):
+        actual = data_utils.rand_int_id()
+        self.assertIsInstance(actual, int)
+
+        actual2 = data_utils.rand_int_id()
+        self.assertNotEqual(actual, actual2)
+
+    def test_rand_mac_address(self):
+        actual = data_utils.rand_mac_address()
+        self.assertIsInstance(actual, str)
+        self.assertRegexpMatches(actual, "^([0-9a-f][0-9a-f]:){5}"
+                                         "[0-9a-f][0-9a-f]$")
+
+        actual2 = data_utils.rand_mac_address()
+        self.assertNotEqual(actual, actual2)
+
+    def test_parse_image_id(self):
+        actual = data_utils.parse_image_id("/foo/bar/deadbeaf")
+        self.assertEqual("deadbeaf", actual)
+
+    def test_arbitrary_string(self):
+        actual = data_utils.arbitrary_string()
+        self.assertEqual(actual, "test")
+        actual = data_utils.arbitrary_string(size=30, base_text="abc")
+        self.assertEqual(actual, "abc" * int(30 / len("abc")))
+        actual = data_utils.arbitrary_string(size=5, base_text="deadbeaf")
+        self.assertEqual(actual, "deadb")
+
+    def test_random_bytes(self):
+        actual = data_utils.random_bytes()  # default size=1024
+        self.assertIsInstance(actual, str)
+        self.assertRegexpMatches(actual, "^[\x00-\xFF]{1024}")
+        actual2 = data_utils.random_bytes()
+        self.assertNotEqual(actual, actual2)
+
+        actual = data_utils.random_bytes(size=2048)
+        self.assertRegexpMatches(actual, "^[\x00-\xFF]{2048}")
+
+    def test_get_ipv6_addr_by_EUI64(self):
+        actual = data_utils.get_ipv6_addr_by_EUI64('2001:db8::',
+                                                   '00:16:3e:33:44:55')
+        self.assertIsInstance(actual, netaddr.IPAddress)
+        self.assertEqual(actual,
+                         netaddr.IPAddress('2001:db8::216:3eff:fe33:4455'))
+
+    def test_get_ipv6_addr_by_EUI64_with_IPv4_prefix(self):
+        ipv4_prefix = '10.0.8'
+        mac = '00:16:3e:33:44:55'
+        self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64,
+                          ipv4_prefix, mac)
+
+    def test_get_ipv6_addr_by_EUI64_bad_cidr_type(self):
+        bad_cidr = 123
+        mac = '00:16:3e:33:44:55'
+        self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64,
+                          bad_cidr, mac)
+
+    def test_get_ipv6_addr_by_EUI64_bad_cidr_value(self):
+        bad_cidr = 'bb'
+        mac = '00:16:3e:33:44:55'
+        self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64,
+                          bad_cidr, mac)
+
+    def test_get_ipv6_addr_by_EUI64_bad_mac_value(self):
+        cidr = '2001:db8::'
+        bad_mac = '00:16:3e:33:44:5Z'
+        self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64,
+                          cidr, bad_mac)
+
+    def test_get_ipv6_addr_by_EUI64_bad_mac_type(self):
+        cidr = '2001:db8::'
+        bad_mac = 99999999999999999999
+        self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64,
+                          cidr, bad_mac)
diff --git a/tempest/tests/lib/common/utils/test_misc.py b/tempest/tests/lib/common/utils/test_misc.py
new file mode 100644
index 0000000..e23d7fb
--- /dev/null
+++ b/tempest/tests/lib/common/utils/test_misc.py
@@ -0,0 +1,88 @@
+# Copyright 2014 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.common.utils import misc
+from tempest.tests.lib import base
+
+
+@misc.singleton
+class TestFoo(object):
+
+    count = 0
+
+    def increment(self):
+        self.count += 1
+        return self.count
+
+
+@misc.singleton
+class TestBar(object):
+
+    count = 0
+
+    def increment(self):
+        self.count += 1
+        return self.count
+
+
+class TestMisc(base.TestCase):
+
+    def test_singleton(self):
+        test = TestFoo()
+        self.assertEqual(0, test.count)
+        self.assertEqual(1, test.increment())
+        test2 = TestFoo()
+        self.assertEqual(1, test.count)
+        self.assertEqual(1, test2.count)
+        self.assertEqual(test, test2)
+        test3 = TestBar()
+        self.assertNotEqual(test, test3)
+
+    def test_find_test_caller_test_case(self):
+        # Calling it from here should give us the method we're in.
+        self.assertEqual('TestMisc:test_find_test_caller_test_case',
+                         misc.find_test_caller())
+
+    def test_find_test_caller_setup_self(self):
+        def setUp(self):
+            return misc.find_test_caller()
+        self.assertEqual('TestMisc:setUp', setUp(self))
+
+    def test_find_test_caller_setup_no_self(self):
+        def setUp():
+            return misc.find_test_caller()
+        self.assertEqual(':setUp', setUp())
+
+    def test_find_test_caller_setupclass_cls(self):
+        def setUpClass(cls):  # noqa
+            return misc.find_test_caller()
+        self.assertEqual('TestMisc:setUpClass', setUpClass(self.__class__))
+
+    def test_find_test_caller_teardown_self(self):
+        def tearDown(self):
+            return misc.find_test_caller()
+        self.assertEqual('TestMisc:tearDown', tearDown(self))
+
+    def test_find_test_caller_teardown_no_self(self):
+        def tearDown():
+            return misc.find_test_caller()
+        self.assertEqual(':tearDown', tearDown())
+
+    def test_find_test_caller_teardown_class(self):
+        def tearDownClass(cls):  # noqa
+            return misc.find_test_caller()
+        self.assertEqual('TestMisc:tearDownClass',
+                         tearDownClass(self.__class__))
diff --git a/tempest/tests/lib/fake_auth_provider.py b/tempest/tests/lib/fake_auth_provider.py
new file mode 100644
index 0000000..8095453
--- /dev/null
+++ b/tempest/tests/lib/fake_auth_provider.py
@@ -0,0 +1,35 @@
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
+# 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.
+
+
+class FakeAuthProvider(object):
+
+    def __init__(self, creds_dict=None, fake_base_url=None):
+        creds_dict = creds_dict or {}
+        self.credentials = FakeCredentials(creds_dict)
+        self.fake_base_url = fake_base_url
+
+    def auth_request(self, method, url, headers=None, body=None, filters=None):
+        return url, headers, body
+
+    def base_url(self, filters, auth_data=None):
+        return self.fake_base_url or "https://example.com"
+
+
+class FakeCredentials(object):
+
+    def __init__(self, creds_dict):
+        for key in creds_dict.keys():
+            setattr(self, key, creds_dict[key])
diff --git a/tempest/tests/lib/fake_credentials.py b/tempest/tests/lib/fake_credentials.py
new file mode 100644
index 0000000..fb81bd6
--- /dev/null
+++ b/tempest/tests/lib/fake_credentials.py
@@ -0,0 +1,59 @@
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
+# 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 import auth
+
+
+class FakeCredentials(auth.Credentials):
+
+    def is_valid(self):
+        return True
+
+
+class FakeKeystoneV2Credentials(auth.KeystoneV2Credentials):
+
+    def __init__(self):
+        creds = dict(
+            username='fake_username',
+            password='fake_password',
+            tenant_name='fake_tenant_name'
+        )
+        super(FakeKeystoneV2Credentials, self).__init__(**creds)
+
+
+class FakeKeystoneV3Credentials(auth.KeystoneV3Credentials):
+    """Fake credentials suitable for the Keystone Identity V3 API"""
+
+    def __init__(self):
+        creds = dict(
+            username='fake_username',
+            password='fake_password',
+            user_domain_name='fake_domain_name',
+            project_name='fake_tenant_name',
+            project_domain_name='fake_domain_name'
+        )
+        super(FakeKeystoneV3Credentials, self).__init__(**creds)
+
+
+class FakeKeystoneV3DomainCredentials(auth.KeystoneV3Credentials):
+    """Fake credentials for the Keystone Identity V3 API, with no scope"""
+
+    def __init__(self):
+        creds = dict(
+            username='fake_username',
+            password='fake_password',
+            user_domain_name='fake_domain_name'
+        )
+        super(FakeKeystoneV3DomainCredentials, self).__init__(**creds)
diff --git a/tempest/tests/lib/fake_http.py b/tempest/tests/lib/fake_http.py
new file mode 100644
index 0000000..eda202d
--- /dev/null
+++ b/tempest/tests/lib/fake_http.py
@@ -0,0 +1,74 @@
+# 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 copy
+
+import httplib2
+
+
+class fake_httplib2(object):
+
+    def __init__(self, return_type=None, *args, **kwargs):
+        self.return_type = return_type
+
+    def request(self, uri, method="GET", body=None, headers=None,
+                redirections=5, connection_type=None):
+        if not self.return_type:
+            fake_headers = httplib2.Response(headers)
+            return_obj = {
+                'uri': uri,
+                'method': method,
+                'body': body,
+                'headers': headers
+            }
+            return (fake_headers, return_obj)
+        elif isinstance(self.return_type, int):
+            body = body or "fake_body"
+            header_info = {
+                'content-type': 'text/plain',
+                'status': str(self.return_type),
+                'content-length': len(body)
+            }
+            resp_header = httplib2.Response(header_info)
+            return (resp_header, body)
+        else:
+            msg = "unsupported return type %s" % self.return_type
+            raise TypeError(msg)
+
+
+class fake_httplib(object):
+    def __init__(self, headers, body=None,
+                 version=1.0, status=200, reason="Ok"):
+        """Fake httplib implementation
+
+        :param headers: dict representing HTTP response headers
+        :param body: file-like object
+        :param version: HTTP Version
+        :param status: Response status code
+        :param reason: Status code related message.
+        """
+        self.body = body
+        self.status = status
+        self.reason = reason
+        self.version = version
+        self.headers = headers
+
+    def getheaders(self):
+        return copy.deepcopy(self.headers).items()
+
+    def getheader(self, key, default):
+        return self.headers.get(key, default)
+
+    def read(self, amt):
+        return self.body.read(amt)
diff --git a/tempest/tests/lib/fake_identity.py b/tempest/tests/lib/fake_identity.py
new file mode 100644
index 0000000..bac2676
--- /dev/null
+++ b/tempest/tests/lib/fake_identity.py
@@ -0,0 +1,164 @@
+# Copyright 2014 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 json
+
+import httplib2
+
+FAKE_AUTH_URL = 'http://fake_uri.com/auth'
+
+TOKEN = "fake_token"
+ALT_TOKEN = "alt_fake_token"
+
+# Fake Identity v2 constants
+COMPUTE_ENDPOINTS_V2 = {
+    "endpoints": [
+        {
+            "adminURL": "http://fake_url/v2/first_endpoint/admin",
+            "region": "NoMatchRegion",
+            "internalURL": "http://fake_url/v2/first_endpoint/internal",
+            "publicURL": "http://fake_url/v2/first_endpoint/public"
+        },
+        {
+            "adminURL": "http://fake_url/v2/second_endpoint/admin",
+            "region": "FakeRegion",
+            "internalURL": "http://fake_url/v2/second_endpoint/internal",
+            "publicURL": "http://fake_url/v2/second_endpoint/public"
+        },
+    ],
+    "type": "compute",
+    "name": "nova"
+}
+
+CATALOG_V2 = [COMPUTE_ENDPOINTS_V2, ]
+
+ALT_IDENTITY_V2_RESPONSE = {
+    "access": {
+        "token": {
+            "expires": "2020-01-01T00:00:10Z",
+            "id": ALT_TOKEN,
+            "tenant": {
+                "id": "fake_alt_tenant_id"
+            },
+        },
+        "user": {
+            "id": "fake_alt_user_id",
+        },
+        "serviceCatalog": CATALOG_V2,
+    },
+}
+
+IDENTITY_V2_RESPONSE = {
+    "access": {
+        "token": {
+            "expires": "2020-01-01T00:00:10Z",
+            "id": TOKEN,
+            "tenant": {
+                "id": "fake_tenant_id"
+            },
+        },
+        "user": {
+            "id": "fake_user_id",
+        },
+        "serviceCatalog": CATALOG_V2,
+    },
+}
+
+# Fake Identity V3 constants
+COMPUTE_ENDPOINTS_V3 = {
+    "endpoints": [
+        {
+            "id": "first_compute_fake_service",
+            "interface": "public",
+            "region": "NoMatchRegion",
+            "url": "http://fake_url/v3/first_endpoint/api"
+        },
+        {
+            "id": "second_fake_service",
+            "interface": "public",
+            "region": "FakeRegion",
+            "url": "http://fake_url/v3/second_endpoint/api"
+        },
+        {
+            "id": "third_fake_service",
+            "interface": "admin",
+            "region": "MiddleEarthRegion",
+            "url": "http://fake_url/v3/third_endpoint/api"
+        }
+
+    ],
+    "type": "compute",
+    "id": "fake_compute_endpoint"
+}
+
+CATALOG_V3 = [COMPUTE_ENDPOINTS_V3, ]
+
+IDENTITY_V3_RESPONSE = {
+    "token": {
+        "methods": [
+            "token",
+            "password"
+        ],
+        "expires_at": "2020-01-01T00:00:10.000123Z",
+        "project": {
+            "domain": {
+                "id": "fake_domain_id",
+                "name": "fake"
+            },
+            "id": "project_id",
+            "name": "project_name"
+        },
+        "user": {
+            "domain": {
+                "id": "fake_domain_id",
+                "name": "domain_name"
+            },
+            "id": "fake_user_id",
+            "name": "username"
+        },
+        "issued_at": "2013-05-29T16:55:21.468960Z",
+        "catalog": CATALOG_V3
+    }
+}
+
+ALT_IDENTITY_V3 = IDENTITY_V3_RESPONSE
+
+
+def _fake_v3_response(self, uri, method="GET", body=None, headers=None,
+                      redirections=5, connection_type=None):
+    fake_headers = {
+        "status": "201",
+        "x-subject-token": TOKEN
+    }
+    return (httplib2.Response(fake_headers),
+            json.dumps(IDENTITY_V3_RESPONSE))
+
+
+def _fake_v2_response(self, uri, method="GET", body=None, headers=None,
+                      redirections=5, connection_type=None):
+    return (httplib2.Response({"status": "200"}),
+            json.dumps(IDENTITY_V2_RESPONSE))
+
+
+def _fake_auth_failure_response():
+    # the response body isn't really used in this case, but lets send it anyway
+    # to have a safe check in some future change on the rest client.
+    body = {
+        "unauthorized": {
+            "message": "Unauthorized",
+            "code": "401"
+        }
+    }
+    return httplib2.Response({"status": "401"}), json.dumps(body)
diff --git a/tempest/api/messaging/__init__.py b/tempest/tests/lib/services/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/tests/lib/services/__init__.py
diff --git a/tempest/api/messaging/__init__.py b/tempest/tests/lib/services/compute/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/tests/lib/services/compute/__init__.py
diff --git a/tempest/tests/lib/services/compute/base.py b/tempest/tests/lib/services/compute/base.py
new file mode 100644
index 0000000..5602044
--- /dev/null
+++ b/tempest/tests/lib/services/compute/base.py
@@ -0,0 +1,45 @@
+# Copyright 2015 Deutsche Telekom AG.  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 httplib2
+from oslo_serialization import jsonutils as json
+from oslotest import mockpatch
+
+from tempest.tests.lib import base
+
+
+class BaseComputeServiceTest(base.TestCase):
+    def create_response(self, body, to_utf=False, status=200, headers=None):
+        json_body = {}
+        if body:
+            json_body = json.dumps(body)
+            if to_utf:
+                json_body = json_body.encode('utf-8')
+        resp_dict = {'status': status}
+        if headers:
+            resp_dict.update(headers)
+        response = (httplib2.Response(resp_dict), json_body)
+        return response
+
+    def check_service_client_function(self, function, function2mock,
+                                      body, to_utf=False, status=200,
+                                      headers=None, **kwargs):
+        mocked_response = self.create_response(body, to_utf, status, headers)
+        self.useFixture(mockpatch.Patch(
+            function2mock, return_value=mocked_response))
+        if kwargs:
+            resp = function(**kwargs)
+        else:
+            resp = function()
+        self.assertEqual(body, resp)
diff --git a/tempest/tests/lib/services/compute/test_agents_client.py b/tempest/tests/lib/services/compute/test_agents_client.py
new file mode 100644
index 0000000..3c5043d
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_agents_client.py
@@ -0,0 +1,103 @@
+# 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.
+
+from tempest.lib.services.compute import agents_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestAgentsClient(base.BaseComputeServiceTest):
+    FAKE_CREATE_AGENT = {
+        "agent": {
+            "url": "http://foo.com",
+            "hypervisor": "kvm",
+            "md5hash": "md5",
+            "version": "2",
+            "architecture": "x86_64",
+            "os": "linux",
+            "agent_id": 1
+        }
+    }
+
+    FAKE_UPDATE_AGENT = {
+        "agent": {
+            "url": "http://foo.com",
+            "md5hash": "md5",
+            "version": "2",
+            "agent_id": 1
+        }
+    }
+
+    def setUp(self):
+        super(TestAgentsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = agents_client.AgentsClient(fake_auth,
+                                                 'compute', 'regionOne')
+
+    def _test_list_agents(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_agents,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"agents": []},
+            bytes_body)
+        self.check_service_client_function(
+            self.client.list_agents,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"agents": []},
+            bytes_body,
+            hypervisor="kvm")
+
+    def _test_create_agent(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_agent,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_CREATE_AGENT,
+            bytes_body,
+            url="http://foo.com", hypervisor="kvm", md5hash="md5",
+            version="2", architecture="x86_64", os="linux")
+
+    def _test_delete_agent(self):
+        self.check_service_client_function(
+            self.client.delete_agent,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, agent_id="1")
+
+    def _test_update_agent(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_agent,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_UPDATE_AGENT,
+            bytes_body,
+            agent_id="1", url="http://foo.com", md5hash="md5", version="2")
+
+    def test_list_agents_with_str_body(self):
+        self._test_list_agents()
+
+    def test_list_agents_with_bytes_body(self):
+        self._test_list_agents(bytes_body=True)
+
+    def test_create_agent_with_str_body(self):
+        self._test_create_agent()
+
+    def test_create_agent_with_bytes_body(self):
+        self._test_create_agent(bytes_body=True)
+
+    def test_delete_agent(self):
+        self._test_delete_agent()
+
+    def test_update_agent_with_str_body(self):
+        self._test_update_agent()
+
+    def test_update_agent_with_bytes_body(self):
+        self._test_update_agent(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_aggregates_client.py b/tempest/tests/lib/services/compute/test_aggregates_client.py
new file mode 100644
index 0000000..a63380e
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_aggregates_client.py
@@ -0,0 +1,192 @@
+# 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.
+
+from tempest.lib.services.compute import aggregates_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestAggregatesClient(base.BaseComputeServiceTest):
+    FAKE_SHOW_AGGREGATE = {
+        "aggregate":
+        {
+            "name": "hoge",
+            "availability_zone": None,
+            "deleted": False,
+            "created_at":
+            "2015-07-16T03:07:32.000000",
+            "updated_at": None,
+            "hosts": [],
+            "deleted_at": None,
+            "id": 1,
+            "metadata": {}
+        }
+    }
+
+    FAKE_CREATE_AGGREGATE = {
+        "aggregate":
+        {
+            "name": u'\xf4',
+            "availability_zone": None,
+            "deleted": False,
+            "created_at": "2015-07-21T04:11:18.000000",
+            "updated_at": None,
+            "deleted_at": None,
+            "id": 1
+        }
+    }
+
+    FAKE_UPDATE_AGGREGATE = {
+        "aggregate":
+        {
+            "name": u'\xe9',
+            "availability_zone": None,
+            "deleted": False,
+            "created_at": "2015-07-16T03:07:32.000000",
+            "updated_at": "2015-07-23T05:16:29.000000",
+            "hosts": [],
+            "deleted_at": None,
+            "id": 1,
+            "metadata": {}
+        }
+    }
+
+    FAKE_AGGREGATE = {
+        "availability_zone": "nova",
+        "created_at": "2013-08-18T12:17:56.297823",
+        "deleted": False,
+        "deleted_at": None,
+        "hosts": [
+            "21549b2f665945baaa7101926a00143c"
+        ],
+        "id": 1,
+        "metadata": {
+            "availability_zone": "nova"
+        },
+        "name": u'\xe9',
+        "updated_at": None
+    }
+
+    FAKE_ADD_HOST = {'aggregate': FAKE_AGGREGATE}
+    FAKE_REMOVE_HOST = {'aggregate': FAKE_AGGREGATE}
+    FAKE_SET_METADATA = {'aggregate': FAKE_AGGREGATE}
+
+    def setUp(self):
+        super(TestAggregatesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = aggregates_client.AggregatesClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_list_aggregates(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_aggregates,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"aggregates": []},
+            bytes_body)
+
+    def test_list_aggregates_with_str_body(self):
+        self._test_list_aggregates()
+
+    def test_list_aggregates_with_bytes_body(self):
+        self._test_list_aggregates(bytes_body=True)
+
+    def _test_show_aggregate(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_aggregate,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SHOW_AGGREGATE,
+            bytes_body,
+            aggregate_id=1)
+
+    def test_show_aggregate_with_str_body(self):
+        self._test_show_aggregate()
+
+    def test_show_aggregate_with_bytes_body(self):
+        self._test_show_aggregate(bytes_body=True)
+
+    def _test_create_aggregate(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_aggregate,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_CREATE_AGGREGATE,
+            bytes_body,
+            name='hoge')
+
+    def test_create_aggregate_with_str_body(self):
+        self._test_create_aggregate()
+
+    def test_create_aggregate_with_bytes_body(self):
+        self._test_create_aggregate(bytes_body=True)
+
+    def test_delete_aggregate(self):
+        self.check_service_client_function(
+            self.client.delete_aggregate,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, aggregate_id="1")
+
+    def _test_update_aggregate(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_aggregate,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_UPDATE_AGGREGATE,
+            bytes_body,
+            aggregate_id=1)
+
+    def test_update_aggregate_with_str_body(self):
+        self._test_update_aggregate()
+
+    def test_update_aggregate_with_bytes_body(self):
+        self._test_update_aggregate(bytes_body=True)
+
+    def _test_add_host(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.add_host,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_ADD_HOST,
+            bytes_body,
+            aggregate_id=1)
+
+    def test_add_host_with_str_body(self):
+        self._test_add_host()
+
+    def test_add_host_with_bytes_body(self):
+        self._test_add_host(bytes_body=True)
+
+    def _test_remove_host(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.remove_host,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_REMOVE_HOST,
+            bytes_body,
+            aggregate_id=1)
+
+    def test_remove_host_with_str_body(self):
+        self._test_remove_host()
+
+    def test_remove_host_with_bytes_body(self):
+        self._test_remove_host(bytes_body=True)
+
+    def _test_set_metadata(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.set_metadata,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_SET_METADATA,
+            bytes_body,
+            aggregate_id=1)
+
+    def test_set_metadata_with_str_body(self):
+        self._test_set_metadata()
+
+    def test_set_metadata_with_bytes_body(self):
+        self._test_set_metadata(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_availability_zone_client.py b/tempest/tests/lib/services/compute/test_availability_zone_client.py
new file mode 100644
index 0000000..d16cf0a
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_availability_zone_client.py
@@ -0,0 +1,51 @@
+# 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.
+
+from tempest.lib.services.compute import availability_zone_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestAvailabilityZoneClient(base.BaseComputeServiceTest):
+
+    FAKE_AVAILABIRITY_ZONE_INFO = {
+        "availabilityZoneInfo":
+        [
+            {
+                "zoneState": {
+                    "available": True
+                },
+                "hosts": None,
+                "zoneName": u'\xf4'
+            }
+        ]
+    }
+
+    def setUp(self):
+        super(TestAvailabilityZoneClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = availability_zone_client.AvailabilityZoneClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def test_list_availability_zones_with_str_body(self):
+        self.check_service_client_function(
+            self.client.list_availability_zones,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_AVAILABIRITY_ZONE_INFO)
+
+    def test_list_availability_zones_with_bytes_body(self):
+        self.check_service_client_function(
+            self.client.list_availability_zones,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_AVAILABIRITY_ZONE_INFO, to_utf=True)
diff --git a/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py b/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py
new file mode 100644
index 0000000..a867c06
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py
@@ -0,0 +1,74 @@
+# 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.
+
+import copy
+
+from tempest.lib.services.compute import baremetal_nodes_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestBareMetalNodesClient(base.BaseComputeServiceTest):
+
+    FAKE_NODE_INFO = {'cpus': '8',
+                      'disk_gb': '64',
+                      'host': '10.0.2.15',
+                      'id': 'Identifier',
+                      'instance_uuid': "null",
+                      'interfaces': [
+                          {
+                              "address": "20::01",
+                              "datapath_id": "null",
+                              "id": 1,
+                              "port_no": None
+                          }
+                      ],
+                      'memory_mb': '8192',
+                      'task_state': None}
+
+    def setUp(self):
+        super(TestBareMetalNodesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.baremetal_nodes_client = (baremetal_nodes_client.
+                                       BaremetalNodesClient
+                                       (fake_auth, 'compute',
+                                        'regionOne'))
+
+    def _test_bareMetal_nodes(self, operation='list', bytes_body=False):
+        if operation != 'list':
+            expected = {"node": self.FAKE_NODE_INFO}
+            function = self.baremetal_nodes_client.show_baremetal_node
+        else:
+            node_info = copy.deepcopy(self.FAKE_NODE_INFO)
+            del node_info['instance_uuid']
+            expected = {"nodes": [node_info]}
+            function = self.baremetal_nodes_client.list_baremetal_nodes
+
+        self.check_service_client_function(
+            function,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected, bytes_body, 200,
+            baremetal_node_id='Identifier')
+
+    def test_list_bareMetal_nodes_with_str_body(self):
+        self._test_bareMetal_nodes()
+
+    def test_list_bareMetal_nodes_with_bytes_body(self):
+        self._test_bareMetal_nodes(bytes_body=True)
+
+    def test_show_bareMetal_node_with_str_body(self):
+        self._test_bareMetal_nodes('show')
+
+    def test_show_bareMetal_node_with_bytes_body(self):
+        self._test_bareMetal_nodes('show', True)
diff --git a/tempest/tests/lib/services/compute/test_certificates_client.py b/tempest/tests/lib/services/compute/test_certificates_client.py
new file mode 100644
index 0000000..e8123bb
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_certificates_client.py
@@ -0,0 +1,64 @@
+# 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.
+
+import copy
+
+from tempest.lib.services.compute import certificates_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestCertificatesClient(base.BaseComputeServiceTest):
+
+    FAKE_CERTIFICATE = {
+        "certificate": {
+            "data": "-----BEGIN----MIICyzCCAjSgAwI----END CERTIFICATE-----\n",
+            "private_key": None
+        }
+    }
+
+    def setUp(self):
+        super(TestCertificatesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = certificates_client.CertificatesClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_show_certificate(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_certificate,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_CERTIFICATE,
+            bytes_body,
+            certificate_id="fake-id")
+
+    def test_show_certificate_with_str_body(self):
+        self._test_show_certificate()
+
+    def test_show_certificate_with_bytes_body(self):
+        self._test_show_certificate(bytes_body=True)
+
+    def _test_create_certificate(self, bytes_body=False):
+        cert = copy.deepcopy(self.FAKE_CERTIFICATE)
+        cert['certificate']['private_key'] = "my_private_key"
+        self.check_service_client_function(
+            self.client.create_certificate,
+            'tempest.lib.common.rest_client.RestClient.post',
+            cert,
+            bytes_body)
+
+    def test_create_certificate_with_str_body(self):
+        self._test_create_certificate()
+
+    def test_create_certificate_with_bytes_body(self):
+        self._test_create_certificate(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_extensions_client.py b/tempest/tests/lib/services/compute/test_extensions_client.py
new file mode 100644
index 0000000..7415988
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_extensions_client.py
@@ -0,0 +1,65 @@
+# 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.
+
+from tempest.lib.services.compute import extensions_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestExtensionsClient(base.BaseComputeServiceTest):
+
+    FAKE_SHOW_EXTENSION = {
+        "extension": {
+            "updated": "2011-06-09T00:00:00Z",
+            "name": "Multinic",
+            "links": [],
+            "namespace":
+            "http://docs.openstack.org/compute/ext/multinic/api/v1.1",
+            "alias": "NMN",
+            "description": u'\u2740(*\xb4\u25e1`*)\u2740'
+        }
+    }
+
+    def setUp(self):
+        super(TestExtensionsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = extensions_client.ExtensionsClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_list_extensions(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_extensions,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"extensions": []},
+            bytes_body)
+
+    def test_list_extensions_with_str_body(self):
+        self._test_list_extensions()
+
+    def test_list_extensions_with_bytes_body(self):
+        self._test_list_extensions(bytes_body=True)
+
+    def _test_show_extension(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_extension,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SHOW_EXTENSION,
+            bytes_body,
+            extension_alias="NMN")
+
+    def test_show_extension_with_str_body(self):
+        self._test_show_extension()
+
+    def test_show_extension_with_bytes_body(self):
+        self._test_show_extension(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_fixedIPs_client.py b/tempest/tests/lib/services/compute/test_fixedIPs_client.py
new file mode 100644
index 0000000..6999f24
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_fixedIPs_client.py
@@ -0,0 +1,58 @@
+# 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.
+
+from tempest.lib.services.compute import fixed_ips_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestFixedIPsClient(base.BaseComputeServiceTest):
+    FIXED_IP_INFO = {"fixed_ip": {"address": "10.0.0.1",
+                                  "cidr": "10.11.12.0/24",
+                                  "host": "localhost",
+                                  "hostname": "OpenStack"}}
+
+    def setUp(self):
+        super(TestFixedIPsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.fixedIPsClient = (fixed_ips_client.
+                               FixedIPsClient
+                               (fake_auth, 'compute',
+                                'regionOne'))
+
+    def _test_show_fixed_ip(self, bytes_body=False):
+        self.check_service_client_function(
+            self.fixedIPsClient.show_fixed_ip,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FIXED_IP_INFO, bytes_body,
+            status=200, fixed_ip='Identifier')
+
+    def test_show_fixed_ip_with_str_body(self):
+        self._test_show_fixed_ip()
+
+    def test_show_fixed_ip_with_bytes_body(self):
+        self._test_show_fixed_ip(True)
+
+    def _test_reserve_fixed_ip(self, bytes_body=False):
+        self.check_service_client_function(
+            self.fixedIPsClient.reserve_fixed_ip,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {}, bytes_body,
+            status=202, fixed_ip='Identifier')
+
+    def test_reserve_fixed_ip_with_str_body(self):
+        self._test_reserve_fixed_ip()
+
+    def test_reserve_fixed_ip_with_bytes_body(self):
+        self._test_reserve_fixed_ip(True)
diff --git a/tempest/tests/lib/services/compute/test_flavors_client.py b/tempest/tests/lib/services/compute/test_flavors_client.py
new file mode 100644
index 0000000..795aff7
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_flavors_client.py
@@ -0,0 +1,255 @@
+# Copyright 2015 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 copy
+import httplib2
+
+from oslo_serialization import jsonutils as json
+from oslotest import mockpatch
+
+from tempest.lib.services.compute import flavors_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestFlavorsClient(base.BaseComputeServiceTest):
+
+    FAKE_FLAVOR = {
+        "disk": 1,
+        "id": "1",
+        "links": [{
+            "href": "http://openstack.example.com/v2/openstack/flavors/1",
+            "rel": "self"}, {
+            "href": "http://openstack.example.com/openstack/flavors/1",
+            "rel": "bookmark"}],
+        "name": "m1.tiny",
+        "ram": 512,
+        "swap": 1,
+        "vcpus": 1
+    }
+
+    EXTRA_SPECS = {"extra_specs": {
+        "key1": "value1",
+        "key2": "value2"}
+    }
+
+    FAKE_FLAVOR_ACCESS = {
+        "flavor_id": "10",
+        "tenant_id": "1a951d988e264818afe520e78697dcbf"
+    }
+
+    def setUp(self):
+        super(TestFlavorsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = flavors_client.FlavorsClient(fake_auth,
+                                                   'compute', 'regionOne')
+
+    def _test_list_flavors(self, bytes_body=False):
+        flavor = copy.deepcopy(TestFlavorsClient.FAKE_FLAVOR)
+        # Remove extra attributes
+        for attribute in ('disk', 'vcpus', 'ram', 'swap'):
+            del flavor[attribute]
+        expected = {'flavors': [flavor]}
+        self.check_service_client_function(
+            self.client.list_flavors,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected,
+            bytes_body)
+
+    def test_list_flavors_str_body(self):
+        self._test_list_flavors(bytes_body=False)
+
+    def test_list_flavors_byte_body(self):
+        self._test_list_flavors(bytes_body=True)
+
+    def _test_show_flavor(self, bytes_body=False):
+        expected = {"flavor": TestFlavorsClient.FAKE_FLAVOR}
+        self.check_service_client_function(
+            self.client.show_flavor,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected,
+            bytes_body,
+            flavor_id='fake-id')
+
+    def test_show_flavor_str_body(self):
+        self._test_show_flavor(bytes_body=False)
+
+    def test_show_flavor_byte_body(self):
+        self._test_show_flavor(bytes_body=True)
+
+    def _test_create_flavor(self, bytes_body=False):
+        expected = {"flavor": TestFlavorsClient.FAKE_FLAVOR}
+        request = copy.deepcopy(TestFlavorsClient.FAKE_FLAVOR)
+        # The 'links' parameter should not be passed in
+        del request['links']
+        self.check_service_client_function(
+            self.client.create_flavor,
+            'tempest.lib.common.rest_client.RestClient.post',
+            expected,
+            bytes_body,
+            **request)
+
+    def test_create_flavor_str_body(self):
+        self._test_create_flavor(bytes_body=False)
+
+    def test_create_flavor__byte_body(self):
+        self._test_create_flavor(bytes_body=True)
+
+    def test_delete_flavor(self):
+        self.check_service_client_function(
+            self.client.delete_flavor,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=202, flavor_id='c782b7a9-33cd-45f0-b795-7f87f456408b')
+
+    def _test_is_resource_deleted(self, flavor_id, is_deleted=True,
+                                  bytes_body=False):
+        body = json.dumps({'flavors': [TestFlavorsClient.FAKE_FLAVOR]})
+        if bytes_body:
+            body = body.encode('utf-8')
+        response = (httplib2.Response({'status': 200}), body)
+        self.useFixture(mockpatch.Patch(
+            'tempest.lib.common.rest_client.RestClient.get',
+            return_value=response))
+        self.assertEqual(is_deleted,
+                         self.client.is_resource_deleted(flavor_id))
+
+    def test_is_resource_deleted_true_str_body(self):
+        self._test_is_resource_deleted('2', bytes_body=False)
+
+    def test_is_resource_deleted_true_byte_body(self):
+        self._test_is_resource_deleted('2', bytes_body=True)
+
+    def test_is_resource_deleted_false_str_body(self):
+        self._test_is_resource_deleted('1', is_deleted=False, bytes_body=False)
+
+    def test_is_resource_deleted_false_byte_body(self):
+        self._test_is_resource_deleted('1', is_deleted=False, bytes_body=True)
+
+    def _test_set_flavor_extra_spec(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.set_flavor_extra_spec,
+            'tempest.lib.common.rest_client.RestClient.post',
+            TestFlavorsClient.EXTRA_SPECS,
+            bytes_body,
+            flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6',
+            **TestFlavorsClient.EXTRA_SPECS)
+
+    def test_set_flavor_extra_spec_str_body(self):
+        self._test_set_flavor_extra_spec(bytes_body=False)
+
+    def test_set_flavor_extra_spec_byte_body(self):
+        self._test_set_flavor_extra_spec(bytes_body=True)
+
+    def _test_list_flavor_extra_specs(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_flavor_extra_specs,
+            'tempest.lib.common.rest_client.RestClient.get',
+            TestFlavorsClient.EXTRA_SPECS,
+            bytes_body,
+            flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6')
+
+    def test_list_flavor_extra_specs_str_body(self):
+        self._test_list_flavor_extra_specs(bytes_body=False)
+
+    def test_list_flavor_extra_specs__byte_body(self):
+        self._test_list_flavor_extra_specs(bytes_body=True)
+
+    def _test_show_flavor_extra_spec(self, bytes_body=False):
+        expected = {"key": "value"}
+        self.check_service_client_function(
+            self.client.show_flavor_extra_spec,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected,
+            bytes_body,
+            flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6',
+            key='key')
+
+    def test_show_flavor_extra_spec_str_body(self):
+        self._test_show_flavor_extra_spec(bytes_body=False)
+
+    def test_show_flavor_extra_spec__byte_body(self):
+        self._test_show_flavor_extra_spec(bytes_body=True)
+
+    def _test_update_flavor_extra_spec(self, bytes_body=False):
+        expected = {"key1": "value"}
+        self.check_service_client_function(
+            self.client.update_flavor_extra_spec,
+            'tempest.lib.common.rest_client.RestClient.put',
+            expected,
+            bytes_body,
+            flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6',
+            key='key1', **expected)
+
+    def test_update_flavor_extra_spec_str_body(self):
+        self._test_update_flavor_extra_spec(bytes_body=False)
+
+    def test_update_flavor_extra_spec_byte_body(self):
+        self._test_update_flavor_extra_spec(bytes_body=True)
+
+    def test_unset_flavor_extra_spec(self):
+        self.check_service_client_function(
+            self.client.unset_flavor_extra_spec,
+            'tempest.lib.common.rest_client.RestClient.delete', {},
+            flavor_id='c782b7a9-33cd-45f0-b795-7f87f456408b', key='key')
+
+    def _test_list_flavor_access(self, bytes_body=False):
+        expected = {'flavor_access': [TestFlavorsClient.FAKE_FLAVOR_ACCESS]}
+        self.check_service_client_function(
+            self.client.list_flavor_access,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected,
+            bytes_body,
+            flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6')
+
+    def test_list_flavor_access_str_body(self):
+        self._test_list_flavor_access(bytes_body=False)
+
+    def test_list_flavor_access_byte_body(self):
+        self._test_list_flavor_access(bytes_body=True)
+
+    def _test_add_flavor_access(self, bytes_body=False):
+        expected = {
+            "flavor_access": [TestFlavorsClient.FAKE_FLAVOR_ACCESS]
+        }
+        self.check_service_client_function(
+            self.client.add_flavor_access,
+            'tempest.lib.common.rest_client.RestClient.post',
+            expected,
+            bytes_body,
+            flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6',
+            tenant_id='1a951d988e264818afe520e78697dcbf')
+
+    def test_add_flavor_access_str_body(self):
+        self._test_add_flavor_access(bytes_body=False)
+
+    def test_add_flavor_access_byte_body(self):
+        self._test_add_flavor_access(bytes_body=True)
+
+    def _test_remove_flavor_access(self, bytes_body=False):
+        expected = {
+            "flavor_access": [TestFlavorsClient.FAKE_FLAVOR_ACCESS]
+        }
+        self.check_service_client_function(
+            self.client.remove_flavor_access,
+            'tempest.lib.common.rest_client.RestClient.post',
+            expected,
+            bytes_body,
+            flavor_id='10',
+            tenant_id='a6edd4d66ad04245b5d2d8716ecc91e3')
+
+    def test_remove_flavor_access_str_body(self):
+        self._test_remove_flavor_access(bytes_body=False)
+
+    def test_remove_flavor_access_byte_body(self):
+        self._test_remove_flavor_access(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py b/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py
new file mode 100644
index 0000000..f30719e
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py
@@ -0,0 +1,46 @@
+# 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.
+
+from tempest.lib.services.compute import floating_ip_pools_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestFloatingIPPoolsClient(base.BaseComputeServiceTest):
+
+    FAKE_FLOATING_IP_POOLS = {
+        "floating_ip_pools":
+        [
+            {"name": u'\u3042'},
+            {"name": u'\u3044'}
+        ]
+    }
+
+    def setUp(self):
+        super(TestFloatingIPPoolsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = floating_ip_pools_client.FloatingIPPoolsClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def test_list_floating_ip_pools_with_str_body(self):
+        self.check_service_client_function(
+            self.client.list_floating_ip_pools,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_FLOATING_IP_POOLS)
+
+    def test_list_floating_ip_pools_with_bytes_body(self):
+        self.check_service_client_function(
+            self.client.list_floating_ip_pools,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_FLOATING_IP_POOLS, to_utf=True)
diff --git a/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py b/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py
new file mode 100644
index 0000000..c16c985
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py
@@ -0,0 +1,88 @@
+# 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.
+
+from tempest.tests.lib import fake_auth_provider
+
+from tempest.lib.services.compute import floating_ips_bulk_client
+from tempest.tests.lib.services.compute import base
+
+
+class TestFloatingIPsBulkClient(base.BaseComputeServiceTest):
+
+    FAKE_FIP_BULK_LIST = {"floating_ip_info": [{
+        "address": "10.10.10.1",
+        "instance_uuid": None,
+        "fixed_ip": None,
+        "interface": "eth0",
+        "pool": "nova",
+        "project_id": None
+        },
+        {
+        "address": "10.10.10.2",
+        "instance_uuid": None,
+        "fixed_ip": None,
+        "interface": "eth0",
+        "pool": "nova",
+        "project_id": None
+        }]}
+
+    def setUp(self):
+        super(TestFloatingIPsBulkClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = floating_ips_bulk_client.FloatingIPsBulkClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_list_floating_ips_bulk(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_floating_ips_bulk,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_FIP_BULK_LIST,
+            to_utf=bytes_body)
+
+    def _test_create_floating_ips_bulk(self, bytes_body=False):
+        fake_fip_create_data = {"floating_ips_bulk_create": {
+            "ip_range": "192.168.1.0/24", "pool": "nova", "interface": "eth0"}}
+        self.check_service_client_function(
+            self.client.create_floating_ips_bulk,
+            'tempest.lib.common.rest_client.RestClient.post',
+            fake_fip_create_data,
+            to_utf=bytes_body,
+            ip_range="192.168.1.0/24", pool="nova", interface="eth0")
+
+    def _test_delete_floating_ips_bulk(self, bytes_body=False):
+        fake_fip_delete_data = {"floating_ips_bulk_delete": "192.168.1.0/24"}
+        self.check_service_client_function(
+            self.client.delete_floating_ips_bulk,
+            'tempest.lib.common.rest_client.RestClient.put',
+            fake_fip_delete_data,
+            to_utf=bytes_body,
+            ip_range="192.168.1.0/24")
+
+    def test_list_floating_ips_bulk_with_str_body(self):
+        self._test_list_floating_ips_bulk()
+
+    def test_list_floating_ips_bulk_with_bytes_body(self):
+        self._test_list_floating_ips_bulk(True)
+
+    def test_create_floating_ips_bulk_with_str_body(self):
+        self._test_create_floating_ips_bulk()
+
+    def test_create_floating_ips_bulk_with_bytes_body(self):
+        self._test_create_floating_ips_bulk(True)
+
+    def test_delete_floating_ips_bulk_with_str_body(self):
+        self._test_delete_floating_ips_bulk()
+
+    def test_delete_floating_ips_bulk_with_bytes_body(self):
+        self._test_delete_floating_ips_bulk(True)
diff --git a/tempest/tests/lib/services/compute/test_floating_ips_client.py b/tempest/tests/lib/services/compute/test_floating_ips_client.py
new file mode 100644
index 0000000..3844ba8
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_floating_ips_client.py
@@ -0,0 +1,113 @@
+# Copyright 2015 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.
+
+from oslotest import mockpatch
+
+from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.compute import floating_ips_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestFloatingIpsClient(base.BaseComputeServiceTest):
+
+    floating_ip = {"fixed_ip": None,
+                   "id": "46d61064-13ba-4bf0-9557-69de824c3d6f",
+                   "instance_id": "a1daa443-a6bb-463e-aea2-104b7d912eb8",
+                   "ip": "10.10.10.1",
+                   "pool": "nova"}
+
+    def setUp(self):
+        super(TestFloatingIpsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = floating_ips_client.FloatingIPsClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_list_floating_ips(self, bytes_body=False):
+        expected = {'floating_ips': [TestFloatingIpsClient.floating_ip]}
+        self.check_service_client_function(
+            self.client.list_floating_ips,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected,
+            bytes_body)
+
+    def test_list_floating_ips_str_body(self):
+        self._test_list_floating_ips(bytes_body=False)
+
+    def test_list_floating_ips_byte_body(self):
+        self._test_list_floating_ips(bytes_body=True)
+
+    def _test_show_floating_ip(self, bytes_body=False):
+        expected = {"floating_ip": TestFloatingIpsClient.floating_ip}
+        self.check_service_client_function(
+            self.client.show_floating_ip,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected,
+            bytes_body,
+            floating_ip_id='a1daa443-a6bb-463e-aea2-104b7d912eb8')
+
+    def test_show_floating_ip_str_body(self):
+        self._test_show_floating_ip(bytes_body=False)
+
+    def test_show_floating_ip_byte_body(self):
+        self._test_show_floating_ip(bytes_body=True)
+
+    def _test_create_floating_ip(self, bytes_body=False):
+        expected = {"floating_ip": TestFloatingIpsClient.floating_ip}
+        self.check_service_client_function(
+            self.client.create_floating_ip,
+            'tempest.lib.common.rest_client.RestClient.post',
+            expected,
+            bytes_body,
+            pool_name='nova')
+
+    def test_create_floating_ip_str_body(self):
+        self._test_create_floating_ip(bytes_body=False)
+
+    def test_create_floating_ip_byte_body(self):
+        self._test_create_floating_ip(bytes_body=True)
+
+    def test_delete_floating_ip(self):
+        self.check_service_client_function(
+            self.client.delete_floating_ip,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=202, floating_ip_id='fake-id')
+
+    def test_associate_floating_ip_to_server(self):
+        self.check_service_client_function(
+            self.client.associate_floating_ip_to_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {}, status=202, floating_ip='10.10.10.1',
+            server_id='c782b7a9-33cd-45f0-b795-7f87f456408b')
+
+    def test_disassociate_floating_ip_from_server(self):
+        self.check_service_client_function(
+            self.client.disassociate_floating_ip_from_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {}, status=202, floating_ip='10.10.10.1',
+            server_id='c782b7a9-33cd-45f0-b795-7f87f456408b')
+
+    def test_is_resource_deleted_true(self):
+        self.useFixture(mockpatch.Patch(
+            'tempest.lib.services.compute.floating_ips_client.'
+            'FloatingIPsClient.show_floating_ip',
+            side_effect=lib_exc.NotFound()))
+        self.assertTrue(self.client.is_resource_deleted('fake-id'))
+
+    def test_is_resource_deleted_false(self):
+        self.useFixture(mockpatch.Patch(
+            'tempest.lib.services.compute.floating_ips_client.'
+            'FloatingIPsClient.show_floating_ip',
+            return_value={"floating_ip": TestFloatingIpsClient.floating_ip}))
+        self.assertFalse(self.client.is_resource_deleted('fake-id'))
diff --git a/tempest/tests/lib/services/compute/test_hosts_client.py b/tempest/tests/lib/services/compute/test_hosts_client.py
new file mode 100644
index 0000000..d9ff513
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_hosts_client.py
@@ -0,0 +1,147 @@
+# 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.
+
+from tempest.lib.services.compute import hosts_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestHostsClient(base.BaseComputeServiceTest):
+    FAKE_HOST_DATA = {
+        "host": {
+            "resource": {
+                "cpu": 1,
+                "disk_gb": 1028,
+                "host": "c1a7de0ac9d94e4baceae031d05caae3",
+                "memory_mb": 8192,
+                "project": "(total)"
+                }
+        },
+        "hosts": {
+            "host_name": "c1a7de0ac9d94e4baceae031d05caae3",
+            "service": "conductor",
+            "zone": "internal"
+        },
+        "enable_hosts": {
+            "host": "65c5d5b7e3bd44308e67fc50f362aee6",
+            "maintenance_mode": "off_maintenance",
+            "status": "enabled"
+        }
+        }
+
+    FAKE_CONTROL_DATA = {
+        "shutdown": {
+            "host": "c1a7de0ac9d94e4baceae031d05caae3",
+            "power_action": "shutdown"
+        },
+        "startup": {
+            "host": "c1a7de0ac9d94e4baceae031d05caae3",
+            "power_action": "startup"
+        },
+        "reboot": {
+            "host": "c1a7de0ac9d94e4baceae031d05caae3",
+            "power_action": "reboot"
+        }}
+
+    HOST_DATA = {'host': [FAKE_HOST_DATA['host']]}
+    HOSTS_DATA = {'hosts': [FAKE_HOST_DATA['hosts']]}
+    ENABLE_HOST_DATA = FAKE_HOST_DATA['enable_hosts']
+    HOST_ID = "c1a7de0ac9d94e4baceae031d05caae3"
+    TEST_HOST_DATA = {
+        "status": "enable",
+        "maintenance_mode": "disable"
+    }
+
+    def setUp(self):
+        super(TestHostsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = hosts_client.HostsClient(fake_auth, 'compute',
+                                               'regionOne')
+        self.params = {'hostname': self.HOST_ID}
+        self.func2mock = {
+            'get': 'tempest.lib.common.rest_client.RestClient.get',
+            'put': 'tempest.lib.common.rest_client.RestClient.put'}
+
+    def _test_host_data(self, test_type='list', bytes_body=False):
+        expected_resp = self.HOST_DATA
+        if test_type != 'list':
+            function_call = self.client.show_host
+        else:
+            expected_resp = self.HOSTS_DATA
+            function_call = self.client.list_hosts
+            self.params = {'host_name': self.HOST_ID}
+
+        self.check_service_client_function(
+            function_call, self.func2mock['get'],
+            expected_resp, bytes_body,
+            200, **self.params)
+
+    def _test_update_hosts(self, bytes_body=False):
+        expected_resp = self.ENABLE_HOST_DATA
+        self.check_service_client_function(
+            self.client.update_host, self.func2mock['put'],
+            expected_resp, bytes_body,
+            200, **self.params)
+
+    def _test_control_host(self, control_op='reboot', bytes_body=False):
+        if control_op == 'start':
+            expected_resp = self.FAKE_CONTROL_DATA['startup']
+            function_call = self.client.startup_host
+        elif control_op == 'stop':
+            expected_resp = self.FAKE_CONTROL_DATA['shutdown']
+            function_call = self.client.shutdown_host
+        else:
+            expected_resp = self.FAKE_CONTROL_DATA['reboot']
+            function_call = self.client.reboot_host
+
+        self.check_service_client_function(
+            function_call, self.func2mock['get'],
+            expected_resp, bytes_body,
+            200, **self.params)
+
+    def test_show_host_with_str_body(self):
+        self._test_host_data('show')
+
+    def test_show_host_with_bytes_body(self):
+        self._test_host_data('show', True)
+
+    def test_list_host_with_str_body(self):
+        self._test_host_data()
+
+    def test_list_host_with_bytes_body(self):
+        self._test_host_data(bytes_body=True)
+
+    def test_start_host_with_str_body(self):
+        self._test_control_host('start')
+
+    def test_start_host_with_bytes_body(self):
+        self._test_control_host('start', True)
+
+    def test_stop_host_with_str_body(self):
+        self._test_control_host('stop')
+
+    def test_stop_host_with_bytes_body(self):
+        self._test_control_host('stop', True)
+
+    def test_reboot_host_with_str_body(self):
+        self._test_control_host('reboot')
+
+    def test_reboot_host_with_bytes_body(self):
+        self._test_control_host('reboot', True)
+
+    def test_update_host_with_str_body(self):
+        self._test_update_hosts()
+
+    def test_update_host_with_bytes_body(self):
+        self._test_update_hosts(True)
diff --git a/tempest/tests/lib/services/compute/test_hypervisor_client.py b/tempest/tests/lib/services/compute/test_hypervisor_client.py
new file mode 100644
index 0000000..fab34da
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_hypervisor_client.py
@@ -0,0 +1,167 @@
+# Copyright 2015 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.
+
+from tempest.lib.services.compute import hypervisor_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestHypervisorClient(base.BaseComputeServiceTest):
+
+    hypervisor_id = "1"
+    hypervisor_name = "hyper.hostname.com"
+
+    def setUp(self):
+        super(TestHypervisorClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = hypervisor_client.HypervisorClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def test_list_hypervisor_str_body(self):
+        self._test_list_hypervisor(bytes_body=False)
+
+    def test_list_hypervisor_byte_body(self):
+        self._test_list_hypervisor(bytes_body=True)
+
+    def _test_list_hypervisor(self, bytes_body=False):
+        expected = {"hypervisors": [{
+            "id": 1,
+            "hypervisor_hostname": "hypervisor1.hostname.com"},
+            {
+            "id": 2,
+            "hypervisor_hostname": "hypervisor2.hostname.com"}]}
+        self.check_service_client_function(
+            self.client.list_hypervisors,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected, bytes_body)
+
+    def test_show_hypervisor_str_body(self):
+        self._test_show_hypervisor(bytes_body=False)
+
+    def test_show_hypervisor_byte_body(self):
+        self._test_show_hypervisor(bytes_body=True)
+
+    def _test_show_hypervisor(self, bytes_body=False):
+        expected = {"hypervisor": {
+            "cpu_info": "?",
+            "current_workload": 0,
+            "disk_available_least": 1,
+            "host_ip": "10.10.10.10",
+            "free_disk_gb": 1028,
+            "free_ram_mb": 7680,
+            "hypervisor_hostname": "fake-mini",
+            "hypervisor_type": "fake",
+            "hypervisor_version": 1,
+            "id": 1,
+            "local_gb": 1028,
+            "local_gb_used": 0,
+            "memory_mb": 8192,
+            "memory_mb_used": 512,
+            "running_vms": 0,
+            "service": {
+                "host": "fake_host",
+                "id": 2},
+            "vcpus": 1,
+            "vcpus_used": 0}}
+        self.check_service_client_function(
+            self.client.show_hypervisor,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected, bytes_body,
+            hypervisor_id=self.hypervisor_id)
+
+    def test_list_servers_on_hypervisor_str_body(self):
+        self._test_list_servers_on_hypervisor(bytes_body=False)
+
+    def test_list_servers_on_hypervisor_byte_body(self):
+        self._test_list_servers_on_hypervisor(bytes_body=True)
+
+    def _test_list_servers_on_hypervisor(self, bytes_body=False):
+        expected = {"hypervisors": [{
+            "id": 1,
+            "hypervisor_hostname": "hyper.hostname.com",
+            "servers": [{
+                "uuid": "e1ae8fc4-b72d-4c2f-a427-30dd420b6277",
+                "name": "instance-00000001"},
+                {
+                "uuid": "e1ae8fc4-b72d-4c2f-a427-30dd42066666",
+                "name": "instance-00000002"}
+                ]}
+            ]}
+        self.check_service_client_function(
+            self.client.list_servers_on_hypervisor,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected, bytes_body,
+            hypervisor_name=self.hypervisor_name)
+
+    def test_show_hypervisor_statistics_str_body(self):
+        self._test_show_hypervisor_statistics(bytes_body=False)
+
+    def test_show_hypervisor_statistics_byte_body(self):
+        self._test_show_hypervisor_statistics(bytes_body=True)
+
+    def _test_show_hypervisor_statistics(self, bytes_body=False):
+        expected = {
+            "hypervisor_statistics": {
+                "count": 1,
+                "current_workload": 0,
+                "disk_available_least": 0,
+                "free_disk_gb": 1028,
+                "free_ram_mb": 7680,
+                "local_gb": 1028,
+                "local_gb_used": 0,
+                "memory_mb": 8192,
+                "memory_mb_used": 512,
+                "running_vms": 0,
+                "vcpus": 1,
+                "vcpus_used": 0}}
+        self.check_service_client_function(
+            self.client.show_hypervisor_statistics,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected, bytes_body)
+
+    def test_show_hypervisor_uptime_str_body(self):
+        self._test_show_hypervisor_uptime(bytes_body=False)
+
+    def test_show_hypervisor_uptime_byte_body(self):
+        self._test_show_hypervisor_uptime(bytes_body=True)
+
+    def _test_show_hypervisor_uptime(self, bytes_body=False):
+        expected = {
+            "hypervisor": {
+                "hypervisor_hostname": "fake-mini",
+                "id": 1,
+                "uptime": (" 08:32:11 up 93 days, 18:25, 12 users, "
+                           " load average: 0.20, 0.12, 0.14")
+            }}
+        self.check_service_client_function(
+            self.client.show_hypervisor_uptime,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected, bytes_body,
+            hypervisor_id=self.hypervisor_id)
+
+    def test_search_hypervisor_str_body(self):
+        self._test_search_hypervisor(bytes_body=False)
+
+    def test_search_hypervisor_byte_body(self):
+        self._test_search_hypervisor(bytes_body=True)
+
+    def _test_search_hypervisor(self, bytes_body=False):
+        expected = {"hypervisors": [{
+            "id": 2,
+            "hypervisor_hostname": "hyper.hostname.com"}]}
+        self.check_service_client_function(
+            self.client.search_hypervisor,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected, bytes_body,
+            hypervisor_name=self.hypervisor_name)
diff --git a/tempest/tests/lib/services/compute/test_images_client.py b/tempest/tests/lib/services/compute/test_images_client.py
new file mode 100644
index 0000000..28757c3
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_images_client.py
@@ -0,0 +1,265 @@
+# 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.
+
+import copy
+
+from oslotest import mockpatch
+
+from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.compute import images_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestImagesClient(base.BaseComputeServiceTest):
+    # Data Dictionaries used for testing #
+    FAKE_IMAGE_METADATA = {
+        "list":
+            {"metadata": {
+             "auto_disk_config": "True",
+             "Label": "Changed"
+             }},
+        "set_item":
+            {"meta": {
+             "auto_disk_config": "True"
+             }},
+        "show_item":
+            {"meta": {
+             "kernel_id": "nokernel",
+             }},
+        "update":
+            {"metadata": {
+             "kernel_id": "False",
+             "Label": "UpdatedImage"
+             }},
+        "set":
+            {"metadata": {
+             "Label": "Changed",
+             "auto_disk_config": "True"
+             }},
+        "delete_item": {}
+        }
+
+    FAKE_IMAGE_DATA = {
+        "list":
+            {"images": [
+             {"id": "70a599e0-31e7-49b7-b260-868f441e862b",
+              "links": [
+                    {"href": "http://openstack.example.com/v2/openstack" +
+                             "/images/70a599e0-31e7-49b7-b260-868f441e862b",
+                     "rel": "self"
+                     }
+              ],
+              "name": "fakeimage7"
+              }]},
+        "show": {"image": {
+            "created": "2011-01-01T01:02:03Z",
+            "id": "70a599e0-31e7-49b7-b260-868f441e862b",
+            "links": [
+                {
+                    "href": "http://openstack.example.com/v2/openstack" +
+                            "/images/70a599e0-31e7-49b7-b260-868f441e862b",
+                    "rel": "self"
+                },
+            ],
+            "metadata": {
+                "architecture": "x86_64",
+                "auto_disk_config": "True",
+                "kernel_id": "nokernel",
+                "ramdisk_id": "nokernel"
+            },
+            "minDisk": 0,
+            "minRam": 0,
+            "name": "fakeimage7",
+            "progress": 100,
+            "status": "ACTIVE",
+            "updated": "2011-01-01T01:02:03Z"}},
+        "create": {},
+        "delete": {}
+        }
+    func2mock = {
+        'get': 'tempest.lib.common.rest_client.RestClient.get',
+        'post': 'tempest.lib.common.rest_client.RestClient.post',
+        'put': 'tempest.lib.common.rest_client.RestClient.put',
+        'delete': 'tempest.lib.common.rest_client.RestClient.delete'}
+    # Variable definition
+    FAKE_IMAGE_ID = FAKE_IMAGE_DATA['show']['image']['id']
+    FAKE_SERVER_ID = "80a599e0-31e7-49b7-b260-868f441e343f"
+    FAKE_CREATE_INFO = {'location': 'None'}
+    FAKE_METADATA = FAKE_IMAGE_METADATA['show_item']['meta']
+
+    def setUp(self):
+        super(TestImagesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = images_client.ImagesClient(fake_auth,
+                                                 "compute", "regionOne")
+
+    def _test_image_operation(self, operation="delete", bytes_body=False):
+        response_code = 200
+        mock_operation = self.func2mock['get']
+        expected_op = self.FAKE_IMAGE_DATA[operation]
+        params = {"image_id": self.FAKE_IMAGE_ID}
+        headers = None
+        if operation == 'list':
+            function = self.client.list_images
+        elif operation == 'show':
+            function = self.client.show_image
+        elif operation == 'create':
+            function = self.client.create_image
+            mock_operation = self.func2mock['post']
+            params = {"server_id": self.FAKE_SERVER_ID}
+            response_code = 202
+            headers = {
+                'connection': 'keep-alive',
+                'content-length': '0',
+                'content-type': 'application/json',
+                'status': '202',
+                'x-compute-request-id': 'req-fake',
+                'vary': 'accept-encoding',
+                'x-openstack-nova-api-version': 'v2.1',
+                'date': '13 Oct 2015 05:55:36 GMT',
+                'location': 'http://fake.com/images/fake'
+            }
+        else:
+            function = self.client.delete_image
+            mock_operation = self.func2mock['delete']
+            response_code = 204
+
+        self.check_service_client_function(
+            function, mock_operation, expected_op,
+            bytes_body, response_code, headers, **params)
+
+    def _test_image_metadata(self, operation="set_item", bytes_body=False):
+        response_code = 200
+        expected_op = self.FAKE_IMAGE_METADATA[operation]
+        if operation == 'list':
+            function = self.client.list_image_metadata
+            mock_operation = self.func2mock['get']
+            params = {"image_id": self.FAKE_IMAGE_ID}
+
+        elif operation == 'set':
+            function = self.client.set_image_metadata
+            mock_operation = self.func2mock['put']
+            params = {"image_id": "_dummy_data",
+                      "meta": self.FAKE_METADATA}
+
+        elif operation == 'update':
+            function = self.client.update_image_metadata
+            mock_operation = self.func2mock['post']
+            params = {"image_id": self.FAKE_IMAGE_ID,
+                      "meta": self.FAKE_METADATA}
+
+        elif operation == 'show_item':
+            mock_operation = self.func2mock['get']
+            function = self.client.show_image_metadata_item
+            params = {"image_id": self.FAKE_IMAGE_ID,
+                      "key": "123"}
+
+        elif operation == 'delete_item':
+            function = self.client.delete_image_metadata_item
+            mock_operation = self.func2mock['delete']
+            response_code = 204
+            params = {"image_id": self.FAKE_IMAGE_ID,
+                      "key": "123"}
+
+        else:
+            function = self.client.set_image_metadata_item
+            mock_operation = self.func2mock['put']
+            params = {"image_id": self.FAKE_IMAGE_ID,
+                      "key": "123",
+                      "meta": self.FAKE_METADATA}
+
+        self.check_service_client_function(
+            function, mock_operation, expected_op,
+            bytes_body, response_code, **params)
+
+    def _test_resource_deleted(self, bytes_body=False):
+        params = {"id": self.FAKE_IMAGE_ID}
+        expected_op = self.FAKE_IMAGE_DATA['show']['image']
+        self.useFixture(mockpatch.Patch('tempest.lib.services.compute'
+                        '.images_client.ImagesClient.show_image',
+                                        side_effect=lib_exc.NotFound))
+        self.assertEqual(True, self.client.is_resource_deleted(**params))
+        tempdata = copy.deepcopy(self.FAKE_IMAGE_DATA['show'])
+        tempdata['image']['id'] = None
+        self.useFixture(mockpatch.Patch('tempest.lib.services.compute'
+                        '.images_client.ImagesClient.show_image',
+                                        return_value=expected_op))
+        self.assertEqual(False, self.client.is_resource_deleted(**params))
+
+    def test_list_images_with_str_body(self):
+        self._test_image_operation('list')
+
+    def test_list_images_with_bytes_body(self):
+        self._test_image_operation('list', True)
+
+    def test_show_image_with_str_body(self):
+        self._test_image_operation('show')
+
+    def test_show_image_with_bytes_body(self):
+        self._test_image_operation('show', True)
+
+    def test_create_image_with_str_body(self):
+        self._test_image_operation('create')
+
+    def test_create_image_with_bytes_body(self):
+        self._test_image_operation('create', True)
+
+    def test_delete_image_with_str_body(self):
+        self._test_image_operation('delete')
+
+    def test_delete_image_with_bytes_body(self):
+        self._test_image_operation('delete', True)
+
+    def test_list_image_metadata_with_str_body(self):
+        self._test_image_metadata('list')
+
+    def test_list_image_metadata_with_bytes_body(self):
+        self._test_image_metadata('list', True)
+
+    def test_set_image_metadata_with_str_body(self):
+        self._test_image_metadata('set')
+
+    def test_set_image_metadata_with_bytes_body(self):
+        self._test_image_metadata('set', True)
+
+    def test_update_image_metadata_with_str_body(self):
+        self._test_image_metadata('update')
+
+    def test_update_image_metadata_with_bytes_body(self):
+        self._test_image_metadata('update', True)
+
+    def test_set_image_metadata_item_with_str_body(self):
+        self._test_image_metadata()
+
+    def test_set_image_metadata_item_with_bytes_body(self):
+        self._test_image_metadata(bytes_body=True)
+
+    def test_show_image_metadata_item_with_str_body(self):
+        self._test_image_metadata('show_item')
+
+    def test_show_image_metadata_item_with_bytes_body(self):
+        self._test_image_metadata('show_item', True)
+
+    def test_delete_image_metadata_item_with_str_body(self):
+        self._test_image_metadata('delete_item')
+
+    def test_delete_image_metadata_item_with_bytes_body(self):
+        self._test_image_metadata('delete_item', True)
+
+    def test_resource_delete_with_str_body(self):
+        self._test_resource_deleted()
+
+    def test_resource_delete_with_bytes_body(self):
+        self._test_resource_deleted(True)
diff --git a/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py b/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py
new file mode 100644
index 0000000..e8c22f1
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py
@@ -0,0 +1,73 @@
+# 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.
+
+import datetime
+
+from tempest.lib.services.compute import instance_usage_audit_log_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestInstanceUsagesAuditLogClient(base.BaseComputeServiceTest):
+
+    FAKE_AUDIT_LOG = {
+        "hosts_not_run": [
+            "f4eb7cfd155f4574967f8b55a7faed75"
+        ],
+        "log": {},
+        "num_hosts": 1,
+        "num_hosts_done": 0,
+        "num_hosts_not_run": 1,
+        "num_hosts_running": 0,
+        "overall_status": "0 of 1 hosts done. 0 errors.",
+        "period_beginning": "2012-12-01 00:00:00",
+        "period_ending": "2013-01-01 00:00:00",
+        "total_errors": 0,
+        "total_instances": 0
+    }
+
+    def setUp(self):
+        super(TestInstanceUsagesAuditLogClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = (instance_usage_audit_log_client.
+                       InstanceUsagesAuditLogClient(fake_auth, 'compute',
+                                                    'regionOne'))
+
+    def _test_list_instance_usage_audit_logs(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_instance_usage_audit_logs,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"instance_usage_audit_logs": self.FAKE_AUDIT_LOG},
+            bytes_body)
+
+    def test_list_instance_usage_audit_logs_with_str_body(self):
+        self._test_list_instance_usage_audit_logs()
+
+    def test_list_instance_usage_audit_logs_with_bytes_body(self):
+        self._test_list_instance_usage_audit_logs(bytes_body=True)
+
+    def _test_show_instance_usage_audit_log(self, bytes_body=False):
+        before_time = datetime.datetime(2012, 12, 1, 0, 0)
+        self.check_service_client_function(
+            self.client.show_instance_usage_audit_log,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"instance_usage_audit_log": self.FAKE_AUDIT_LOG},
+            bytes_body,
+            time_before=before_time)
+
+    def test_show_instance_usage_audit_log_with_str_body(self):
+        self._test_show_instance_usage_audit_log()
+
+    def test_show_network_with_bytes_body_with_bytes_body(self):
+        self._test_show_instance_usage_audit_log(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_interfaces_client.py b/tempest/tests/lib/services/compute/test_interfaces_client.py
new file mode 100644
index 0000000..de8e268
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_interfaces_client.py
@@ -0,0 +1,98 @@
+# 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.
+
+from tempest.lib.services.compute import interfaces_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestInterfacesClient(base.BaseComputeServiceTest):
+    # Data Values to be used for testing #
+    FAKE_INTERFACE_DATA = {
+        "fixed_ips": [{
+            "ip_address": "192.168.1.1",
+            "subnet_id": "f8a6e8f8-c2ec-497c-9f23-da9616de54ef"
+            }],
+        "mac_addr": "fa:16:3e:4c:2c:30",
+        "net_id": "3cb9bc59-5699-4588-a4b1-b87f96708bc6",
+        "port_id": "ce531f90-199f-48c0-816c-13e38010b442",
+        "port_state": "ACTIVE"}
+
+    FAKE_SHOW_DATA = {
+        "interfaceAttachment": FAKE_INTERFACE_DATA}
+    FAKE_LIST_DATA = {
+        "interfaceAttachments": [FAKE_INTERFACE_DATA]}
+
+    FAKE_SERVER_ID = "ec14c864-096e-4e27-bb8a-2c2b4dc6f3f5"
+    FAKE_PORT_ID = FAKE_SHOW_DATA['interfaceAttachment']['port_id']
+    func2mock = {
+        'delete': 'tempest.lib.common.rest_client.RestClient.delete',
+        'get': 'tempest.lib.common.rest_client.RestClient.get',
+        'post': 'tempest.lib.common.rest_client.RestClient.post'}
+
+    def setUp(self):
+        super(TestInterfacesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = interfaces_client.InterfacesClient(fake_auth,
+                                                         "compute",
+                                                         "regionOne")
+
+    def _test_interface_operation(self, operation="create", bytes_body=False):
+        response_code = 200
+        expected_op = self.FAKE_SHOW_DATA
+        mock_operation = self.func2mock['get']
+        params = {'server_id': self.FAKE_SERVER_ID,
+                  'port_id': self.FAKE_PORT_ID}
+        if operation == 'list':
+            expected_op = self.FAKE_LIST_DATA
+            function = self.client.list_interfaces
+            params = {'server_id': self.FAKE_SERVER_ID}
+        elif operation == 'show':
+            function = self.client.show_interface
+        elif operation == 'delete':
+            expected_op = {}
+            mock_operation = self.func2mock['delete']
+            function = self.client.delete_interface
+            response_code = 202
+        else:
+            function = self.client.create_interface
+            mock_operation = self.func2mock['post']
+
+        self.check_service_client_function(
+            function, mock_operation, expected_op,
+            bytes_body, response_code, **params)
+
+    def test_list_interfaces_with_str_body(self):
+        self._test_interface_operation('list')
+
+    def test_list_interfaces_with_bytes_body(self):
+        self._test_interface_operation('list', True)
+
+    def test_show_interface_with_str_body(self):
+        self._test_interface_operation('show')
+
+    def test_show_interface_with_bytes_body(self):
+        self._test_interface_operation('show', True)
+
+    def test_delete_interface_with_str_body(self):
+        self._test_interface_operation('delete')
+
+    def test_delete_interface_with_bytes_body(self):
+        self._test_interface_operation('delete', True)
+
+    def test_create_interface_with_str_body(self):
+        self._test_interface_operation()
+
+    def test_create_interface_with_bytes_body(self):
+        self._test_interface_operation(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_keypairs_client.py b/tempest/tests/lib/services/compute/test_keypairs_client.py
new file mode 100644
index 0000000..7c595ca
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_keypairs_client.py
@@ -0,0 +1,94 @@
+# 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.
+
+import copy
+
+from tempest.lib.services.compute import keypairs_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestKeyPairsClient(base.BaseComputeServiceTest):
+
+    FAKE_KEYPAIR = {"keypair": {
+        "public_key": "ssh-rsa foo Generated-by-Nova",
+        "name": u'\u2740(*\xb4\u25e1`*)\u2740',
+        "user_id": "525d55f98980415ba98e634972fa4a10",
+        "fingerprint": "76:24:66:49:d7:ca:6e:5c:77:ea:8e:bb:9c:15:5f:98"
+        }}
+
+    def setUp(self):
+        super(TestKeyPairsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = keypairs_client.KeyPairsClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_list_keypairs(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_keypairs,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"keypairs": []},
+            bytes_body)
+
+    def test_list_keypairs_with_str_body(self):
+        self._test_list_keypairs()
+
+    def test_list_keypairs_with_bytes_body(self):
+        self._test_list_keypairs(bytes_body=True)
+
+    def _test_show_keypair(self, bytes_body=False):
+        fake_keypair = copy.deepcopy(self.FAKE_KEYPAIR)
+        fake_keypair["keypair"].update({
+            "deleted": False,
+            "created_at": "2015-07-22T04:53:52.000000",
+            "updated_at": None,
+            "deleted_at": None,
+            "id": 1
+            })
+
+        self.check_service_client_function(
+            self.client.show_keypair,
+            'tempest.lib.common.rest_client.RestClient.get',
+            fake_keypair,
+            bytes_body,
+            keypair_name="test")
+
+    def test_show_keypair_with_str_body(self):
+        self._test_show_keypair()
+
+    def test_show_keypair_with_bytes_body(self):
+        self._test_show_keypair(bytes_body=True)
+
+    def _test_create_keypair(self, bytes_body=False):
+        fake_keypair = copy.deepcopy(self.FAKE_KEYPAIR)
+        fake_keypair["keypair"].update({"private_key": "foo"})
+
+        self.check_service_client_function(
+            self.client.create_keypair,
+            'tempest.lib.common.rest_client.RestClient.post',
+            fake_keypair,
+            bytes_body,
+            name="test")
+
+    def test_create_keypair_with_str_body(self):
+        self._test_create_keypair()
+
+    def test_create_keypair_with_bytes_body(self):
+        self._test_create_keypair(bytes_body=True)
+
+    def test_delete_keypair(self):
+        self.check_service_client_function(
+            self.client.delete_keypair,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=202, keypair_name='test')
diff --git a/tempest/tests/lib/services/compute/test_limits_client.py b/tempest/tests/lib/services/compute/test_limits_client.py
new file mode 100644
index 0000000..d3f0aee
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_limits_client.py
@@ -0,0 +1,66 @@
+# 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.
+
+from tempest.lib.services.compute import limits_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestLimitsClient(base.BaseComputeServiceTest):
+
+    def setUp(self):
+        super(TestLimitsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = limits_client.LimitsClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_show_limits(self, bytes_body=False):
+        expected = {
+            "limits": {
+                "rate": [],
+                "absolute": {
+                    "maxServerMeta": 128,
+                    "maxPersonality": 5,
+                    "totalServerGroupsUsed": 0,
+                    "maxImageMeta": 128,
+                    "maxPersonalitySize": 10240,
+                    "maxServerGroups": 10,
+                    "maxSecurityGroupRules": 20,
+                    "maxTotalKeypairs": 100,
+                    "totalCoresUsed": 0,
+                    "totalRAMUsed": 0,
+                    "totalInstancesUsed": 0,
+                    "maxSecurityGroups": 10,
+                    "totalFloatingIpsUsed": 0,
+                    "maxTotalCores": 20,
+                    "totalSecurityGroupsUsed": 0,
+                    "maxTotalFloatingIps": 10,
+                    "maxTotalInstances": 10,
+                    "maxTotalRAMSize": 51200,
+                    "maxServerGroupMembers": 10
+                    }
+            }
+        }
+
+        self.check_service_client_function(
+            self.client.show_limits,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected,
+            bytes_body)
+
+    def test_show_limits_with_str_body(self):
+        self._test_show_limits()
+
+    def test_show_limits_with_bytes_body(self):
+        self._test_show_limits(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_migrations_client.py b/tempest/tests/lib/services/compute/test_migrations_client.py
new file mode 100644
index 0000000..5b1578d
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_migrations_client.py
@@ -0,0 +1,52 @@
+# 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.
+
+from tempest.lib.services.compute import migrations_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestMigrationsClient(base.BaseComputeServiceTest):
+    FAKE_MIGRATION_INFO = {"migrations": [{
+        "created_at": "2012-10-29T13:42:02",
+        "dest_compute": "compute2",
+        "dest_host": "1.2.3.4",
+        "dest_node": "node2",
+        "id": 1234,
+        "instance_uuid": "e9e4fdd7-f956-44ff-bfeb-d654a96ab3a2",
+        "new_instance_type_id": 2,
+        "old_instance_type_id": 1,
+        "source_compute": "compute1",
+        "source_node": "node1",
+        "status": "finished",
+        "updated_at": "2012-10-29T13:42:02"}]}
+
+    def setUp(self):
+        super(TestMigrationsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.mg_client_obj = migrations_client.MigrationsClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_list_migrations(self, bytes_body=False):
+        self.check_service_client_function(
+            self.mg_client_obj.list_migrations,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_MIGRATION_INFO,
+            bytes_body)
+
+    def test_list_migration_with_str_body(self):
+        self._test_list_migrations()
+
+    def test_list_migration_with_bytes_body(self):
+        self._test_list_migrations(True)
diff --git a/tempest/tests/lib/services/compute/test_networks_client.py b/tempest/tests/lib/services/compute/test_networks_client.py
new file mode 100644
index 0000000..4f5c8b9
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_networks_client.py
@@ -0,0 +1,94 @@
+# 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.
+
+from tempest.lib.services.compute import networks_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestNetworksClient(base.BaseComputeServiceTest):
+
+    FAKE_NETWORK = {
+        "bridge": None,
+        "vpn_public_port": None,
+        "dhcp_start": None,
+        "bridge_interface": None,
+        "share_address": None,
+        "updated_at": None,
+        "id": "34d5ae1e-5659-49cf-af80-73bccd7d7ad3",
+        "cidr_v6": None,
+        "deleted_at": None,
+        "gateway": None,
+        "rxtx_base": None,
+        "label": u'30d7',
+        "priority": None,
+        "project_id": None,
+        "vpn_private_address": None,
+        "deleted": None,
+        "vlan": None,
+        "broadcast": None,
+        "netmask": None,
+        "injected": None,
+        "cidr": None,
+        "vpn_public_address": None,
+        "multi_host": None,
+        "enable_dhcp": None,
+        "dns2": None,
+        "created_at": None,
+        "host": None,
+        "mtu": None,
+        "gateway_v6": None,
+        "netmask_v6": None,
+        "dhcp_server": None,
+        "dns1": None
+        }
+
+    network_id = "34d5ae1e-5659-49cf-af80-73bccd7d7ad3"
+
+    FAKE_NETWORKS = [FAKE_NETWORK]
+
+    def setUp(self):
+        super(TestNetworksClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = networks_client.NetworksClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_list_networks(self, bytes_body=False):
+        fake_list = {"networks": self.FAKE_NETWORKS}
+        self.check_service_client_function(
+            self.client.list_networks,
+            'tempest.lib.common.rest_client.RestClient.get',
+            fake_list,
+            bytes_body)
+
+    def test_list_networks_with_str_body(self):
+        self._test_list_networks()
+
+    def test_list_networks_with_bytes_body(self):
+        self._test_list_networks(bytes_body=True)
+
+    def _test_show_network(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_network,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"network": self.FAKE_NETWORK},
+            bytes_body,
+            network_id=self.network_id
+            )
+
+    def test_show_network_with_str_body(self):
+        self._test_show_network()
+
+    def test_show_network_with_bytes_body(self):
+        self._test_show_network(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_quota_classes_client.py b/tempest/tests/lib/services/compute/test_quota_classes_client.py
new file mode 100644
index 0000000..4b67576
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_quota_classes_client.py
@@ -0,0 +1,71 @@
+# 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.
+
+import copy
+
+from tempest.lib.services.compute import quota_classes_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestQuotaClassesClient(base.BaseComputeServiceTest):
+
+    FAKE_QUOTA_CLASS_SET = {
+        "injected_file_content_bytes": 10240,
+        "metadata_items": 128,
+        "server_group_members": 10,
+        "server_groups": 10,
+        "ram": 51200,
+        "floating_ips": 10,
+        "key_pairs": 100,
+        "id": u'\u2740(*\xb4\u25e1`*)\u2740',
+        "instances": 10,
+        "security_group_rules": 20,
+        "security_groups": 10,
+        "injected_files": 5,
+        "cores": 20,
+        "fixed_ips": -1,
+        "injected_file_path_bytes": 255,
+        }
+
+    def setUp(self):
+        super(TestQuotaClassesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = quota_classes_client.QuotaClassesClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_show_quota_class_set(self, bytes_body=False):
+        fake_body = {'quota_class_set': self.FAKE_QUOTA_CLASS_SET}
+        self.check_service_client_function(
+            self.client.show_quota_class_set,
+            'tempest.lib.common.rest_client.RestClient.get',
+            fake_body,
+            bytes_body,
+            quota_class_id="test")
+
+    def test_show_quota_class_set_with_str_body(self):
+        self._test_show_quota_class_set()
+
+    def test_show_quota_class_set_with_bytes_body(self):
+        self._test_show_quota_class_set(bytes_body=True)
+
+    def test_update_quota_class_set(self):
+        fake_quota_class_set = copy.deepcopy(self.FAKE_QUOTA_CLASS_SET)
+        fake_quota_class_set.pop("id")
+        fake_body = {'quota_class_set': fake_quota_class_set}
+        self.check_service_client_function(
+            self.client.update_quota_class_set,
+            'tempest.lib.common.rest_client.RestClient.put',
+            fake_body,
+            quota_class_id="test")
diff --git a/tempest/tests/lib/services/compute/test_quotas_client.py b/tempest/tests/lib/services/compute/test_quotas_client.py
new file mode 100644
index 0000000..9f5d1f6
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_quotas_client.py
@@ -0,0 +1,130 @@
+# 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.
+
+import copy
+
+from tempest.lib.services.compute import quotas_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestQuotasClient(base.BaseComputeServiceTest):
+
+    FAKE_QUOTA_SET = {
+        "quota_set": {
+            "injected_file_content_bytes": 10240,
+            "metadata_items": 128,
+            "server_group_members": 10,
+            "server_groups": 10,
+            "ram": 51200,
+            "floating_ips": 10,
+            "key_pairs": 100,
+            "id": "8421f7be61064f50b680465c07f334af",
+            "instances": 10,
+            "security_group_rules": 20,
+            "injected_files": 5,
+            "cores": 20,
+            "fixed_ips": -1,
+            "injected_file_path_bytes": 255,
+            "security_groups": 10}
+        }
+
+    project_id = "8421f7be61064f50b680465c07f334af"
+    fake_user_id = "65f09168cbb04eb593f3138b63b67b67"
+
+    def setUp(self):
+        super(TestQuotasClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = quotas_client.QuotasClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_show_quota_set(self, bytes_body=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,
+                to_utf=bytes_body,
+                tenant_id=self.project_id,
+                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,
+                to_utf=bytes_body,
+                tenant_id=self.project_id)
+
+    def test_show_quota_set_with_str_body(self):
+        self._test_show_quota_set()
+
+    def test_show_quota_set_with_bytes_body(self):
+        self._test_show_quota_set(bytes_body=True)
+
+    def test_show_quota_set_for_user_with_str_body(self):
+        self._test_show_quota_set(user_id=self.fake_user_id)
+
+    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_default_quota_set(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_default_quota_set,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_QUOTA_SET,
+            to_utf=bytes_body,
+            tenant_id=self.project_id)
+
+    def test_show_default_quota_set_with_str_body(self):
+        self._test_show_default_quota_set()
+
+    def test_show_default_quota_set_with_bytes_body(self):
+        self._test_show_default_quota_set(bytes_body=True)
+
+    def _test_update_quota_set(self, bytes_body=False, user_id=None):
+        fake_quota_set = copy.deepcopy(self.FAKE_QUOTA_SET)
+        fake_quota_set['quota_set'].pop("id")
+        if user_id:
+            self.check_service_client_function(
+                self.client.update_quota_set,
+                'tempest.lib.common.rest_client.RestClient.put',
+                fake_quota_set,
+                to_utf=bytes_body,
+                tenant_id=self.project_id,
+                user_id=user_id)
+        else:
+            self.check_service_client_function(
+                self.client.update_quota_set,
+                'tempest.lib.common.rest_client.RestClient.put',
+                fake_quota_set,
+                to_utf=bytes_body,
+                tenant_id=self.project_id)
+
+    def test_update_quota_set_with_str_body(self):
+        self._test_update_quota_set()
+
+    def test_update_quota_set_with_bytes_body(self):
+        self._test_update_quota_set(bytes_body=True)
+
+    def test_update_quota_set_for_user_with_str_body(self):
+        self._test_update_quota_set(user_id=self.fake_user_id)
+
+    def test_update_quota_set_for_user_with_bytes_body(self):
+        self._test_update_quota_set(bytes_body=True, user_id=self.fake_user_id)
+
+    def test_delete_quota_set(self):
+        self.check_service_client_function(
+            self.client.delete_quota_set,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=202, tenant_id=self.project_id)
diff --git a/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py b/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py
new file mode 100644
index 0000000..581f7b1
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py
@@ -0,0 +1,88 @@
+# 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.
+
+from tempest.lib.services.compute import security_group_default_rules_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestSecurityGroupDefaultRulesClient(base.BaseComputeServiceTest):
+    FAKE_RULE = {
+        "from_port": 80,
+        "id": 1,
+        "ip_protocol": "TCP",
+        "ip_range": {
+            "cidr": "10.10.10.0/24"
+        },
+        "to_port": 80
+    }
+
+    def setUp(self):
+        super(TestSecurityGroupDefaultRulesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = (security_group_default_rules_client.
+                       SecurityGroupDefaultRulesClient(fake_auth, 'compute',
+                                                       'regionOne'))
+
+    def _test_list_security_group_default_rules(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_security_group_default_rules,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"security_group_default_rules": [self.FAKE_RULE]},
+            to_utf=bytes_body)
+
+    def test_list_security_group_default_rules_with_str_body(self):
+        self._test_list_security_group_default_rules()
+
+    def test_list_security_group_default_rules_with_bytes_body(self):
+        self._test_list_security_group_default_rules(bytes_body=True)
+
+    def _test_show_security_group_default_rule(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_security_group_default_rule,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"security_group_default_rule": self.FAKE_RULE},
+            to_utf=bytes_body,
+            security_group_default_rule_id=1)
+
+    def test_show_security_group_default_rule_with_str_body(self):
+        self._test_show_security_group_default_rule()
+
+    def test_show_security_group_default_rule_with_bytes_body(self):
+        self._test_show_security_group_default_rule(bytes_body=True)
+
+    def _test_create_security_default_group_rule(self, bytes_body=False):
+        request_body = {
+            "to_port": 80,
+            "from_port": 80,
+            "ip_protocol": "TCP",
+            "cidr": "10.10.10.0/24"
+        }
+        self.check_service_client_function(
+            self.client.create_security_default_group_rule,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {"security_group_default_rule": self.FAKE_RULE},
+            to_utf=bytes_body, **request_body)
+
+    def test_create_security_default_group_rule_with_str_body(self):
+        self._test_create_security_default_group_rule()
+
+    def test_create_security_default_group_rule_with_bytes_body(self):
+        self._test_create_security_default_group_rule(bytes_body=True)
+
+    def test_delete_security_group_default_rule(self):
+        self.check_service_client_function(
+            self.client.delete_security_group_default_rule,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=204, security_group_default_rule_id=1)
diff --git a/tempest/tests/lib/services/compute/test_security_group_rules_client.py b/tempest/tests/lib/services/compute/test_security_group_rules_client.py
new file mode 100644
index 0000000..9a7c04d
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_security_group_rules_client.py
@@ -0,0 +1,66 @@
+# 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.
+
+from tempest.lib.services.compute import security_group_rules_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestSecurityGroupRulesClient(base.BaseComputeServiceTest):
+
+    FAKE_SECURITY_GROUP_RULE = {
+        "security_group_rule": {
+            "id": "2d021cf1-ce4b-4292-994f-7a785d62a144",
+            "ip_range": {
+                "cidr": "0.0.0.0/0"
+            },
+            "parent_group_id": "48700ff3-30b8-4e63-845f-a79c9633e9fb",
+            "to_port": 443,
+            "ip_protocol": "tcp",
+            "group": {},
+            "from_port": 443
+        }
+    }
+
+    def setUp(self):
+        super(TestSecurityGroupRulesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = security_group_rules_client.SecurityGroupRulesClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_create_security_group_rule(self, bytes_body=False):
+        req_body = {
+            "from_port": "443",
+            "ip_protocol": "tcp",
+            "to_port": "443",
+            "cidr": "0.0.0.0/0",
+            "parent_group_id": "48700ff3-30b8-4e63-845f-a79c9633e9fb"
+        }
+        self.check_service_client_function(
+            self.client.create_security_group_rule,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_SECURITY_GROUP_RULE,
+            to_utf=bytes_body, **req_body)
+
+    def test_create_security_group_rule_with_str_body(self):
+        self._test_create_security_group_rule()
+
+    def test_create_security_group_rule_with_bytes_body(self):
+        self._test_create_security_group_rule(bytes_body=True)
+
+    def test_delete_security_group_rule(self):
+        self.check_service_client_function(
+            self.client.delete_security_group_rule,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=202, group_rule_id='group-id')
diff --git a/tempest/tests/lib/services/compute/test_security_groups_client.py b/tempest/tests/lib/services/compute/test_security_groups_client.py
new file mode 100644
index 0000000..6a11c29
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_security_groups_client.py
@@ -0,0 +1,113 @@
+# 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.
+
+from oslotest import mockpatch
+
+from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.compute import security_groups_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestSecurityGroupsClient(base.BaseComputeServiceTest):
+
+    FAKE_SECURITY_GROUP_INFO = [{
+        "description": "default",
+        "id": "3fb26eb3-581b-4420-9963-b0879a026506",
+        "name": "default",
+        "rules": [],
+        "tenant_id": "openstack"
+    }]
+
+    def setUp(self):
+        super(TestSecurityGroupsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = security_groups_client.SecurityGroupsClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_list_security_groups(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_security_groups,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"security_groups": self.FAKE_SECURITY_GROUP_INFO},
+            to_utf=bytes_body)
+
+    def test_list_security_groups_with_str_body(self):
+        self._test_list_security_groups()
+
+    def test_list_security_groups_with_bytes_body(self):
+        self._test_list_security_groups(bytes_body=True)
+
+    def _test_show_security_group(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_security_group,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"security_group": self.FAKE_SECURITY_GROUP_INFO[0]},
+            to_utf=bytes_body,
+            security_group_id='fake-id')
+
+    def test_show_security_group_with_str_body(self):
+        self._test_show_security_group()
+
+    def test_show_security_group_with_bytes_body(self):
+        self._test_show_security_group(bytes_body=True)
+
+    def _test_create_security_group(self, bytes_body=False):
+        post_body = {"name": "test", "description": "test_group"}
+        self.check_service_client_function(
+            self.client.create_security_group,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {"security_group": self.FAKE_SECURITY_GROUP_INFO[0]},
+            to_utf=bytes_body,
+            kwargs=post_body)
+
+    def test_create_security_group_with_str_body(self):
+        self._test_create_security_group()
+
+    def test_create_security_group_with_bytes_body(self):
+        self._test_create_security_group(bytes_body=True)
+
+    def _test_update_security_group(self, bytes_body=False):
+        req_body = {"name": "test", "description": "test_group"}
+        self.check_service_client_function(
+            self.client.update_security_group,
+            'tempest.lib.common.rest_client.RestClient.put',
+            {"security_group": self.FAKE_SECURITY_GROUP_INFO[0]},
+            to_utf=bytes_body,
+            security_group_id='fake-id',
+            kwargs=req_body)
+
+    def test_update_security_group_with_str_body(self):
+        self._test_update_security_group()
+
+    def test_update_security_group_with_bytes_body(self):
+        self._test_update_security_group(bytes_body=True)
+
+    def test_delete_security_group(self):
+        self.check_service_client_function(
+            self.client.delete_security_group,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=202, security_group_id='fake-id')
+
+    def test_is_resource_deleted_true(self):
+        mod = ('tempest.lib.services.compute.security_groups_client.'
+               'SecurityGroupsClient.show_security_group')
+        self.useFixture(mockpatch.Patch(mod, side_effect=lib_exc.NotFound))
+        self.assertTrue(self.client.is_resource_deleted('fake-id'))
+
+    def test_is_resource_deleted_false(self):
+        mod = ('tempest.lib.services.compute.security_groups_client.'
+               'SecurityGroupsClient.show_security_group')
+        self.useFixture(mockpatch.Patch(mod, return_value='success'))
+        self.assertFalse(self.client.is_resource_deleted('fake-id'))
diff --git a/tempest/tests/lib/services/compute/test_server_groups_client.py b/tempest/tests/lib/services/compute/test_server_groups_client.py
new file mode 100644
index 0000000..f1f2906
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_server_groups_client.py
@@ -0,0 +1,84 @@
+# Copyright 2015 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 httplib2
+
+from oslotest import mockpatch
+from tempest.tests.lib import fake_auth_provider
+
+from tempest.lib.services.compute import server_groups_client
+from tempest.tests.lib.services.compute import base
+
+
+class TestServerGroupsClient(base.BaseComputeServiceTest):
+
+    server_group = {
+        "id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9",
+        "name": "test",
+        "policies": ["anti-affinity"],
+        "members": [],
+        "metadata": {}}
+
+    def setUp(self):
+        super(TestServerGroupsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = server_groups_client.ServerGroupsClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_create_server_group(self, bytes_body=False):
+        expected = {"server_group": TestServerGroupsClient.server_group}
+        self.check_service_client_function(
+            self.client.create_server_group,
+            'tempest.lib.common.rest_client.RestClient.post', expected,
+            bytes_body, name='fake-group', policies=['affinity'])
+
+    def test_create_server_group_str_body(self):
+        self._test_create_server_group(bytes_body=False)
+
+    def test_create_server_group_byte_body(self):
+        self._test_create_server_group(bytes_body=True)
+
+    def test_delete_server_group(self):
+        response = (httplib2.Response({'status': 204}), None)
+        self.useFixture(mockpatch.Patch(
+            'tempest.lib.common.rest_client.RestClient.delete',
+            return_value=response))
+        self.client.delete_server_group('fake-group')
+
+    def _test_list_server_groups(self, bytes_body=False):
+        expected = {"server_groups": [TestServerGroupsClient.server_group]}
+        self.check_service_client_function(
+            self.client.list_server_groups,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected, bytes_body)
+
+    def test_list_server_groups_str_body(self):
+        self._test_list_server_groups(bytes_body=False)
+
+    def test_list_server_groups_byte_body(self):
+        self._test_list_server_groups(bytes_body=True)
+
+    def _test_show_server_group(self, bytes_body=False):
+        expected = {"server_group": TestServerGroupsClient.server_group}
+        self.check_service_client_function(
+            self.client.show_server_group,
+            'tempest.lib.common.rest_client.RestClient.get',
+            expected, bytes_body,
+            server_group_id='5bbcc3c4-1da2-4437-a48a-66f15b1b13f9')
+
+    def test_show_server_group_str_body(self):
+        self._test_show_server_group(bytes_body=False)
+
+    def test_show_server_group_byte_body(self):
+        self._test_show_server_group(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_servers_client.py b/tempest/tests/lib/services/compute/test_servers_client.py
new file mode 100644
index 0000000..0078497
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_servers_client.py
@@ -0,0 +1,1011 @@
+# Copyright 2015 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 copy
+
+from tempest.lib.services.compute import servers_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestServersClient(base.BaseComputeServiceTest):
+
+    FAKE_SERVERS = {'servers': [{
+        "id": "616fb98f-46ca-475e-917e-2563e5a8cd19",
+        "links": [
+            {
+                "href": "http://os.co/v2/616fb98f-46ca-475e-917e-2563e5a8cd19",
+                "rel": "self"
+            },
+            {
+                "href": "http://os.co/616fb98f-46ca-475e-917e-2563e5a8cd19",
+                "rel": "bookmark"
+            }
+        ],
+        "name": u"new\u1234-server-test"}]
+    }
+
+    FAKE_SERVER_DIAGNOSTICS = {
+        "cpu0_time": 17300000000,
+        "memory": 524288,
+        "vda_errors": -1,
+        "vda_read": 262144,
+        "vda_read_req": 112,
+        "vda_write": 5778432,
+        "vda_write_req": 488,
+        "vnet1_rx": 2070139,
+        "vnet1_rx_drop": 0,
+        "vnet1_rx_errors": 0,
+        "vnet1_rx_packets": 26701,
+        "vnet1_tx": 140208,
+        "vnet1_tx_drop": 0,
+        "vnet1_tx_errors": 0,
+        "vnet1_tx_packets": 662
+    }
+
+    FAKE_SERVER_GET = {'server': {
+        "accessIPv4": "",
+        "accessIPv6": "",
+        "addresses": {
+            "private": [
+                {
+                    "addr": "192.168.0.3",
+                    "version": 4
+                }
+            ]
+        },
+        "created": "2012-08-20T21:11:09Z",
+        "flavor": {
+            "id": "1",
+            "links": [
+                {
+                    "href": "http://os.com/openstack/flavors/1",
+                    "rel": "bookmark"
+                }
+            ]
+        },
+        "hostId": "65201c14a29663e06d0748e561207d998b343e1d164bfa0aafa9c45d",
+        "id": "893c7791-f1df-4c3d-8383-3caae9656c62",
+        "image": {
+            "id": "70a599e0-31e7-49b7-b260-868f441e862b",
+            "links": [
+                {
+                    "href": "http://imgs/70a599e0-31e7-49b7-b260-868f441e862b",
+                    "rel": "bookmark"
+                }
+            ]
+        },
+        "links": [
+            {
+                "href": "http://v2/srvs/893c7791-f1df-4c3d-8383-3caae9656c62",
+                "rel": "self"
+            },
+            {
+                "href": "http://srvs/893c7791-f1df-4c3d-8383-3caae9656c62",
+                "rel": "bookmark"
+            }
+        ],
+        "metadata": {
+            u"My Server N\u1234me": u"Apa\u1234che1"
+        },
+        "name": u"new\u1234-server-test",
+        "progress": 0,
+        "status": "ACTIVE",
+        "tenant_id": "openstack",
+        "updated": "2012-08-20T21:11:09Z",
+        "user_id": "fake"}
+    }
+
+    FAKE_SERVER_POST = {"server": {
+        "id": "616fb98f-46ca-475e-917e-2563e5a8cd19",
+        "adminPass": "fake-admin-pass",
+        "security_groups": [
+            'fake-security-group-1',
+            'fake-security-group-2'
+        ],
+        "links": [
+            {
+                "href": "http://os.co/v2/616fb98f-46ca-475e-917e-2563e5a8cd19",
+                "rel": "self"
+            },
+            {
+                "href": "http://os.co/616fb98f-46ca-475e-917e-2563e5a8cd19",
+                "rel": "bookmark"
+            }
+        ],
+        "OS-DCF:diskConfig": "fake-disk-config"}
+    }
+
+    FAKE_ADDRESS = {"addresses": {
+        "private": [
+            {
+                "addr": "192.168.0.3",
+                "version": 4
+            }
+        ]}
+    }
+
+    FAKE_COMMON_VOLUME = {
+        "id": "a6b0875b-6b5d-4a5a-81eb-0c3aa62e5fdb",
+        "device": "fake-device",
+        "volumeId": "a6b0875b-46ca-475e-917e-0c3aa62e5fdb",
+        "serverId": "616fb98f-46ca-475e-917e-2563e5a8cd19"
+    }
+
+    FAKE_VIRTUAL_INTERFACES = {
+        "id": "a6b0875b-46ca-475e-917e-0c3aa62e5fdb",
+        "mac_address": "00:25:90:5b:f8:c3",
+        "OS-EXT-VIF-NET:net_id": "fake-os-net-id"
+    }
+
+    FAKE_INSTANCE_ACTIONS = {
+        "action": "fake-action",
+        "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",
+        "message": "fake-msg",
+        "instance_uuid": "16fb98f-46ca-475e-917e-2563e5a8cd12"
+    }
+
+    FAKE_VNC_CONSOLE = {
+        "type": "fake-type",
+        "url": "http://os.co/v2/616fb98f-46ca-475e-917e-2563e5a8cd19"
+    }
+
+    FAKE_INSTANCE_ACTION_EVENTS = {
+        "event": "fake-event",
+        "start_time": "09MAR2015 11:15",
+        "finish_time": "09MAR2015 11:15",
+        "result": "fake-result",
+        "traceback": "fake-trace-back"
+    }
+
+    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'
+
+    server_id = FAKE_SERVER_GET['server']['id']
+    network_id = 'a6b0875b-6b5d-4a5a-81eb-0c3aa62e5fdb'
+
+    def setUp(self):
+        super(TestServersClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = servers_client.ServersClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def test_list_servers_with_str_body(self):
+        self._test_list_servers()
+
+    def test_list_servers_with_bytes_body(self):
+        self._test_list_servers(bytes_body=True)
+
+    def _test_list_servers(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_servers,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SERVERS,
+            bytes_body)
+
+    def test_show_server_with_str_body(self):
+        self._test_show_server()
+
+    def test_show_server_with_bytes_body(self):
+        self._test_show_server(bytes_body=True)
+
+    def _test_show_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_server,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SERVER_GET,
+            bytes_body,
+            server_id=self.server_id
+            )
+
+    def test_delete_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.delete_server,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            status=204,
+            server_id=self.server_id
+            )
+
+    def test_create_server_with_str_body(self):
+        self._test_create_server()
+
+    def test_create_server_with_bytes_body(self):
+        self._test_create_server(True)
+
+    def _test_create_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_SERVER_POST,
+            bytes_body,
+            status=202,
+            name='fake-name',
+            imageRef='fake-image-ref',
+            flavorRef='fake-flavor-ref'
+            )
+
+    def test_list_addresses_with_str_body(self):
+        self._test_list_addresses()
+
+    def test_list_addresses_with_bytes_body(self):
+        self._test_list_addresses(True)
+
+    def _test_list_addresses(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_addresses,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_ADDRESS,
+            bytes_body,
+            server_id=self.server_id
+            )
+
+    def test_list_addresses_by_network_with_str_body(self):
+        self._test_list_addresses_by_network()
+
+    def test_list_addresses_by_network_with_bytes_body(self):
+        self._test_list_addresses_by_network(True)
+
+    def _test_list_addresses_by_network(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_addresses_by_network,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_ADDRESS['addresses'],
+            server_id=self.server_id,
+            network_id=self.network_id
+            )
+
+    def test_action_with_str_body(self):
+        self._test_action()
+
+    def test_action_with_bytes_body(self):
+        self._test_action(True)
+
+    def _test_action(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.action,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            server_id=self.server_id,
+            action_name='fake-action-name',
+            schema={'status_code': 200}
+            )
+
+    def test_create_backup_with_str_body(self):
+        self._test_create_backup()
+
+    def test_create_backup_with_bytes_body(self):
+        self._test_create_backup(True)
+
+    def _test_create_backup(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_backup,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id,
+            backup_type='fake-backup',
+            rotation='fake-rotation',
+            name='fake-name'
+            )
+
+    def test_change_password_with_str_body(self):
+        self._test_change_password()
+
+    def test_change_password_with_bytes_body(self):
+        self._test_change_password(True)
+
+    def _test_change_password(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.change_password,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id,
+            adminPass='fake-admin-pass'
+            )
+
+    def test_show_password_with_str_body(self):
+        self._test_show_password()
+
+    def test_show_password_with_bytes_body(self):
+        self._test_show_password(True)
+
+    def _test_show_password(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_password,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {'password': 'fake-password'},
+            server_id=self.server_id
+            )
+
+    def test_delete_password_with_str_body(self):
+        self._test_delete_password()
+
+    def test_delete_password_with_bytes_body(self):
+        self._test_delete_password(True)
+
+    def _test_delete_password(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.delete_password,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            status=204,
+            server_id=self.server_id
+            )
+
+    def test_reboot_server_with_str_body(self):
+        self._test_reboot_server()
+
+    def test_reboot_server_with_bytes_body(self):
+        self._test_reboot_server(True)
+
+    def _test_reboot_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.reboot_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id,
+            type='fake-reboot-type'
+            )
+
+    def test_rebuild_server_with_str_body(self):
+        self._test_rebuild_server()
+
+    def test_rebuild_server_with_bytes_body(self):
+        self._test_rebuild_server(True)
+
+    def _test_rebuild_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.rebuild_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_REBUILD_SERVER,
+            status=202,
+            server_id=self.server_id,
+            image_ref='fake-image-ref'
+            )
+
+    def test_resize_server_with_str_body(self):
+        self._test_resize_server()
+
+    def test_resize_server_with_bytes_body(self):
+        self._test_resize_server(True)
+
+    def _test_resize_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.resize_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id,
+            flavor_ref='fake-flavor-ref'
+            )
+
+    def test_confirm_resize_server_with_str_body(self):
+        self._test_confirm_resize_server()
+
+    def test_confirm_resize_server_with_bytes_body(self):
+        self._test_confirm_resize_server(True)
+
+    def _test_confirm_resize_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.confirm_resize_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=204,
+            server_id=self.server_id
+            )
+
+    def test_revert_resize_server_with_str_body(self):
+        self._test_revert_resize()
+
+    def test_revert_resize_server_with_bytes_body(self):
+        self._test_revert_resize(True)
+
+    def _test_revert_resize(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.revert_resize_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_list_server_metadata_with_str_body(self):
+        self._test_list_server_metadata()
+
+    def test_list_server_metadata_with_bytes_body(self):
+        self._test_list_server_metadata()
+
+    def _test_list_server_metadata(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_server_metadata,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {'metadata': {'fake-key': 'fake-meta-data'}},
+            server_id=self.server_id
+            )
+
+    def test_set_server_metadata_with_str_body(self):
+        self._test_set_server_metadata()
+
+    def test_set_server_metadata_with_bytes_body(self):
+        self._test_set_server_metadata(True)
+
+    def _test_set_server_metadata(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.set_server_metadata,
+            'tempest.lib.common.rest_client.RestClient.put',
+            {'metadata': {'fake-key': 'fake-meta-data'}},
+            server_id=self.server_id,
+            meta='fake-meta'
+            )
+
+    def test_update_server_metadata_with_str_body(self):
+        self._test_update_server_metadata()
+
+    def test_update_server_metadata_with_bytes_body(self):
+        self._test_update_server_metadata(True)
+
+    def _test_update_server_metadata(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_server_metadata,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {'metadata': {'fake-key': 'fake-meta-data'}},
+            server_id=self.server_id,
+            meta='fake-meta'
+            )
+
+    def test_show_server_metadata_item_with_str_body(self):
+        self._test_show_server_metadata()
+
+    def test_show_server_metadata_item_with_bytes_body(self):
+        self._test_show_server_metadata(True)
+
+    def _test_show_server_metadata(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_server_metadata_item,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {'meta': {'fake-key': 'fake-meta-data'}},
+            server_id=self.server_id,
+            key='fake-key'
+            )
+
+    def test_set_server_metadata_item_with_str_body(self):
+        self._test_set_server_metadata_item()
+
+    def test_set_server_metadata_item_with_bytes_body(self):
+        self._test_set_server_metadata_item(True)
+
+    def _test_set_server_metadata_item(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.set_server_metadata_item,
+            'tempest.lib.common.rest_client.RestClient.put',
+            {'meta': {'fake-key': 'fake-meta-data'}},
+            server_id=self.server_id,
+            key='fake-key',
+            meta='fake-meta'
+            )
+
+    def test_delete_server_metadata_item_with_str_body(self):
+        self._test_delete_server_metadata()
+
+    def test_delete_server_metadata_item_with_bytes_body(self):
+        self._test_delete_server_metadata(True)
+
+    def _test_delete_server_metadata(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.delete_server_metadata_item,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            status=204,
+            server_id=self.server_id,
+            key='fake-key'
+            )
+
+    def test_stop_server_with_str_body(self):
+        self._test_stop_server()
+
+    def test_stop_server_with_bytes_body(self):
+        self._test_stop_server(True)
+
+    def _test_stop_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.stop_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_start_server_with_str_body(self):
+        self._test_start_server()
+
+    def test_start_server_with_bytes_body(self):
+        self._test_start_server(True)
+
+    def _test_start_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.start_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_attach_volume_with_str_body(self):
+        self._test_attach_volume_server()
+
+    def test_attach_volume_with_bytes_body(self):
+        self._test_attach_volume_server(True)
+
+    def _test_attach_volume_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.attach_volume,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {'volumeAttachment': self.FAKE_COMMON_VOLUME},
+            server_id=self.server_id
+            )
+
+    def test_update_attached_volume(self):
+        self.check_service_client_function(
+            self.client.update_attached_volume,
+            'tempest.lib.common.rest_client.RestClient.put',
+            {},
+            status=202,
+            server_id=self.server_id,
+            attachment_id='fake-attachment-id',
+            volumeId='fake-volume-id'
+            )
+
+    def test_detach_volume_with_str_body(self):
+        self._test_detach_volume_server()
+
+    def test_detach_volume_with_bytes_body(self):
+        self._test_detach_volume_server(True)
+
+    def _test_detach_volume_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.detach_volume,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            status=202,
+            server_id=self.server_id,
+            volume_id=self.FAKE_COMMON_VOLUME['volumeId']
+            )
+
+    def test_show_volume_attachment_with_str_body(self):
+        self._test_show_volume_attachment()
+
+    def test_show_volume_attachment_with_bytes_body(self):
+        self._test_show_volume_attachment(True)
+
+    def _test_show_volume_attachment(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_volume_attachment,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {'volumeAttachment': self.FAKE_COMMON_VOLUME},
+            server_id=self.server_id,
+            volume_id=self.FAKE_COMMON_VOLUME['volumeId']
+            )
+
+    def test_list_volume_attachments_with_str_body(self):
+        self._test_list_volume_attachments()
+
+    def test_list_volume_attachments_with_bytes_body(self):
+        self._test_list_volume_attachments(True)
+
+    def _test_list_volume_attachments(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_volume_attachments,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {'volumeAttachments': [self.FAKE_COMMON_VOLUME]},
+            server_id=self.server_id
+            )
+
+    def test_add_security_group_with_str_body(self):
+        self._test_add_security_group()
+
+    def test_add_security_group_with_bytes_body(self):
+        self._test_add_security_group(True)
+
+    def _test_add_security_group(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.add_security_group,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id,
+            name='fake-name'
+            )
+
+    def test_remove_security_group_with_str_body(self):
+        self._test_remove_security_group()
+
+    def test_remove_security_group_with_bytes_body(self):
+        self._test_remove_security_group(True)
+
+    def _test_remove_security_group(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.remove_security_group,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id,
+            name='fake-name'
+            )
+
+    def test_live_migrate_server_with_str_body(self):
+        self._test_live_migrate_server()
+
+    def test_live_migrate_server_with_bytes_body(self):
+        self._test_live_migrate_server(True)
+
+    def _test_live_migrate_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.live_migrate_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_migrate_server_with_str_body(self):
+        self._test_migrate_server()
+
+    def test_migrate_server_with_bytes_body(self):
+        self._test_migrate_server(True)
+
+    def _test_migrate_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.migrate_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_lock_server_with_str_body(self):
+        self._test_lock_server()
+
+    def test_lock_server_with_bytes_body(self):
+        self._test_lock_server(True)
+
+    def _test_lock_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.lock_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_unlock_server_with_str_body(self):
+        self._test_unlock_server()
+
+    def test_unlock_server_with_bytes_body(self):
+        self._test_unlock_server(True)
+
+    def _test_unlock_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.unlock_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_suspend_server_with_str_body(self):
+        self._test_suspend_server()
+
+    def test_suspend_server_with_bytes_body(self):
+        self._test_suspend_server(True)
+
+    def _test_suspend_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.suspend_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_resume_server_with_str_body(self):
+        self._test_resume_server()
+
+    def test_resume_server_with_bytes_body(self):
+        self._test_resume_server(True)
+
+    def _test_resume_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.resume_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_pause_server_with_str_body(self):
+        self._test_pause_server()
+
+    def test_pause_server_with_bytes_body(self):
+        self._test_pause_server(True)
+
+    def _test_pause_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.pause_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_unpause_server_with_str_body(self):
+        self._test_unpause_server()
+
+    def test_unpause_server_with_bytes_body(self):
+        self._test_unpause_server(True)
+
+    def _test_unpause_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.unpause_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_reset_state_with_str_body(self):
+        self._test_reset_state()
+
+    def test_reset_state_with_bytes_body(self):
+        self._test_reset_state(True)
+
+    def _test_reset_state(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.reset_state,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id,
+            state='fake-state'
+            )
+
+    def test_shelve_server_with_str_body(self):
+        self._test_shelve_server()
+
+    def test_shelve_server_with_bytes_body(self):
+        self._test_shelve_server(True)
+
+    def _test_shelve_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.shelve_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_unshelve_server_with_str_body(self):
+        self._test_unshelve_server()
+
+    def test_unshelve_server_with_bytes_body(self):
+        self._test_unshelve_server(True)
+
+    def _test_unshelve_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.unshelve_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_shelve_offload_server_with_str_body(self):
+        self._test_shelve_offload_server()
+
+    def test_shelve_offload_server_with_bytes_body(self):
+        self._test_shelve_offload_server(True)
+
+    def _test_shelve_offload_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.shelve_offload_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_get_console_output_with_str_body(self):
+        self._test_get_console_output()
+
+    def test_get_console_output_with_bytes_body(self):
+        self._test_get_console_output(True)
+
+    def _test_get_console_output(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.get_console_output,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {'output': 'fake-output'},
+            server_id=self.server_id,
+            length='fake-length'
+            )
+
+    def test_list_virtual_interfaces_with_str_body(self):
+        self._test_list_virtual_interfaces()
+
+    def test_list_virtual_interfaces_with_bytes_body(self):
+        self._test_list_virtual_interfaces(True)
+
+    def _test_list_virtual_interfaces(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_virtual_interfaces,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {'virtual_interfaces': [self.FAKE_VIRTUAL_INTERFACES]},
+            server_id=self.server_id
+            )
+
+    def test_rescue_server_with_str_body(self):
+        self._test_rescue_server()
+
+    def test_rescue_server_with_bytes_body(self):
+        self._test_rescue_server(True)
+
+    def _test_rescue_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.rescue_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {'adminPass': 'fake-admin-pass'},
+            server_id=self.server_id
+            )
+
+    def test_unrescue_server_with_str_body(self):
+        self._test_unrescue_server()
+
+    def test_unrescue_server_with_bytes_body(self):
+        self._test_unrescue_server(True)
+
+    def _test_unrescue_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.unrescue_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_show_server_diagnostics_with_str_body(self):
+        self._test_show_server_diagnostics()
+
+    def test_show_server_diagnostics_with_bytes_body(self):
+        self._test_show_server_diagnostics(True)
+
+    def _test_show_server_diagnostics(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_server_diagnostics,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SERVER_DIAGNOSTICS,
+            status=200,
+            server_id=self.server_id
+            )
+
+    def test_list_instance_actions_with_str_body(self):
+        self._test_list_instance_actions()
+
+    def test_list_instance_actions_with_bytes_body(self):
+        self._test_list_instance_actions(True)
+
+    def _test_list_instance_actions(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_instance_actions,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {'instanceActions': [self.FAKE_INSTANCE_ACTIONS]},
+            server_id=self.server_id
+            )
+
+    def test_show_instance_action_with_str_body(self):
+        self._test_show_instance_action()
+
+    def test_show_instance_action_with_bytes_body(self):
+        self._test_show_instance_action(True)
+
+    def _test_show_instance_action(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_instance_action,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {'instanceAction': self.FAKE_INSTANCE_WITH_EVENTS},
+            server_id=self.server_id,
+            request_id='fake-request-id'
+            )
+
+    def test_force_delete_server_with_str_body(self):
+        self._test_force_delete_server()
+
+    def test_force_delete_server_with_bytes_body(self):
+        self._test_force_delete_server(True)
+
+    def _test_force_delete_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.force_delete_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_restore_soft_deleted_server_with_str_body(self):
+        self._test_restore_soft_deleted_server()
+
+    def test_restore_soft_deleted_server_with_bytes_body(self):
+        self._test_restore_soft_deleted_server(True)
+
+    def _test_restore_soft_deleted_server(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.restore_soft_deleted_server,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_reset_network_with_str_body(self):
+        self._test_reset_network()
+
+    def test_reset_network_with_bytes_body(self):
+        self._test_reset_network(True)
+
+    def _test_reset_network(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.reset_network,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_inject_network_info_with_str_body(self):
+        self._test_inject_network_info()
+
+    def test_inject_network_info_with_bytes_body(self):
+        self._test_inject_network_info(True)
+
+    def _test_inject_network_info(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.inject_network_info,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            status=202,
+            server_id=self.server_id
+            )
+
+    def test_get_vnc_console_with_str_body(self):
+        self._test_get_vnc_console()
+
+    def test_get_vnc_console_with_bytes_body(self):
+        self._test_get_vnc_console(True)
+
+    def _test_get_vnc_console(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.get_vnc_console,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {'console': self.FAKE_VNC_CONSOLE},
+            server_id=self.server_id,
+            type='fake-console-type'
+            )
diff --git a/tempest/tests/lib/services/compute/test_services_client.py b/tempest/tests/lib/services/compute/test_services_client.py
new file mode 100644
index 0000000..7add187
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_services_client.py
@@ -0,0 +1,94 @@
+# 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.
+
+import copy
+
+from tempest.lib.services.compute import services_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestServicesClient(base.BaseComputeServiceTest):
+
+    FAKE_SERVICES = {
+        "services":
+        [{
+            "status": "enabled",
+            "binary": "nova-conductor",
+            "zone": "internal",
+            "state": "up",
+            "updated_at": "2015-08-19T06:50:55.000000",
+            "host": "controller",
+            "disabled_reason": None,
+            "id": 1
+        }]
+    }
+
+    FAKE_SERVICE = {
+        "service":
+        {
+            "status": "enabled",
+            "binary": "nova-conductor",
+            "host": "controller"
+        }
+    }
+
+    def setUp(self):
+        super(TestServicesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = services_client.ServicesClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def test_list_services_with_str_body(self):
+        self.check_service_client_function(
+            self.client.list_services,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SERVICES)
+
+    def test_list_services_with_bytes_body(self):
+        self.check_service_client_function(
+            self.client.list_services,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SERVICES, to_utf=True)
+
+    def _test_enable_service(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.enable_service,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_SERVICE,
+            bytes_body,
+            host_name="nova-conductor", binary="controller")
+
+    def test_enable_service_with_str_body(self):
+        self._test_enable_service()
+
+    def test_enable_service_with_bytes_body(self):
+        self._test_enable_service(bytes_body=True)
+
+    def _test_disable_service(self, bytes_body=False):
+        fake_service = copy.deepcopy(self.FAKE_SERVICE)
+        fake_service["service"]["status"] = "disable"
+
+        self.check_service_client_function(
+            self.client.disable_service,
+            'tempest.lib.common.rest_client.RestClient.put',
+            fake_service,
+            bytes_body,
+            host_name="nova-conductor", binary="controller")
+
+    def test_disable_service_with_str_body(self):
+        self._test_disable_service()
+
+    def test_disable_service_with_bytes_body(self):
+        self._test_disable_service(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_snapshots_client.py b/tempest/tests/lib/services/compute/test_snapshots_client.py
new file mode 100644
index 0000000..b1d8ade
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_snapshots_client.py
@@ -0,0 +1,103 @@
+# 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.
+
+from oslotest import mockpatch
+
+from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.compute import snapshots_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestSnapshotsClient(base.BaseComputeServiceTest):
+
+    FAKE_SNAPSHOT = {
+        "createdAt": "2015-10-02T16:27:54.724209",
+        "displayDescription": u"Another \u1234.",
+        "displayName": u"v\u1234-001",
+        "id": "100",
+        "size": 100,
+        "status": "available",
+        "volumeId": "12"
+    }
+
+    FAKE_SNAPSHOTS = {"snapshots": [FAKE_SNAPSHOT]}
+
+    def setUp(self):
+        super(TestSnapshotsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = snapshots_client.SnapshotsClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_create_snapshot(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_snapshot,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {"snapshot": self.FAKE_SNAPSHOT},
+            to_utf=bytes_body, status=200,
+            volume_id=self.FAKE_SNAPSHOT["volumeId"])
+
+    def test_create_snapshot_with_str_body(self):
+        self._test_create_snapshot()
+
+    def test_create_shapshot_with_bytes_body(self):
+        self._test_create_snapshot(bytes_body=True)
+
+    def _test_show_snapshot(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_snapshot,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"snapshot": self.FAKE_SNAPSHOT},
+            to_utf=bytes_body, snapshot_id=self.FAKE_SNAPSHOT["id"])
+
+    def test_show_snapshot_with_str_body(self):
+        self._test_show_snapshot()
+
+    def test_show_snapshot_with_bytes_body(self):
+        self._test_show_snapshot(bytes_body=True)
+
+    def _test_list_snapshots(self, bytes_body=False, **params):
+        self.check_service_client_function(
+            self.client.list_snapshots,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SNAPSHOTS, to_utf=bytes_body, **params)
+
+    def test_list_snapshots_with_str_body(self):
+        self._test_list_snapshots()
+
+    def test_list_snapshots_with_byte_body(self):
+        self._test_list_snapshots(bytes_body=True)
+
+    def test_list_snapshots_with_params(self):
+        self._test_list_snapshots('fake')
+
+    def test_delete_snapshot(self):
+        self.check_service_client_function(
+            self.client.delete_snapshot,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=202, snapshot_id=self.FAKE_SNAPSHOT['id'])
+
+    def test_is_resource_deleted_true(self):
+        module = ('tempest.lib.services.compute.snapshots_client.'
+                  'SnapshotsClient.show_snapshot')
+        self.useFixture(mockpatch.Patch(
+            module, side_effect=lib_exc.NotFound))
+        self.assertTrue(self.client.is_resource_deleted('fake-id'))
+
+    def test_is_resource_deleted_false(self):
+        module = ('tempest.lib.services.compute.snapshots_client.'
+                  'SnapshotsClient.show_snapshot')
+        self.useFixture(mockpatch.Patch(
+            module, return_value={}))
+        self.assertFalse(self.client.is_resource_deleted('fake-id'))
diff --git a/tempest/tests/lib/services/compute/test_tenant_networks_client.py b/tempest/tests/lib/services/compute/test_tenant_networks_client.py
new file mode 100644
index 0000000..cfb68cc
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_tenant_networks_client.py
@@ -0,0 +1,63 @@
+# 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.
+
+from tempest.lib.services.compute import tenant_networks_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestTenantNetworksClient(base.BaseComputeServiceTest):
+
+    FAKE_NETWORK = {
+        "cidr": "None",
+        "id": "c2329eb4-cc8e-4439-ac4c-932369309e36",
+        "label": u'\u30d7'
+        }
+
+    FAKE_NETWORKS = [FAKE_NETWORK]
+
+    NETWORK_ID = FAKE_NETWORK['id']
+
+    def setUp(self):
+        super(TestTenantNetworksClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = tenant_networks_client.TenantNetworksClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_list_tenant_networks(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_tenant_networks,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"networks": self.FAKE_NETWORKS},
+            bytes_body)
+
+    def test_list_tenant_networks_with_str_body(self):
+        self._test_list_tenant_networks()
+
+    def test_list_tenant_networks_with_bytes_body(self):
+        self._test_list_tenant_networks(bytes_body=True)
+
+    def _test_show_tenant_network(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_tenant_network,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"network": self.FAKE_NETWORK},
+            bytes_body,
+            network_id=self.NETWORK_ID)
+
+    def test_show_tenant_network_with_str_body(self):
+        self._test_show_tenant_network()
+
+    def test_show_tenant_network_with_bytes_body(self):
+        self._test_show_tenant_network(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_tenant_usages_client.py b/tempest/tests/lib/services/compute/test_tenant_usages_client.py
new file mode 100644
index 0000000..88d093d
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_tenant_usages_client.py
@@ -0,0 +1,79 @@
+# 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.
+
+from tempest.lib.services.compute import tenant_usages_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestTenantUsagesClient(base.BaseComputeServiceTest):
+
+    FAKE_SERVER_USAGES = [{
+        "ended_at": None,
+        "flavor": "m1.tiny",
+        "hours": 1.0,
+        "instance_id": "1f1deceb-17b5-4c04-84c7-e0d4499c8fe0",
+        "local_gb": 1,
+        "memory_mb": 512,
+        "name": "new-server-test",
+        "started_at": "2012-10-08T20:10:44.541277",
+        "state": "active",
+        "tenant_id": "openstack",
+        "uptime": 3600,
+        "vcpus": 1
+        }]
+
+    FAKE_TENANT_USAGES = [{
+        "server_usages": FAKE_SERVER_USAGES,
+        "start": "2012-10-08T21:10:44.587336",
+        "stop": "2012-10-08T22:10:44.587336",
+        "tenant_id": "openstack",
+        "total_hours": 1,
+        "total_local_gb_usage": 1,
+        "total_memory_mb_usage": 512,
+        "total_vcpus_usage": 1
+        }]
+
+    def setUp(self):
+        super(TestTenantUsagesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = tenant_usages_client.TenantUsagesClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_list_tenant_usages(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_tenant_usages,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"tenant_usages": self.FAKE_TENANT_USAGES},
+            to_utf=bytes_body)
+
+    def test_list_tenant_usages_with_str_body(self):
+        self._test_list_tenant_usages()
+
+    def test_list_tenant_usages_with_bytes_body(self):
+        self._test_list_tenant_usages(bytes_body=True)
+
+    def _test_show_tenant_usage(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_tenant_usage,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"tenant_usage": self.FAKE_TENANT_USAGES[0]},
+            to_utf=bytes_body,
+            tenant_id='openstack')
+
+    def test_show_tenant_usage_with_str_body(self):
+        self._test_show_tenant_usage()
+
+    def test_show_tenant_usage_with_bytes_body(self):
+        self._test_show_tenant_usage(bytes_body=True)
diff --git a/tempest/tests/lib/services/compute/test_versions_client.py b/tempest/tests/lib/services/compute/test_versions_client.py
new file mode 100644
index 0000000..fc6c1d2
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_versions_client.py
@@ -0,0 +1,135 @@
+# 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.
+
+import copy
+from oslotest import mockpatch
+
+from tempest.lib.services.compute import versions_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestVersionsClient(base.BaseComputeServiceTest):
+
+    FAKE_INIT_VERSION = {
+        "version": {
+            "id": "v2.1",
+            "links": [
+                {
+                    "href": "http://openstack.example.com/v2.1/",
+                    "rel": "self"
+                },
+                {
+                    "href": "http://docs.openstack.org/",
+                    "rel": "describedby",
+                    "type": "text/html"
+                }
+            ],
+            "status": "CURRENT",
+            "updated": "2013-07-23T11:33:21Z",
+            "version": "2.1",
+            "min_version": "2.1"
+            }
+        }
+
+    FAKE_VERSIONS_INFO = {
+        "versions": [FAKE_INIT_VERSION["version"]]
+        }
+
+    FAKE_VERSION_INFO = copy.deepcopy(FAKE_INIT_VERSION)
+
+    FAKE_VERSION_INFO["version"]["media-types"] = [
+        {
+            "base": "application/json",
+            "type": "application/vnd.openstack.compute+json;version=2.1"
+        }
+        ]
+
+    def setUp(self):
+        super(TestVersionsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.versions_client = (
+            versions_client.VersionsClient
+            (fake_auth, 'compute', 'regionOne'))
+
+    def _test_versions_client(self, bytes_body=False):
+        self.check_service_client_function(
+            self.versions_client.list_versions,
+            'tempest.lib.common.rest_client.RestClient.raw_request',
+            self.FAKE_VERSIONS_INFO,
+            bytes_body,
+            200)
+
+    def _test_get_version_by_url(self, bytes_body=False):
+        self.useFixture(mockpatch.Patch(
+            "tempest.lib.common.rest_client.RestClient.token",
+            return_value="Dummy Token"))
+        params = {"version_url": self.versions_client._get_base_version_url()}
+        self.check_service_client_function(
+            self.versions_client.get_version_by_url,
+            'tempest.lib.common.rest_client.RestClient.raw_request',
+            self.FAKE_VERSION_INFO,
+            bytes_body,
+            200, **params)
+
+    def test_list_versions_client_with_str_body(self):
+        self._test_versions_client()
+
+    def test_list_versions_client_with_bytes_body(self):
+        self._test_versions_client(bytes_body=True)
+
+    def test_get_version_by_url_with_str_body(self):
+        self._test_get_version_by_url()
+
+    def test_get_version_by_url_with_bytes_body(self):
+        self._test_get_version_by_url(bytes_body=True)
+
+    def _test_get_base_version_url(self, url, expected_base_url):
+        auth = fake_auth_provider.FakeAuthProvider(fake_base_url=url)
+        client = versions_client.VersionsClient(auth, 'compute', 'regionOne')
+        self.assertEqual(expected_base_url, client._get_base_version_url())
+
+    def test_get_base_version_url(self):
+        self._test_get_base_version_url('https://bar.org/v2/123',
+                                        'https://bar.org/')
+        self._test_get_base_version_url('https://bar.org/v2.1/123',
+                                        'https://bar.org/')
+        self._test_get_base_version_url('https://bar.org/v2.15/123',
+                                        'https://bar.org/')
+        self._test_get_base_version_url('https://bar.org/v22.2/123',
+                                        'https://bar.org/')
+        self._test_get_base_version_url('https://bar.org/v22/123',
+                                        'https://bar.org/')
+
+    def test_get_base_version_url_app_name(self):
+        self._test_get_base_version_url('https://bar.org/compute/v2/123',
+                                        'https://bar.org/compute/')
+        self._test_get_base_version_url('https://bar.org/compute/v2.1/123',
+                                        'https://bar.org/compute/')
+        self._test_get_base_version_url('https://bar.org/compute/v2.15/123',
+                                        'https://bar.org/compute/')
+        self._test_get_base_version_url('https://bar.org/compute/v22.2/123',
+                                        'https://bar.org/compute/')
+        self._test_get_base_version_url('https://bar.org/compute/v22/123',
+                                        'https://bar.org/compute/')
+
+    def test_get_base_version_url_double_slash(self):
+        self._test_get_base_version_url('https://bar.org//v2/123',
+                                        'https://bar.org/')
+        self._test_get_base_version_url('https://bar.org//v2.1/123',
+                                        'https://bar.org/')
+        self._test_get_base_version_url('https://bar.org/compute//v2/123',
+                                        'https://bar.org/compute/')
+        self._test_get_base_version_url('https://bar.org/compute//v2.1/123',
+                                        'https://bar.org/compute/')
diff --git a/tempest/tests/lib/services/compute/test_volumes_client.py b/tempest/tests/lib/services/compute/test_volumes_client.py
new file mode 100644
index 0000000..d16f5b0
--- /dev/null
+++ b/tempest/tests/lib/services/compute/test_volumes_client.py
@@ -0,0 +1,114 @@
+# 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.
+
+import copy
+
+from oslotest import mockpatch
+
+from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.compute import volumes_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
+
+
+class TestVolumesClient(base.BaseComputeServiceTest):
+
+    FAKE_VOLUME = {
+        "id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+        "displayName": u"v\u12345ol-001",
+        "displayDescription": u"Another \u1234volume.",
+        "size": 30,
+        "status": "Active",
+        "volumeType": "289da7f8-6440-407c-9fb4-7db01ec49164",
+        "metadata": {
+            "contents": "junk"
+        },
+        "availabilityZone": "us-east1",
+        "snapshotId": None,
+        "attachments": [],
+        "createdAt": "2012-02-14T20:53:07Z"
+    }
+
+    FAKE_VOLUMES = {"volumes": [FAKE_VOLUME]}
+
+    def setUp(self):
+        super(TestVolumesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = volumes_client.VolumesClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_list_volumes(self, bytes_body=False, **params):
+        self.check_service_client_function(
+            self.client.list_volumes,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_VOLUMES, to_utf=bytes_body, **params)
+
+    def test_list_volumes_with_str_body(self):
+        self._test_list_volumes()
+
+    def test_list_volumes_with_byte_body(self):
+        self._test_list_volumes(bytes_body=True)
+
+    def test_list_volumes_with_params(self):
+        self._test_list_volumes(name='fake')
+
+    def _test_show_volume(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_volume,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {"volume": self.FAKE_VOLUME},
+            to_utf=bytes_body, volume_id=self.FAKE_VOLUME['id'])
+
+    def test_show_volume_with_str_body(self):
+        self._test_show_volume()
+
+    def test_show_volume_with_bytes_body(self):
+        self._test_show_volume(bytes_body=True)
+
+    def _test_create_volume(self, bytes_body=False):
+        post_body = copy.deepcopy(self.FAKE_VOLUME)
+        del post_body['id']
+        del post_body['createdAt']
+        del post_body['status']
+        self.check_service_client_function(
+            self.client.create_volume,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {"volume": self.FAKE_VOLUME},
+            to_utf=bytes_body, status=200, **post_body)
+
+    def test_create_volume_with_str_body(self):
+        self._test_create_volume()
+
+    def test_create_volume_with_bytes_body(self):
+        self._test_create_volume(bytes_body=True)
+
+    def test_delete_volume(self):
+        self.check_service_client_function(
+            self.client.delete_volume,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=202, volume_id=self.FAKE_VOLUME['id'])
+
+    def test_is_resource_deleted_true(self):
+        module = ('tempest.lib.services.compute.volumes_client.'
+                  'VolumesClient.show_volume')
+        self.useFixture(mockpatch.Patch(
+            module, side_effect=lib_exc.NotFound))
+        self.assertTrue(self.client.is_resource_deleted('fake-id'))
+
+    def test_is_resource_deleted_false(self):
+        module = ('tempest.lib.services.compute.volumes_client.'
+                  'VolumesClient.show_volume')
+        self.useFixture(mockpatch.Patch(
+            module, return_value={}))
+        self.assertFalse(self.client.is_resource_deleted('fake-id'))
diff --git a/tempest/api/messaging/__init__.py b/tempest/tests/lib/services/identity/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/tests/lib/services/identity/__init__.py
diff --git a/tempest/api/messaging/__init__.py b/tempest/tests/lib/services/identity/v2/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/tests/lib/services/identity/v2/__init__.py
diff --git a/tempest/tests/lib/services/identity/v2/test_token_client.py b/tempest/tests/lib/services/identity/v2/test_token_client.py
new file mode 100644
index 0000000..dd3533a
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v2/test_token_client.py
@@ -0,0 +1,92 @@
+# Copyright 2015 Hewlett-Packard Development Company, L.P.
+#
+# 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 json
+
+import httplib2
+from oslotest import mockpatch
+
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions
+from tempest.lib.services.identity.v2 import token_client
+from tempest.tests.lib import base
+from tempest.tests.lib import fake_http
+
+
+class TestTokenClientV2(base.TestCase):
+
+    def setUp(self):
+        super(TestTokenClientV2, self).setUp()
+        self.fake_200_http = fake_http.fake_httplib2(return_type=200)
+
+    def test_init_without_authurl(self):
+        self.assertRaises(exceptions.IdentityError,
+                          token_client.TokenClient, None)
+
+    def test_auth(self):
+        token_client_v2 = token_client.TokenClient('fake_url')
+        post_mock = self.useFixture(mockpatch.PatchObject(
+            token_client_v2, 'post', return_value=self.fake_200_http.request(
+                'fake_url', body={'access': {'token': 'fake_token'}})))
+        resp = token_client_v2.auth('fake_user', 'fake_pass')
+        self.assertIsInstance(resp, rest_client.ResponseBody)
+        req_dict = json.dumps({
+            'auth': {
+                'passwordCredentials': {
+                    'username': 'fake_user',
+                    'password': 'fake_pass',
+                },
+            }
+        }, sort_keys=True)
+        post_mock.mock.assert_called_once_with('fake_url/tokens',
+                                               body=req_dict)
+
+    def test_auth_with_tenant(self):
+        token_client_v2 = token_client.TokenClient('fake_url')
+        post_mock = self.useFixture(mockpatch.PatchObject(
+            token_client_v2, 'post', return_value=self.fake_200_http.request(
+                'fake_url', body={'access': {'token': 'fake_token'}})))
+        resp = token_client_v2.auth('fake_user', 'fake_pass', 'fake_tenant')
+        self.assertIsInstance(resp, rest_client.ResponseBody)
+        req_dict = json.dumps({
+            'auth': {
+                'tenantName': 'fake_tenant',
+                'passwordCredentials': {
+                    'username': 'fake_user',
+                    'password': 'fake_pass',
+                },
+            }
+        }, sort_keys=True)
+        post_mock.mock.assert_called_once_with('fake_url/tokens',
+                                               body=req_dict)
+
+    def test_request_with_str_body(self):
+        token_client_v2 = token_client.TokenClient('fake_url')
+        self.useFixture(mockpatch.PatchObject(
+            token_client_v2, 'raw_request', return_value=(
+                httplib2.Response({'status': '200'}),
+                str('{"access": {"token": "fake_token"}}'))))
+        resp, body = token_client_v2.request('GET', 'fake_uri')
+        self.assertIsInstance(resp, httplib2.Response)
+        self.assertIsInstance(body, dict)
+
+    def test_request_with_bytes_body(self):
+        token_client_v2 = token_client.TokenClient('fake_url')
+        self.useFixture(mockpatch.PatchObject(
+            token_client_v2, 'raw_request', return_value=(
+                httplib2.Response({'status': '200'}),
+                bytes(b'{"access": {"token": "fake_token"}}'))))
+        resp, body = token_client_v2.request('GET', 'fake_uri')
+        self.assertIsInstance(resp, httplib2.Response)
+        self.assertIsInstance(body, dict)
diff --git a/tempest/api/messaging/__init__.py b/tempest/tests/lib/services/identity/v3/__init__.py
similarity index 100%
copy from tempest/api/messaging/__init__.py
copy to tempest/tests/lib/services/identity/v3/__init__.py
diff --git a/tempest/tests/lib/services/identity/v3/test_token_client.py b/tempest/tests/lib/services/identity/v3/test_token_client.py
new file mode 100644
index 0000000..bb4dae3
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_token_client.py
@@ -0,0 +1,145 @@
+# Copyright 2015 Hewlett-Packard Development Company, L.P.
+#
+# 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 json
+
+import httplib2
+from oslotest import mockpatch
+
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions
+from tempest.lib.services.identity.v3 import token_client
+from tempest.tests.lib import base
+from tempest.tests.lib import fake_http
+
+
+class TestTokenClientV2(base.TestCase):
+
+    def setUp(self):
+        super(TestTokenClientV2, self).setUp()
+        self.fake_201_http = fake_http.fake_httplib2(return_type=201)
+
+    def test_init_without_authurl(self):
+        self.assertRaises(exceptions.IdentityError,
+                          token_client.V3TokenClient, None)
+
+    def test_auth(self):
+        token_client_v3 = token_client.V3TokenClient('fake_url')
+        post_mock = self.useFixture(mockpatch.PatchObject(
+            token_client_v3, 'post', return_value=self.fake_201_http.request(
+                'fake_url', body={'access': {'token': 'fake_token'}})))
+        resp = token_client_v3.auth(username='fake_user', password='fake_pass')
+        self.assertIsInstance(resp, rest_client.ResponseBody)
+        req_dict = json.dumps({
+            'auth': {
+                'identity': {
+                    'methods': ['password'],
+                    'password': {
+                        'user': {
+                            'name': 'fake_user',
+                            'password': 'fake_pass',
+                        }
+                    }
+                },
+            }
+        }, sort_keys=True)
+        post_mock.mock.assert_called_once_with('fake_url/auth/tokens',
+                                               body=req_dict)
+
+    def test_auth_with_project_id_and_domain_id(self):
+        token_client_v3 = token_client.V3TokenClient('fake_url')
+        post_mock = self.useFixture(mockpatch.PatchObject(
+            token_client_v3, 'post', return_value=self.fake_201_http.request(
+                'fake_url', body={'access': {'token': 'fake_token'}})))
+        resp = token_client_v3.auth(
+            username='fake_user', password='fake_pass',
+            project_id='fcac2a055a294e4c82d0a9c21c620eb4',
+            user_domain_id='14f4a9a99973404d8c20ba1d2af163ff',
+            project_domain_id='291f63ae9ac54ee292ca09e5f72d9676')
+        self.assertIsInstance(resp, rest_client.ResponseBody)
+        req_dict = json.dumps({
+            'auth': {
+                'identity': {
+                    'methods': ['password'],
+                    'password': {
+                        'user': {
+                            'name': 'fake_user',
+                            'password': 'fake_pass',
+                            'domain': {
+                                'id': '14f4a9a99973404d8c20ba1d2af163ff'
+                            }
+                        }
+                    }
+                },
+                'scope': {
+                    'project': {
+                        'id': 'fcac2a055a294e4c82d0a9c21c620eb4',
+                        'domain': {
+                            'id': '291f63ae9ac54ee292ca09e5f72d9676'
+                        }
+                    }
+                }
+            }
+        }, sort_keys=True)
+        post_mock.mock.assert_called_once_with('fake_url/auth/tokens',
+                                               body=req_dict)
+
+    def test_auth_with_tenant(self):
+        token_client_v2 = token_client.V3TokenClient('fake_url')
+        post_mock = self.useFixture(mockpatch.PatchObject(
+            token_client_v2, 'post', return_value=self.fake_201_http.request(
+                'fake_url', body={'access': {'token': 'fake_token'}})))
+        resp = token_client_v2.auth(username='fake_user', password='fake_pass',
+                                    project_name='fake_tenant')
+        self.assertIsInstance(resp, rest_client.ResponseBody)
+        req_dict = json.dumps({
+            'auth': {
+                'identity': {
+                    'methods': ['password'],
+                    'password': {
+                        'user': {
+                            'name': 'fake_user',
+                            'password': 'fake_pass',
+                        }
+                    }},
+                'scope': {
+                    'project': {
+                        'name': 'fake_tenant'
+                    }
+                },
+            }
+        }, sort_keys=True)
+
+        post_mock.mock.assert_called_once_with('fake_url/auth/tokens',
+                                               body=req_dict)
+
+    def test_request_with_str_body(self):
+        token_client_v3 = token_client.V3TokenClient('fake_url')
+        self.useFixture(mockpatch.PatchObject(
+            token_client_v3, 'raw_request', return_value=(
+                httplib2.Response({"status": "200"}),
+                str('{"access": {"token": "fake_token"}}'))))
+        resp, body = token_client_v3.request('GET', 'fake_uri')
+        self.assertIsInstance(resp, httplib2.Response)
+        self.assertIsInstance(body, dict)
+
+    def test_request_with_bytes_body(self):
+        token_client_v3 = token_client.V3TokenClient('fake_url')
+        self.useFixture(mockpatch.PatchObject(
+            token_client_v3, 'raw_request', return_value=(
+                httplib2.Response({"status": "200"}),
+                bytes(b'{"access": {"token": "fake_token"}}'))))
+        resp, body = token_client_v3.request('GET', 'fake_uri')
+        self.assertIsInstance(resp, httplib2.Response)
+        self.assertIsInstance(body, dict)
diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py
new file mode 100644
index 0000000..ebcfe82
--- /dev/null
+++ b/tempest/tests/lib/test_auth.py
@@ -0,0 +1,532 @@
+# Copyright 2014 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 copy
+import datetime
+
+from oslotest import mockpatch
+
+from tempest.lib import auth
+from tempest.lib import exceptions
+from tempest.lib.services.identity.v2 import token_client as v2_client
+from tempest.lib.services.identity.v3 import token_client as v3_client
+from tempest.tests.lib import base
+from tempest.tests.lib import fake_credentials
+from tempest.tests.lib import fake_http
+from tempest.tests.lib import fake_identity
+
+
+def fake_get_credentials(fill_in=True, identity_version='v2', **kwargs):
+    return fake_credentials.FakeCredentials()
+
+
+class BaseAuthTestsSetUp(base.TestCase):
+    _auth_provider_class = None
+    credentials = fake_credentials.FakeCredentials()
+
+    def _auth(self, credentials, auth_url, **params):
+        """returns auth method according to keystone"""
+        return self._auth_provider_class(credentials, auth_url, **params)
+
+    def setUp(self):
+        super(BaseAuthTestsSetUp, self).setUp()
+        self.fake_http = fake_http.fake_httplib2(return_type=200)
+        self.stubs.Set(auth, 'get_credentials', fake_get_credentials)
+        self.auth_provider = self._auth(self.credentials,
+                                        fake_identity.FAKE_AUTH_URL)
+
+
+class TestBaseAuthProvider(BaseAuthTestsSetUp):
+    """Tests for base AuthProvider
+
+    This tests auth.AuthProvider class which is base for the other so we
+    obviously don't test not implemented method or the ones which strongly
+    depends on them.
+    """
+
+    class FakeAuthProviderImpl(auth.AuthProvider):
+        def _decorate_request(self):
+            pass
+
+        def _fill_credentials(self):
+            pass
+
+        def _get_auth(self):
+            pass
+
+        def base_url(self):
+            pass
+
+        def is_expired(self):
+            pass
+
+    _auth_provider_class = FakeAuthProviderImpl
+
+    def _auth(self, credentials, auth_url, **params):
+        """returns auth method according to keystone"""
+        return self._auth_provider_class(credentials, **params)
+
+    def test_check_credentials_bad_type(self):
+        self.assertFalse(self.auth_provider.check_credentials([]))
+
+    def test_auth_data_property_when_cache_exists(self):
+        self.auth_provider.cache = 'foo'
+        self.useFixture(mockpatch.PatchObject(self.auth_provider,
+                                              'is_expired',
+                                              return_value=False))
+        self.assertEqual('foo', getattr(self.auth_provider, 'auth_data'))
+
+    def test_delete_auth_data_property_through_deleter(self):
+        self.auth_provider.cache = 'foo'
+        del self.auth_provider.auth_data
+        self.assertIsNone(self.auth_provider.cache)
+
+    def test_delete_auth_data_property_through_clear_auth(self):
+        self.auth_provider.cache = 'foo'
+        self.auth_provider.clear_auth()
+        self.assertIsNone(self.auth_provider.cache)
+
+    def test_set_and_reset_alt_auth_data(self):
+        self.auth_provider.set_alt_auth_data('foo', 'bar')
+        self.assertEqual(self.auth_provider.alt_part, 'foo')
+        self.assertEqual(self.auth_provider.alt_auth_data, 'bar')
+
+        self.auth_provider.reset_alt_auth_data()
+        self.assertIsNone(self.auth_provider.alt_part)
+        self.assertIsNone(self.auth_provider.alt_auth_data)
+
+    def test_auth_class(self):
+        self.assertRaises(TypeError,
+                          auth.AuthProvider,
+                          fake_credentials.FakeCredentials)
+
+
+class TestKeystoneV2AuthProvider(BaseAuthTestsSetUp):
+    _endpoints = fake_identity.IDENTITY_V2_RESPONSE['access']['serviceCatalog']
+    _auth_provider_class = auth.KeystoneV2AuthProvider
+    credentials = fake_credentials.FakeKeystoneV2Credentials()
+
+    def setUp(self):
+        super(TestKeystoneV2AuthProvider, self).setUp()
+        self.stubs.Set(v2_client.TokenClient, 'raw_request',
+                       fake_identity._fake_v2_response)
+        self.target_url = 'test_api'
+
+    def _get_fake_identity(self):
+        return fake_identity.IDENTITY_V2_RESPONSE['access']
+
+    def _get_fake_alt_identity(self):
+        return fake_identity.ALT_IDENTITY_V2_RESPONSE['access']
+
+    def _get_result_url_from_endpoint(self, ep, endpoint_type='publicURL',
+                                      replacement=None):
+        if replacement:
+            return ep[endpoint_type].replace('v2', replacement)
+        return ep[endpoint_type]
+
+    def _get_token_from_fake_identity(self):
+        return fake_identity.TOKEN
+
+    def _get_from_fake_identity(self, attr):
+        access = fake_identity.IDENTITY_V2_RESPONSE['access']
+        if attr == 'user_id':
+            return access['user']['id']
+        elif attr == 'tenant_id':
+            return access['token']['tenant']['id']
+
+    def _test_request_helper(self, filters, expected):
+        url, headers, body = self.auth_provider.auth_request('GET',
+                                                             self.target_url,
+                                                             filters=filters)
+
+        self.assertEqual(expected['url'], url)
+        self.assertEqual(expected['token'], headers['X-Auth-Token'])
+        self.assertEqual(expected['body'], body)
+
+    def _auth_data_with_expiry(self, date_as_string):
+        token, access = self.auth_provider.auth_data
+        access['token']['expires'] = date_as_string
+        return token, access
+
+    def test_request(self):
+        filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion'
+        }
+
+        url = self._get_result_url_from_endpoint(
+            self._endpoints[0]['endpoints'][1]) + '/' + self.target_url
+
+        expected = {
+            'body': None,
+            'url': url,
+            'token': self._get_token_from_fake_identity(),
+        }
+        self._test_request_helper(filters, expected)
+
+    def test_request_with_alt_auth_cleans_alt(self):
+        """Test alternate auth data for headers
+
+        Assert that when the alt data is provided for headers, after an
+        auth_request the data alt_data is cleaned-up.
+        """
+        self.auth_provider.set_alt_auth_data(
+            'headers',
+            (fake_identity.ALT_TOKEN, self._get_fake_alt_identity()))
+        filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'fakeRegion'
+        }
+        self.auth_provider.auth_request('GET', self.target_url,
+                                        filters=filters)
+
+        # Assert alt auth data is clear after it
+        self.assertIsNone(self.auth_provider.alt_part)
+        self.assertIsNone(self.auth_provider.alt_auth_data)
+
+    def _test_request_with_identical_alt_auth(self, part):
+        """Test alternate but identical auth data for headers
+
+        Assert that when the alt data is provided, but it's actually
+        identical, an exception is raised.
+        """
+        self.auth_provider.set_alt_auth_data(
+            part,
+            (fake_identity.TOKEN, self._get_fake_identity()))
+        filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'fakeRegion'
+        }
+
+        self.assertRaises(exceptions.BadAltAuth,
+                          self.auth_provider.auth_request,
+                          'GET', self.target_url, filters=filters)
+
+    def test_request_with_identical_alt_auth_headers(self):
+        self._test_request_with_identical_alt_auth('headers')
+
+    def test_request_with_identical_alt_auth_url(self):
+        self._test_request_with_identical_alt_auth('url')
+
+    def test_request_with_identical_alt_auth_body(self):
+        self._test_request_with_identical_alt_auth('body')
+
+    def test_request_with_alt_part_without_alt_data(self):
+        """Test empty alternate auth data
+
+        Assert that when alt_part is defined, the corresponding original
+        request element is kept the same.
+        """
+        filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'fakeRegion'
+        }
+        self.auth_provider.set_alt_auth_data('headers', None)
+
+        url, headers, body = self.auth_provider.auth_request('GET',
+                                                             self.target_url,
+                                                             filters=filters)
+        # The original headers where empty
+        self.assertNotEqual(url, self.target_url)
+        self.assertIsNone(headers)
+        self.assertEqual(body, None)
+
+    def _test_request_with_alt_part_without_alt_data_no_change(self, body):
+        """Test empty alternate auth data with no effect
+
+        Assert that when alt_part is defined, no auth_data is provided,
+        and the the corresponding original request element was not going to
+        be changed anyways, and exception is raised
+        """
+        filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'fakeRegion'
+        }
+        self.auth_provider.set_alt_auth_data('body', None)
+
+        self.assertRaises(exceptions.BadAltAuth,
+                          self.auth_provider.auth_request,
+                          'GET', self.target_url, filters=filters)
+
+    def test_request_with_alt_part_without_alt_data_no_change_headers(self):
+        self._test_request_with_alt_part_without_alt_data_no_change('headers')
+
+    def test_request_with_alt_part_without_alt_data_no_change_url(self):
+        self._test_request_with_alt_part_without_alt_data_no_change('url')
+
+    def test_request_with_alt_part_without_alt_data_no_change_body(self):
+        self._test_request_with_alt_part_without_alt_data_no_change('body')
+
+    def test_request_with_bad_service(self):
+        filters = {
+            'service': 'BAD_SERVICE',
+            'endpoint_type': 'publicURL',
+            'region': 'fakeRegion'
+        }
+        self.assertRaises(exceptions.EndpointNotFound,
+                          self.auth_provider.auth_request, 'GET',
+                          self.target_url, filters=filters)
+
+    def test_request_without_service(self):
+        filters = {
+            'service': None,
+            'endpoint_type': 'publicURL',
+            'region': 'fakeRegion'
+        }
+        self.assertRaises(exceptions.EndpointNotFound,
+                          self.auth_provider.auth_request, 'GET',
+                          self.target_url, filters=filters)
+
+    def test_check_credentials_missing_attribute(self):
+        for attr in ['username', 'password']:
+            cred = copy.copy(self.credentials)
+            del cred[attr]
+            self.assertFalse(self.auth_provider.check_credentials(cred))
+
+    def test_fill_credentials(self):
+        self.auth_provider.fill_credentials()
+        creds = self.auth_provider.credentials
+        for attr in ['user_id', 'tenant_id']:
+            self.assertEqual(self._get_from_fake_identity(attr),
+                             getattr(creds, attr))
+
+    def _test_base_url_helper(self, expected_url, filters,
+                              auth_data=None):
+
+        url = self.auth_provider.base_url(filters, auth_data)
+        self.assertEqual(url, expected_url)
+
+    def test_base_url(self):
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion'
+        }
+        expected = self._get_result_url_from_endpoint(
+            self._endpoints[0]['endpoints'][1])
+        self._test_base_url_helper(expected, self.filters)
+
+    def test_base_url_to_get_admin_endpoint(self):
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'adminURL',
+            'region': 'FakeRegion'
+        }
+        expected = self._get_result_url_from_endpoint(
+            self._endpoints[0]['endpoints'][1], endpoint_type='adminURL')
+        self._test_base_url_helper(expected, self.filters)
+
+    def test_base_url_unknown_region(self):
+        """If the region is unknown, the first endpoint is returned."""
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'AintNoBodyKnowThisRegion'
+        }
+        expected = self._get_result_url_from_endpoint(
+            self._endpoints[0]['endpoints'][0])
+        self._test_base_url_helper(expected, self.filters)
+
+    def test_base_url_with_non_existent_service(self):
+        self.filters = {
+            'service': 'BAD_SERVICE',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion'
+        }
+        self.assertRaises(exceptions.EndpointNotFound,
+                          self._test_base_url_helper, None, self.filters)
+
+    def test_base_url_without_service(self):
+        self.filters = {
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion'
+        }
+        self.assertRaises(exceptions.EndpointNotFound,
+                          self._test_base_url_helper, None, self.filters)
+
+    def test_base_url_with_api_version_filter(self):
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion',
+            'api_version': 'v12'
+        }
+        expected = self._get_result_url_from_endpoint(
+            self._endpoints[0]['endpoints'][1], replacement='v12')
+        self._test_base_url_helper(expected, self.filters)
+
+    def test_base_url_with_skip_path_filter(self):
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion',
+            'skip_path': True
+        }
+        expected = 'http://fake_url/'
+        self._test_base_url_helper(expected, self.filters)
+
+    def test_base_url_with_unversioned_endpoint(self):
+        auth_data = {
+            'serviceCatalog': [
+                {
+                    'type': 'identity',
+                    'endpoints': [
+                        {
+                            'region': 'FakeRegion',
+                            'publicURL': 'http://fake_url'
+                        }
+                    ]
+                }
+            ]
+        }
+
+        filters = {
+            'service': 'identity',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion',
+            'api_version': 'v2.0'
+        }
+
+        expected = 'http://fake_url/v2.0'
+        self._test_base_url_helper(expected, filters, ('token', auth_data))
+
+    def test_token_not_expired(self):
+        expiry_data = datetime.datetime.utcnow() + datetime.timedelta(days=1)
+        self._verify_expiry(expiry_data=expiry_data, should_be_expired=False)
+
+    def test_token_expired(self):
+        expiry_data = datetime.datetime.utcnow() - datetime.timedelta(hours=1)
+        self._verify_expiry(expiry_data=expiry_data, should_be_expired=True)
+
+    def test_token_not_expired_to_be_renewed(self):
+        expiry_data = (datetime.datetime.utcnow() +
+                       self.auth_provider.token_expiry_threshold / 2)
+        self._verify_expiry(expiry_data=expiry_data, should_be_expired=True)
+
+    def _verify_expiry(self, expiry_data, should_be_expired):
+        for expiry_format in self.auth_provider.EXPIRY_DATE_FORMATS:
+            auth_data = self._auth_data_with_expiry(
+                expiry_data.strftime(expiry_format))
+            self.assertEqual(self.auth_provider.is_expired(auth_data),
+                             should_be_expired)
+
+
+class TestKeystoneV3AuthProvider(TestKeystoneV2AuthProvider):
+    _endpoints = fake_identity.IDENTITY_V3_RESPONSE['token']['catalog']
+    _auth_provider_class = auth.KeystoneV3AuthProvider
+    credentials = fake_credentials.FakeKeystoneV3Credentials()
+
+    def setUp(self):
+        super(TestKeystoneV3AuthProvider, self).setUp()
+        self.stubs.Set(v3_client.V3TokenClient, 'raw_request',
+                       fake_identity._fake_v3_response)
+
+    def _get_fake_identity(self):
+        return fake_identity.IDENTITY_V3_RESPONSE['token']
+
+    def _get_fake_alt_identity(self):
+        return fake_identity.ALT_IDENTITY_V3['token']
+
+    def _get_result_url_from_endpoint(self, ep, replacement=None):
+        if replacement:
+            return ep['url'].replace('v3', replacement)
+        return ep['url']
+
+    def _auth_data_with_expiry(self, date_as_string):
+        token, access = self.auth_provider.auth_data
+        access['expires_at'] = date_as_string
+        return token, access
+
+    def _get_from_fake_identity(self, attr):
+        token = fake_identity.IDENTITY_V3_RESPONSE['token']
+        if attr == 'user_id':
+            return token['user']['id']
+        elif attr == 'project_id':
+            return token['project']['id']
+        elif attr == 'user_domain_id':
+            return token['user']['domain']['id']
+        elif attr == 'project_domain_id':
+            return token['project']['domain']['id']
+
+    def test_check_credentials_missing_attribute(self):
+        # reset credentials to fresh ones
+        self.credentials.reset()
+        for attr in ['username', 'password', 'user_domain_name',
+                     'project_domain_name']:
+            cred = copy.copy(self.credentials)
+            del cred[attr]
+            self.assertFalse(self.auth_provider.check_credentials(cred),
+                             "Credentials should be invalid without %s" % attr)
+
+    def test_check_domain_credentials_missing_attribute(self):
+        # reset credentials to fresh ones
+        self.credentials.reset()
+        domain_creds = fake_credentials.FakeKeystoneV3DomainCredentials()
+        for attr in ['username', 'password', 'user_domain_name']:
+            cred = copy.copy(domain_creds)
+            del cred[attr]
+            self.assertFalse(self.auth_provider.check_credentials(cred),
+                             "Credentials should be invalid without %s" % attr)
+
+    def test_fill_credentials(self):
+        self.auth_provider.fill_credentials()
+        creds = self.auth_provider.credentials
+        for attr in ['user_id', 'project_id', 'user_domain_id',
+                     'project_domain_id']:
+            self.assertEqual(self._get_from_fake_identity(attr),
+                             getattr(creds, attr))
+
+    # Overwrites v2 test
+    def test_base_url_to_get_admin_endpoint(self):
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'admin',
+            'region': 'MiddleEarthRegion'
+        }
+        expected = self._get_result_url_from_endpoint(
+            self._endpoints[0]['endpoints'][2])
+        self._test_base_url_helper(expected, self.filters)
+
+    # Overwrites v2 test
+    def test_base_url_with_unversioned_endpoint(self):
+        auth_data = {
+            'catalog': [
+                {
+                    'type': 'identity',
+                    'endpoints': [
+                        {
+                            'region': 'FakeRegion',
+                            'url': 'http://fake_url',
+                            'interface': 'public'
+                        }
+                    ]
+                }
+            ]
+        }
+
+        filters = {
+            'service': 'identity',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion',
+            'api_version': 'v3'
+        }
+
+        expected = 'http://fake_url/v3'
+        self._test_base_url_helper(expected, filters, ('token', auth_data))
diff --git a/tempest/tests/lib/test_base.py b/tempest/tests/lib/test_base.py
new file mode 100644
index 0000000..27cda1a
--- /dev/null
+++ b/tempest/tests/lib/test_base.py
@@ -0,0 +1,64 @@
+# Copyright 2014 Mirantis 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.lib import base
+from tempest.lib import exceptions
+
+
+class TestAttr(base.BaseTestCase):
+
+    def test_has_no_attrs(self):
+        self.assertEqual(
+            'tempest.tests.lib.test_base.TestAttr.test_has_no_attrs',
+            self.id()
+        )
+
+    @testtools.testcase.attr('foo')
+    def test_has_one_attr(self):
+        self.assertEqual(
+            'tempest.tests.lib.test_base.TestAttr.test_has_one_attr[foo]',
+            self.id()
+        )
+
+    @testtools.testcase.attr('foo')
+    @testtools.testcase.attr('bar')
+    def test_has_two_attrs(self):
+        self.assertEqual(
+            'tempest.tests.lib.test_base.TestAttr.test_has_two_attrs[bar,foo]',
+            self.id(),
+        )
+
+
+class TestSetUpClass(base.BaseTestCase):
+
+    @classmethod
+    def setUpClass(cls):  # noqa
+        """Simulate absence of super() call."""
+
+    def setUp(self):
+        try:
+            # We expect here RuntimeError exception because 'setUpClass'
+            # has not called 'super'.
+            super(TestSetUpClass, self).setUp()
+        except RuntimeError:
+            pass
+        else:
+            raise exceptions.TempestException(
+                "If you see this, then expected exception was not raised.")
+
+    def test_setup_class_raises_runtime_error(self):
+        """No-op test just to call setUp."""
diff --git a/tempest/tests/lib/test_credentials.py b/tempest/tests/lib/test_credentials.py
new file mode 100644
index 0000000..791fbb5
--- /dev/null
+++ b/tempest/tests/lib/test_credentials.py
@@ -0,0 +1,180 @@
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
+# 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 copy
+
+from tempest.lib import auth
+from tempest.lib import exceptions
+from tempest.lib.services.identity.v2 import token_client as v2_client
+from tempest.lib.services.identity.v3 import token_client as v3_client
+from tempest.tests.lib import base
+from tempest.tests.lib import fake_identity
+
+
+class CredentialsTests(base.TestCase):
+    attributes = {}
+    credentials_class = auth.Credentials
+
+    def _get_credentials(self, attributes=None):
+        if attributes is None:
+            attributes = self.attributes
+        return self.credentials_class(**attributes)
+
+    def _check(self, credentials, credentials_class, filled):
+        # Check the right version of credentials has been returned
+        self.assertIsInstance(credentials, credentials_class)
+        # Check the id attributes are filled in
+        attributes = [x for x in credentials.ATTRIBUTES if (
+            '_id' in x and x != 'domain_id')]
+        for attr in attributes:
+            if filled:
+                self.assertIsNotNone(getattr(credentials, attr))
+            else:
+                self.assertIsNone(getattr(credentials, attr))
+
+    def test_create(self):
+        creds = self._get_credentials()
+        self.assertEqual(self.attributes, creds._initial)
+
+    def test_create_invalid_attr(self):
+        self.assertRaises(exceptions.InvalidCredentials,
+                          self._get_credentials,
+                          attributes=dict(invalid='fake'))
+
+    def test_is_valid(self):
+        creds = self._get_credentials()
+        self.assertRaises(NotImplementedError, creds.is_valid)
+
+
+class KeystoneV2CredentialsTests(CredentialsTests):
+    attributes = {
+        'username': 'fake_username',
+        'password': 'fake_password',
+        'tenant_name': 'fake_tenant_name'
+    }
+
+    identity_response = fake_identity._fake_v2_response
+    credentials_class = auth.KeystoneV2Credentials
+    tokenclient_class = v2_client.TokenClient
+    identity_version = 'v2'
+
+    def setUp(self):
+        super(KeystoneV2CredentialsTests, self).setUp()
+        self.stubs.Set(self.tokenclient_class, 'raw_request',
+                       self.identity_response)
+
+    def _verify_credentials(self, credentials_class, creds_dict, filled=True):
+        creds = auth.get_credentials(fake_identity.FAKE_AUTH_URL,
+                                     fill_in=filled,
+                                     identity_version=self.identity_version,
+                                     **creds_dict)
+        self._check(creds, credentials_class, filled)
+
+    def test_get_credentials(self):
+        self._verify_credentials(credentials_class=self.credentials_class,
+                                 creds_dict=self.attributes)
+
+    def test_get_credentials_not_filled(self):
+        self._verify_credentials(credentials_class=self.credentials_class,
+                                 creds_dict=self.attributes,
+                                 filled=False)
+
+    def test_is_valid(self):
+        creds = self._get_credentials()
+        self.assertTrue(creds.is_valid())
+
+    def _test_is_not_valid(self, ignore_key):
+        creds = self._get_credentials()
+        for attr in self.attributes.keys():
+            if attr == ignore_key:
+                continue
+            temp_attr = getattr(creds, attr)
+            delattr(creds, attr)
+            self.assertFalse(creds.is_valid(),
+                             "Credentials should be invalid without %s" % attr)
+            setattr(creds, attr, temp_attr)
+
+    def test_is_not_valid(self):
+        # NOTE(mtreinish): A KeystoneV2 credential object is valid without
+        # a tenant_name. So skip that check. See tempest.auth for the valid
+        # credential requirements
+        self._test_is_not_valid('tenant_name')
+
+    def test_reset_all_attributes(self):
+        creds = self._get_credentials()
+        initial_creds = copy.deepcopy(creds)
+        set_attr = creds.__dict__.keys()
+        missing_attr = set(creds.ATTRIBUTES).difference(set_attr)
+        # Set all unset attributes, then reset
+        for attr in missing_attr:
+            setattr(creds, attr, 'fake' + attr)
+        creds.reset()
+        # Check reset credentials are same as initial ones
+        self.assertEqual(creds, initial_creds)
+
+    def test_reset_single_attribute(self):
+        creds = self._get_credentials()
+        initial_creds = copy.deepcopy(creds)
+        set_attr = creds.__dict__.keys()
+        missing_attr = set(creds.ATTRIBUTES).difference(set_attr)
+        # Set one unset attributes, then reset
+        for attr in missing_attr:
+            setattr(creds, attr, 'fake' + attr)
+            creds.reset()
+            # Check reset credentials are same as initial ones
+            self.assertEqual(creds, initial_creds)
+
+
+class KeystoneV3CredentialsTests(KeystoneV2CredentialsTests):
+    attributes = {
+        'username': 'fake_username',
+        'password': 'fake_password',
+        'project_name': 'fake_project_name',
+        'user_domain_name': 'fake_domain_name'
+    }
+
+    credentials_class = auth.KeystoneV3Credentials
+    identity_response = fake_identity._fake_v3_response
+    tokenclient_class = v3_client.V3TokenClient
+    identity_version = 'v3'
+
+    def test_is_not_valid(self):
+        # NOTE(mtreinish) For a Keystone V3 credential object a project name
+        # is not required to be valid, so we skip that check. See tempest.auth
+        # for the valid credential requirements
+        self._test_is_not_valid('project_name')
+
+    def test_synced_attributes(self):
+        attributes = self.attributes
+        # Create V3 credentials with tenant instead of project, and user_domain
+        for attr in ['project_id', 'user_domain_id']:
+            attributes[attr] = 'fake_' + attr
+        creds = self._get_credentials(attributes)
+        self.assertEqual(creds.project_name, creds.tenant_name)
+        self.assertEqual(creds.project_id, creds.tenant_id)
+        self.assertEqual(creds.user_domain_name, creds.project_domain_name)
+        self.assertEqual(creds.user_domain_id, creds.project_domain_id)
+        # Replace user_domain with project_domain
+        del attributes['user_domain_name']
+        del attributes['user_domain_id']
+        del attributes['project_name']
+        del attributes['project_id']
+        for attr in ['project_domain_name', 'project_domain_id',
+                     'tenant_name', 'tenant_id']:
+            attributes[attr] = 'fake_' + attr
+        self.assertEqual(creds.tenant_name, creds.project_name)
+        self.assertEqual(creds.tenant_id, creds.project_id)
+        self.assertEqual(creds.project_domain_name, creds.user_domain_name)
+        self.assertEqual(creds.project_domain_id, creds.user_domain_id)
diff --git a/tempest/tests/lib/test_decorators.py b/tempest/tests/lib/test_decorators.py
new file mode 100644
index 0000000..558445d
--- /dev/null
+++ b/tempest/tests/lib/test_decorators.py
@@ -0,0 +1,126 @@
+# Copyright 2013 IBM Corp
+# Copyright 2015 Hewlett-Packard Development Company, L.P.
+#
+#    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 uuid
+
+import testtools
+
+from tempest.lib import base as test
+from tempest.lib import decorators
+from tempest.tests.lib import base
+
+
+class TestSkipBecauseDecorator(base.TestCase):
+    def _test_skip_because_helper(self, expected_to_skip=True,
+                                  **decorator_args):
+        class TestFoo(test.BaseTestCase):
+            _interface = 'json'
+
+            @decorators.skip_because(**decorator_args)
+            def test_bar(self):
+                return 0
+
+        t = TestFoo('test_bar')
+        if expected_to_skip:
+            self.assertRaises(testtools.TestCase.skipException, t.test_bar)
+        else:
+            # assert that test_bar returned 0
+            self.assertEqual(TestFoo('test_bar').test_bar(), 0)
+
+    def test_skip_because_bug(self):
+        self._test_skip_because_helper(bug='12345')
+
+    def test_skip_because_bug_and_condition_true(self):
+        self._test_skip_because_helper(bug='12348', condition=True)
+
+    def test_skip_because_bug_and_condition_false(self):
+        self._test_skip_because_helper(expected_to_skip=False,
+                                       bug='12349', condition=False)
+
+    def test_skip_because_bug_without_bug_never_skips(self):
+        """Never skip without a bug parameter."""
+        self._test_skip_because_helper(expected_to_skip=False,
+                                       condition=True)
+        self._test_skip_because_helper(expected_to_skip=False)
+
+    def test_skip_because_invalid_bug_number(self):
+        """Raise ValueError if with an invalid bug number"""
+        self.assertRaises(ValueError, self._test_skip_because_helper,
+                          bug='critical_bug')
+
+
+class TestIdempotentIdDecorator(base.TestCase):
+    def _test_helper(self, _id, **decorator_args):
+        @decorators.idempotent_id(_id)
+        def foo():
+            """Docstring"""
+            pass
+
+        return foo
+
+    def _test_helper_without_doc(self, _id, **decorator_args):
+        @decorators.idempotent_id(_id)
+        def foo():
+            pass
+
+        return foo
+
+    def test_positive(self):
+        _id = str(uuid.uuid4())
+        foo = self._test_helper(_id)
+        self.assertIn('id-%s' % _id, getattr(foo, '__testtools_attrs'))
+        self.assertTrue(foo.__doc__.startswith('Test idempotent id: %s' % _id))
+
+    def test_positive_without_doc(self):
+        _id = str(uuid.uuid4())
+        foo = self._test_helper_without_doc(_id)
+        self.assertTrue(foo.__doc__.startswith('Test idempotent id: %s' % _id))
+
+    def test_idempotent_id_not_str(self):
+        _id = 42
+        self.assertRaises(TypeError, self._test_helper, _id)
+
+    def test_idempotent_id_not_valid_uuid(self):
+        _id = '42'
+        self.assertRaises(ValueError, self._test_helper, _id)
+
+
+class TestSkipUnlessAttrDecorator(base.TestCase):
+    def _test_skip_unless_attr(self, attr, expected_to_skip=True):
+        class TestFoo(test.BaseTestCase):
+            expected_attr = not expected_to_skip
+
+            @decorators.skip_unless_attr(attr)
+            def test_foo(self):
+                pass
+
+        t = TestFoo('test_foo')
+        if expected_to_skip:
+            self.assertRaises(testtools.TestCase.skipException,
+                              t.test_foo())
+        else:
+            try:
+                t.test_foo()
+            except Exception:
+                raise testtools.TestCase.failureException()
+
+    def test_skip_attr_does_not_exist(self):
+        self._test_skip_unless_attr('unexpected_attr')
+
+    def test_skip_attr_false(self):
+        self._test_skip_unless_attr('expected_attr')
+
+    def test_no_skip_for_attr_exist_and_true(self):
+        self._test_skip_unless_attr('expected_attr', expected_to_skip=False)
diff --git a/tempest/tests/lib/test_rest_client.py b/tempest/tests/lib/test_rest_client.py
new file mode 100644
index 0000000..87af455
--- /dev/null
+++ b/tempest/tests/lib/test_rest_client.py
@@ -0,0 +1,1075 @@
+# 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 copy
+import json
+
+import httplib2
+import jsonschema
+from oslotest import mockpatch
+import six
+
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions
+from tempest.tests.lib import base
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib import fake_http
+import tempest.tests.utils as utils
+
+
+class BaseRestClientTestClass(base.TestCase):
+
+    url = 'fake_endpoint'
+
+    def setUp(self):
+        super(BaseRestClientTestClass, self).setUp()
+        self.fake_auth_provider = fake_auth_provider.FakeAuthProvider()
+        self.rest_client = rest_client.RestClient(
+            self.fake_auth_provider, None, None)
+        self.stubs.Set(httplib2.Http, 'request', self.fake_http.request)
+        self.useFixture(mockpatch.PatchObject(self.rest_client,
+                                              '_log_request'))
+
+
+class TestRestClientHTTPMethods(BaseRestClientTestClass):
+    def setUp(self):
+        self.fake_http = fake_http.fake_httplib2()
+        super(TestRestClientHTTPMethods, self).setUp()
+        self.useFixture(mockpatch.PatchObject(self.rest_client,
+                                              '_error_checker'))
+
+    def test_post(self):
+        __, return_dict = self.rest_client.post(self.url, {}, {})
+        self.assertEqual('POST', return_dict['method'])
+
+    def test_get(self):
+        __, return_dict = self.rest_client.get(self.url)
+        self.assertEqual('GET', return_dict['method'])
+
+    def test_delete(self):
+        __, return_dict = self.rest_client.delete(self.url)
+        self.assertEqual('DELETE', return_dict['method'])
+
+    def test_patch(self):
+        __, return_dict = self.rest_client.patch(self.url, {}, {})
+        self.assertEqual('PATCH', return_dict['method'])
+
+    def test_put(self):
+        __, return_dict = self.rest_client.put(self.url, {}, {})
+        self.assertEqual('PUT', return_dict['method'])
+
+    def test_head(self):
+        self.useFixture(mockpatch.PatchObject(self.rest_client,
+                                              'response_checker'))
+        __, return_dict = self.rest_client.head(self.url)
+        self.assertEqual('HEAD', return_dict['method'])
+
+    def test_copy(self):
+        __, return_dict = self.rest_client.copy(self.url)
+        self.assertEqual('COPY', return_dict['method'])
+
+
+class TestRestClientNotFoundHandling(BaseRestClientTestClass):
+    def setUp(self):
+        self.fake_http = fake_http.fake_httplib2(404)
+        super(TestRestClientNotFoundHandling, self).setUp()
+
+    def test_post(self):
+        self.assertRaises(exceptions.NotFound, self.rest_client.post,
+                          self.url, {}, {})
+
+
+class TestRestClientHeadersJSON(TestRestClientHTTPMethods):
+    TYPE = "json"
+
+    def _verify_headers(self, resp):
+        self.assertEqual(self.rest_client._get_type(), self.TYPE)
+        resp = dict((k.lower(), v) for k, v in six.iteritems(resp))
+        self.assertEqual(self.header_value, resp['accept'])
+        self.assertEqual(self.header_value, resp['content-type'])
+
+    def setUp(self):
+        super(TestRestClientHeadersJSON, self).setUp()
+        self.rest_client.TYPE = self.TYPE
+        self.header_value = 'application/%s' % self.rest_client._get_type()
+
+    def test_post(self):
+        resp, __ = self.rest_client.post(self.url, {})
+        self._verify_headers(resp)
+
+    def test_get(self):
+        resp, __ = self.rest_client.get(self.url)
+        self._verify_headers(resp)
+
+    def test_delete(self):
+        resp, __ = self.rest_client.delete(self.url)
+        self._verify_headers(resp)
+
+    def test_patch(self):
+        resp, __ = self.rest_client.patch(self.url, {})
+        self._verify_headers(resp)
+
+    def test_put(self):
+        resp, __ = self.rest_client.put(self.url, {})
+        self._verify_headers(resp)
+
+    def test_head(self):
+        self.useFixture(mockpatch.PatchObject(self.rest_client,
+                                              'response_checker'))
+        resp, __ = self.rest_client.head(self.url)
+        self._verify_headers(resp)
+
+    def test_copy(self):
+        resp, __ = self.rest_client.copy(self.url)
+        self._verify_headers(resp)
+
+
+class TestRestClientUpdateHeaders(BaseRestClientTestClass):
+    def setUp(self):
+        self.fake_http = fake_http.fake_httplib2()
+        super(TestRestClientUpdateHeaders, self).setUp()
+        self.useFixture(mockpatch.PatchObject(self.rest_client,
+                                              '_error_checker'))
+        self.headers = {'X-Configuration-Session': 'session_id'}
+
+    def test_post_update_headers(self):
+        __, return_dict = self.rest_client.post(self.url, {},
+                                                extra_headers=True,
+                                                headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+    def test_get_update_headers(self):
+        __, return_dict = self.rest_client.get(self.url,
+                                               extra_headers=True,
+                                               headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+    def test_delete_update_headers(self):
+        __, return_dict = self.rest_client.delete(self.url,
+                                                  extra_headers=True,
+                                                  headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+    def test_patch_update_headers(self):
+        __, return_dict = self.rest_client.patch(self.url, {},
+                                                 extra_headers=True,
+                                                 headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+    def test_put_update_headers(self):
+        __, return_dict = self.rest_client.put(self.url, {},
+                                               extra_headers=True,
+                                               headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+    def test_head_update_headers(self):
+        self.useFixture(mockpatch.PatchObject(self.rest_client,
+                                              'response_checker'))
+
+        __, return_dict = self.rest_client.head(self.url,
+                                                extra_headers=True,
+                                                headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+    def test_copy_update_headers(self):
+        __, return_dict = self.rest_client.copy(self.url,
+                                                extra_headers=True,
+                                                headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+
+class TestRestClientParseRespJSON(BaseRestClientTestClass):
+    TYPE = "json"
+
+    keys = ["fake_key1", "fake_key2"]
+    values = ["fake_value1", "fake_value2"]
+    item_expected = dict((key, value) for (key, value) in zip(keys, values))
+    list_expected = {"body_list": [
+        {keys[0]: values[0]},
+        {keys[1]: values[1]},
+    ]}
+    dict_expected = {"body_dict": {
+        keys[0]: values[0],
+        keys[1]: values[1],
+    }}
+    null_dict = {}
+
+    def setUp(self):
+        self.fake_http = fake_http.fake_httplib2()
+        super(TestRestClientParseRespJSON, self).setUp()
+        self.rest_client.TYPE = self.TYPE
+
+    def test_parse_resp_body_item(self):
+        body = self.rest_client._parse_resp(json.dumps(self.item_expected))
+        self.assertEqual(self.item_expected, body)
+
+    def test_parse_resp_body_list(self):
+        body = self.rest_client._parse_resp(json.dumps(self.list_expected))
+        self.assertEqual(self.list_expected["body_list"], body)
+
+    def test_parse_resp_body_dict(self):
+        body = self.rest_client._parse_resp(json.dumps(self.dict_expected))
+        self.assertEqual(self.dict_expected["body_dict"], body)
+
+    def test_parse_resp_two_top_keys(self):
+        dict_two_keys = self.dict_expected.copy()
+        dict_two_keys.update({"second_key": ""})
+        body = self.rest_client._parse_resp(json.dumps(dict_two_keys))
+        self.assertEqual(dict_two_keys, body)
+
+    def test_parse_resp_one_top_key_without_list_or_dict(self):
+        data = {"one_top_key": "not_list_or_dict_value"}
+        body = self.rest_client._parse_resp(json.dumps(data))
+        self.assertEqual(data, body)
+
+    def test_parse_nullable_dict(self):
+        body = self.rest_client._parse_resp(json.dumps(self.null_dict))
+        self.assertEqual(self.null_dict, body)
+
+
+class TestRestClientErrorCheckerJSON(base.TestCase):
+    c_type = "application/json"
+
+    def set_data(self, r_code, enc=None, r_body=None, absolute_limit=True):
+        if enc is None:
+            enc = self.c_type
+        resp_dict = {'status': r_code, 'content-type': enc}
+        resp_body = {'resp_body': 'fake_resp_body'}
+
+        if absolute_limit is False:
+            resp_dict.update({'retry-after': 120})
+            resp_body.update({'overLimit': {'message': 'fake_message'}})
+        resp = httplib2.Response(resp_dict)
+        data = {
+            "method": "fake_method",
+            "url": "fake_url",
+            "headers": "fake_headers",
+            "body": "fake_body",
+            "resp": resp,
+            "resp_body": json.dumps(resp_body)
+        }
+        if r_body is not None:
+            data.update({"resp_body": r_body})
+        return data
+
+    def setUp(self):
+        super(TestRestClientErrorCheckerJSON, self).setUp()
+        self.rest_client = rest_client.RestClient(
+            fake_auth_provider.FakeAuthProvider(), None, None)
+
+    def test_response_less_than_400(self):
+        self.rest_client._error_checker(**self.set_data("399"))
+
+    def _test_error_checker(self, exception_type, data):
+        e = self.assertRaises(exception_type,
+                              self.rest_client._error_checker,
+                              **data)
+        self.assertEqual(e.resp, data['resp'])
+        self.assertTrue(hasattr(e, 'resp_body'))
+        return e
+
+    def test_response_400(self):
+        self._test_error_checker(exceptions.BadRequest, self.set_data("400"))
+
+    def test_response_401(self):
+        self._test_error_checker(exceptions.Unauthorized, self.set_data("401"))
+
+    def test_response_403(self):
+        self._test_error_checker(exceptions.Forbidden, self.set_data("403"))
+
+    def test_response_404(self):
+        self._test_error_checker(exceptions.NotFound, self.set_data("404"))
+
+    def test_response_409(self):
+        self._test_error_checker(exceptions.Conflict, self.set_data("409"))
+
+    def test_response_410(self):
+        self._test_error_checker(exceptions.Gone, self.set_data("410"))
+
+    def test_response_413(self):
+        self._test_error_checker(exceptions.OverLimit, self.set_data("413"))
+
+    def test_response_413_without_absolute_limit(self):
+        self._test_error_checker(exceptions.RateLimitExceeded,
+                                 self.set_data("413", absolute_limit=False))
+
+    def test_response_415(self):
+        self._test_error_checker(exceptions.InvalidContentType,
+                                 self.set_data("415"))
+
+    def test_response_422(self):
+        self._test_error_checker(exceptions.UnprocessableEntity,
+                                 self.set_data("422"))
+
+    def test_response_500_with_text(self):
+        # _parse_resp is expected to return 'str'
+        self._test_error_checker(exceptions.ServerFault, self.set_data("500"))
+
+    def test_response_501_with_text(self):
+        self._test_error_checker(exceptions.NotImplemented,
+                                 self.set_data("501"))
+
+    def test_response_400_with_dict(self):
+        r_body = '{"resp_body": {"err": "fake_resp_body"}}'
+        e = self._test_error_checker(exceptions.BadRequest,
+                                     self.set_data("400", r_body=r_body))
+
+        if self.c_type == 'application/json':
+            expected = {"err": "fake_resp_body"}
+        else:
+            expected = r_body
+        self.assertEqual(expected, e.resp_body)
+
+    def test_response_401_with_dict(self):
+        r_body = '{"resp_body": {"err": "fake_resp_body"}}'
+        e = self._test_error_checker(exceptions.Unauthorized,
+                                     self.set_data("401", r_body=r_body))
+
+        if self.c_type == 'application/json':
+            expected = {"err": "fake_resp_body"}
+        else:
+            expected = r_body
+        self.assertEqual(expected, e.resp_body)
+
+    def test_response_403_with_dict(self):
+        r_body = '{"resp_body": {"err": "fake_resp_body"}}'
+        e = self._test_error_checker(exceptions.Forbidden,
+                                     self.set_data("403", r_body=r_body))
+
+        if self.c_type == 'application/json':
+            expected = {"err": "fake_resp_body"}
+        else:
+            expected = r_body
+        self.assertEqual(expected, e.resp_body)
+
+    def test_response_404_with_dict(self):
+        r_body = '{"resp_body": {"err": "fake_resp_body"}}'
+        e = self._test_error_checker(exceptions.NotFound,
+                                     self.set_data("404", r_body=r_body))
+
+        if self.c_type == 'application/json':
+            expected = {"err": "fake_resp_body"}
+        else:
+            expected = r_body
+        self.assertEqual(expected, e.resp_body)
+
+    def test_response_404_with_invalid_dict(self):
+        r_body = '{"foo": "bar"]'
+        e = self._test_error_checker(exceptions.NotFound,
+                                     self.set_data("404", r_body=r_body))
+
+        expected = r_body
+        self.assertEqual(expected, e.resp_body)
+
+    def test_response_410_with_dict(self):
+        r_body = '{"resp_body": {"err": "fake_resp_body"}}'
+        e = self._test_error_checker(exceptions.Gone,
+                                     self.set_data("410", r_body=r_body))
+
+        if self.c_type == 'application/json':
+            expected = {"err": "fake_resp_body"}
+        else:
+            expected = r_body
+        self.assertEqual(expected, e.resp_body)
+
+    def test_response_410_with_invalid_dict(self):
+        r_body = '{"foo": "bar"]'
+        e = self._test_error_checker(exceptions.Gone,
+                                     self.set_data("410", r_body=r_body))
+
+        expected = r_body
+        self.assertEqual(expected, e.resp_body)
+
+    def test_response_409_with_dict(self):
+        r_body = '{"resp_body": {"err": "fake_resp_body"}}'
+        e = self._test_error_checker(exceptions.Conflict,
+                                     self.set_data("409", r_body=r_body))
+
+        if self.c_type == 'application/json':
+            expected = {"err": "fake_resp_body"}
+        else:
+            expected = r_body
+        self.assertEqual(expected, e.resp_body)
+
+    def test_response_500_with_dict(self):
+        r_body = '{"resp_body": {"err": "fake_resp_body"}}'
+        e = self._test_error_checker(exceptions.ServerFault,
+                                     self.set_data("500", r_body=r_body))
+
+        if self.c_type == 'application/json':
+            expected = {"err": "fake_resp_body"}
+        else:
+            expected = r_body
+        self.assertEqual(expected, e.resp_body)
+
+    def test_response_501_with_dict(self):
+        r_body = '{"resp_body": {"err": "fake_resp_body"}}'
+        self._test_error_checker(exceptions.NotImplemented,
+                                 self.set_data("501", r_body=r_body))
+
+    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)
+        self._test_error_checker(exceptions.UnexpectedResponseCode,
+                                 self.set_data("402"))
+
+
+class TestRestClientErrorCheckerTEXT(TestRestClientErrorCheckerJSON):
+    c_type = "text/plain"
+
+    def test_fake_content_type(self):
+        # This test is required only in one exemplar
+        # Any response code, that bigger than 400, and not in
+        # (401, 403, 404, 409, 413, 422, 500, 501)
+        self._test_error_checker(exceptions.UnexpectedContentType,
+                                 self.set_data("405", enc="fake_enc"))
+
+    def test_response_413_without_absolute_limit(self):
+        # Skip this test because rest_client cannot get overLimit message
+        # from text body.
+        pass
+
+
+class TestRestClientUtils(BaseRestClientTestClass):
+
+    def _is_resource_deleted(self, resource_id):
+        if not isinstance(self.retry_pass, int):
+            return False
+        if self.retry_count >= self.retry_pass:
+            return True
+        self.retry_count = self.retry_count + 1
+        return False
+
+    def setUp(self):
+        self.fake_http = fake_http.fake_httplib2()
+        super(TestRestClientUtils, self).setUp()
+        self.retry_count = 0
+        self.retry_pass = None
+        self.original_deleted_method = self.rest_client.is_resource_deleted
+        self.rest_client.is_resource_deleted = self._is_resource_deleted
+
+    def test_wait_for_resource_deletion(self):
+        self.retry_pass = 2
+        # Ensure timeout long enough for loop execution to hit retry count
+        self.rest_client.build_timeout = 500
+        sleep_mock = self.patch('time.sleep')
+        self.rest_client.wait_for_resource_deletion('1234')
+        self.assertEqual(len(sleep_mock.mock_calls), 2)
+
+    def test_wait_for_resource_deletion_not_deleted(self):
+        self.patch('time.sleep')
+        # Set timeout to be very quick to force exception faster
+        timeout = 1
+        self.rest_client.build_timeout = timeout
+
+        time_mock = self.patch('time.time')
+        time_mock.side_effect = utils.generate_timeout_series(timeout)
+
+        self.assertRaises(exceptions.TimeoutException,
+                          self.rest_client.wait_for_resource_deletion,
+                          '1234')
+
+        # time.time() should be called twice, first to start the timer
+        # and then to compute the timedelta
+        self.assertEqual(2, time_mock.call_count)
+
+    def test_wait_for_deletion_with_unimplemented_deleted_method(self):
+        self.rest_client.is_resource_deleted = self.original_deleted_method
+        self.assertRaises(NotImplementedError,
+                          self.rest_client.wait_for_resource_deletion,
+                          '1234')
+
+    def test_get_versions(self):
+        self.rest_client._parse_resp = lambda x: [{'id': 'v1'}, {'id': 'v2'}]
+        actual_resp, actual_versions = self.rest_client.get_versions()
+        self.assertEqual(['v1', 'v2'], list(actual_versions))
+
+    def test__str__(self):
+        def get_token():
+            return "deadbeef"
+
+        self.fake_auth_provider.get_token = get_token
+        self.assertIsNotNone(str(self.rest_client))
+
+
+class TestProperties(BaseRestClientTestClass):
+
+    def setUp(self):
+        self.fake_http = fake_http.fake_httplib2()
+        super(TestProperties, self).setUp()
+        creds_dict = {
+            'username': 'test-user',
+            'user_id': 'test-user_id',
+            'tenant_name': 'test-tenant_name',
+            'tenant_id': 'test-tenant_id',
+            'password': 'test-password'
+        }
+        self.rest_client = rest_client.RestClient(
+            fake_auth_provider.FakeAuthProvider(creds_dict=creds_dict),
+            None, None)
+
+    def test_properties(self):
+        self.assertEqual('test-user', self.rest_client.user)
+        self.assertEqual('test-user_id', self.rest_client.user_id)
+        self.assertEqual('test-tenant_name', self.rest_client.tenant_name)
+        self.assertEqual('test-tenant_id', self.rest_client.tenant_id)
+        self.assertEqual('test-password', self.rest_client.password)
+
+        self.rest_client.api_version = 'v1'
+        expected = {'api_version': 'v1',
+                    'endpoint_type': 'publicURL',
+                    'region': None,
+                    'service': None,
+                    'skip_path': True}
+        self.rest_client.skip_path()
+        self.assertEqual(expected, self.rest_client.filters)
+
+        self.rest_client.reset_path()
+        self.rest_client.api_version = 'v1'
+        expected = {'api_version': 'v1',
+                    'endpoint_type': 'publicURL',
+                    'region': None,
+                    'service': None}
+        self.assertEqual(expected, self.rest_client.filters)
+
+
+class TestExpectedSuccess(BaseRestClientTestClass):
+
+    def setUp(self):
+        self.fake_http = fake_http.fake_httplib2()
+        super(TestExpectedSuccess, self).setUp()
+
+    def test_expected_succes_int_match(self):
+        expected_code = 202
+        read_code = 202
+        resp = self.rest_client.expected_success(expected_code, read_code)
+        # Assert None resp on success
+        self.assertFalse(resp)
+
+    def test_expected_succes_int_no_match(self):
+        expected_code = 204
+        read_code = 202
+        self.assertRaises(exceptions.InvalidHttpSuccessCode,
+                          self.rest_client.expected_success,
+                          expected_code, read_code)
+
+    def test_expected_succes_list_match(self):
+        expected_code = [202, 204]
+        read_code = 202
+        resp = self.rest_client.expected_success(expected_code, read_code)
+        # Assert None resp on success
+        self.assertFalse(resp)
+
+    def test_expected_succes_list_no_match(self):
+        expected_code = [202, 204]
+        read_code = 200
+        self.assertRaises(exceptions.InvalidHttpSuccessCode,
+                          self.rest_client.expected_success,
+                          expected_code, read_code)
+
+    def test_non_success_expected_int(self):
+        expected_code = 404
+        read_code = 202
+        self.assertRaises(AssertionError, self.rest_client.expected_success,
+                          expected_code, read_code)
+
+    def test_non_success_expected_list(self):
+        expected_code = [404, 202]
+        read_code = 202
+        self.assertRaises(AssertionError, self.rest_client.expected_success,
+                          expected_code, read_code)
+
+
+class TestResponseBody(base.TestCase):
+
+    def test_str(self):
+        response = {'status': 200}
+        body = {'key1': 'value1'}
+        actual = rest_client.ResponseBody(response, body)
+        self.assertEqual("response: %s\nBody: %s" % (response, body),
+                         str(actual))
+
+
+class TestResponseBodyData(base.TestCase):
+
+    def test_str(self):
+        response = {'status': 200}
+        data = 'data1'
+        actual = rest_client.ResponseBodyData(response, data)
+        self.assertEqual("response: %s\nBody: %s" % (response, data),
+                         str(actual))
+
+
+class TestResponseBodyList(base.TestCase):
+
+    def test_str(self):
+        response = {'status': 200}
+        body = ['value1', 'value2', 'value3']
+        actual = rest_client.ResponseBodyList(response, body)
+        self.assertEqual("response: %s\nBody: %s" % (response, body),
+                         str(actual))
+
+
+class TestJSONSchemaValidationBase(base.TestCase):
+
+    class Response(dict):
+
+        def __getattr__(self, attr):
+            return self[attr]
+
+        def __setattr__(self, attr, value):
+            self[attr] = value
+
+    def setUp(self):
+        super(TestJSONSchemaValidationBase, self).setUp()
+        self.fake_auth_provider = fake_auth_provider.FakeAuthProvider()
+        self.rest_client = rest_client.RestClient(
+            self.fake_auth_provider, None, None)
+
+    def _test_validate_pass(self, schema, resp_body, status=200):
+        resp = self.Response()
+        resp.status = status
+        self.rest_client.validate_response(schema, resp, resp_body)
+
+    def _test_validate_fail(self, schema, resp_body, status=200,
+                            error_msg="HTTP response body is invalid"):
+        resp = self.Response()
+        resp.status = status
+        ex = self.assertRaises(exceptions.InvalidHTTPResponseBody,
+                               self.rest_client.validate_response,
+                               schema, resp, resp_body)
+        self.assertIn(error_msg, ex._error_string)
+
+
+class TestRestClientJSONSchemaValidation(TestJSONSchemaValidationBase):
+
+    schema = {
+        'status_code': [200],
+        'response_body': {
+            'type': 'object',
+            'properties': {
+                'foo': {
+                    'type': 'integer',
+                },
+            },
+            'required': ['foo']
+        }
+    }
+
+    def test_validate_pass_with_http_success_code(self):
+        body = {'foo': 12}
+        self._test_validate_pass(self.schema, body, status=200)
+
+    def test_validate_pass_with_http_redirect_code(self):
+        body = {'foo': 12}
+        schema = copy.deepcopy(self.schema)
+        schema['status_code'] = 300
+        self._test_validate_pass(schema, body, status=300)
+
+    def test_validate_not_http_success_code(self):
+        schema = {
+            'status_code': [200]
+        }
+        body = {}
+        self._test_validate_pass(schema, body, status=400)
+
+    def test_validate_multiple_allowed_type(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'foo': {
+                        'type': ['integer', 'string'],
+                    },
+                },
+                'required': ['foo']
+            }
+        }
+        body = {'foo': 12}
+        self._test_validate_pass(schema, body)
+        body = {'foo': '12'}
+        self._test_validate_pass(schema, body)
+
+    def test_validate_enable_additional_property_pass(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'foo': {'type': 'integer'}
+                },
+                'additionalProperties': True,
+                'required': ['foo']
+            }
+        }
+        body = {'foo': 12, 'foo2': 'foo2value'}
+        self._test_validate_pass(schema, body)
+
+    def test_validate_disable_additional_property_pass(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'foo': {'type': 'integer'}
+                },
+                'additionalProperties': False,
+                'required': ['foo']
+            }
+        }
+        body = {'foo': 12}
+        self._test_validate_pass(schema, body)
+
+    def test_validate_disable_additional_property_fail(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'foo': {'type': 'integer'}
+                },
+                'additionalProperties': False,
+                'required': ['foo']
+            }
+        }
+        body = {'foo': 12, 'foo2': 'foo2value'}
+        self._test_validate_fail(schema, body)
+
+    def test_validate_wrong_status_code(self):
+        schema = {
+            'status_code': [202]
+        }
+        body = {}
+        resp = self.Response()
+        resp.status = 200
+        ex = self.assertRaises(exceptions.InvalidHttpSuccessCode,
+                               self.rest_client.validate_response,
+                               schema, resp, body)
+        self.assertIn("Unexpected http success status code", ex._error_string)
+
+    def test_validate_wrong_attribute_type(self):
+        body = {'foo': 1.2}
+        self._test_validate_fail(self.schema, body)
+
+    def test_validate_unexpected_response_body(self):
+        schema = {
+            'status_code': [200],
+        }
+        body = {'foo': 12}
+        self._test_validate_fail(
+            schema, body,
+            error_msg="HTTP response body should not exist")
+
+    def test_validate_missing_response_body(self):
+        body = {}
+        self._test_validate_fail(self.schema, body)
+
+    def test_validate_missing_required_attribute(self):
+        body = {'notfoo': 12}
+        self._test_validate_fail(self.schema, body)
+
+    def test_validate_response_body_not_list(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'list_items': {
+                        'type': 'array',
+                        'items': {'foo': {'type': 'integer'}}
+                    }
+                },
+                'required': ['list_items'],
+            }
+        }
+        body = {'foo': 12}
+        self._test_validate_fail(schema, body)
+
+    def test_validate_response_body_list_pass(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'list_items': {
+                        'type': 'array',
+                        'items': {'foo': {'type': 'integer'}}
+                    }
+                },
+                'required': ['list_items'],
+            }
+        }
+        body = {'list_items': [{'foo': 12}, {'foo': 10}]}
+        self._test_validate_pass(schema, body)
+
+
+class TestRestClientJSONHeaderSchemaValidation(TestJSONSchemaValidationBase):
+
+    schema = {
+        'status_code': [200],
+        'response_header': {
+            'type': 'object',
+            'properties': {
+                'foo': {'type': 'integer'}
+            },
+            'required': ['foo']
+        }
+    }
+
+    def test_validate_header_schema_pass(self):
+        resp_body = {}
+        resp = self.Response()
+        resp.status = 200
+        resp.foo = 12
+        self.rest_client.validate_response(self.schema, resp, resp_body)
+
+    def test_validate_header_schema_fail(self):
+        resp_body = {}
+        resp = self.Response()
+        resp.status = 200
+        resp.foo = 1.2
+        ex = self.assertRaises(exceptions.InvalidHTTPResponseHeader,
+                               self.rest_client.validate_response,
+                               self.schema, resp, resp_body)
+        self.assertIn("HTTP response header is invalid", ex._error_string)
+
+
+class TestRestClientJSONSchemaFormatValidation(TestJSONSchemaValidationBase):
+
+    schema = {
+        'status_code': [200],
+        'response_body': {
+            'type': 'object',
+            'properties': {
+                'foo': {
+                    'type': 'string',
+                    'format': 'email'
+                }
+            },
+            'required': ['foo']
+        }
+    }
+
+    def test_validate_format_pass(self):
+        body = {'foo': 'example@example.com'}
+        self._test_validate_pass(self.schema, body)
+
+    def test_validate_format_fail(self):
+        body = {'foo': 'wrong_email'}
+        self._test_validate_fail(self.schema, body)
+
+    def test_validate_formats_in_oneOf_pass(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'foo': {
+                        'type': 'string',
+                        'oneOf': [
+                            {'format': 'ipv4'},
+                            {'format': 'ipv6'}
+                        ]
+                    }
+                },
+                'required': ['foo']
+            }
+        }
+        body = {'foo': '10.0.0.0'}
+        self._test_validate_pass(schema, body)
+        body = {'foo': 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329'}
+        self._test_validate_pass(schema, body)
+
+    def test_validate_formats_in_oneOf_fail_both_match(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'foo': {
+                        'type': 'string',
+                        'oneOf': [
+                            {'format': 'ipv4'},
+                            {'format': 'ipv4'}
+                        ]
+                    }
+                },
+                'required': ['foo']
+            }
+        }
+        body = {'foo': '10.0.0.0'}
+        self._test_validate_fail(schema, body)
+
+    def test_validate_formats_in_oneOf_fail_no_match(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'foo': {
+                        'type': 'string',
+                        'oneOf': [
+                            {'format': 'ipv4'},
+                            {'format': 'ipv6'}
+                        ]
+                    }
+                },
+                'required': ['foo']
+            }
+        }
+        body = {'foo': 'wrong_ip_format'}
+        self._test_validate_fail(schema, body)
+
+    def test_validate_formats_in_anyOf_pass(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'foo': {
+                        'type': 'string',
+                        'anyOf': [
+                            {'format': 'ipv4'},
+                            {'format': 'ipv6'}
+                        ]
+                    }
+                },
+                'required': ['foo']
+            }
+        }
+        body = {'foo': '10.0.0.0'}
+        self._test_validate_pass(schema, body)
+        body = {'foo': 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329'}
+        self._test_validate_pass(schema, body)
+
+    def test_validate_formats_in_anyOf_pass_both_match(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'foo': {
+                        'type': 'string',
+                        'anyOf': [
+                            {'format': 'ipv4'},
+                            {'format': 'ipv4'}
+                        ]
+                    }
+                },
+                'required': ['foo']
+            }
+        }
+        body = {'foo': '10.0.0.0'}
+        self._test_validate_pass(schema, body)
+
+    def test_validate_formats_in_anyOf_fail_no_match(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'foo': {
+                        'type': 'string',
+                        'anyOf': [
+                            {'format': 'ipv4'},
+                            {'format': 'ipv6'}
+                        ]
+                    }
+                },
+                'required': ['foo']
+            }
+        }
+        body = {'foo': 'wrong_ip_format'}
+        self._test_validate_fail(schema, body)
+
+    def test_validate_formats_pass_for_unknow_format(self):
+        schema = {
+            'status_code': [200],
+            'response_body': {
+                'type': 'object',
+                'properties': {
+                    'foo': {
+                        'type': 'string',
+                        'format': 'UNKNOWN'
+                    }
+                },
+                'required': ['foo']
+            }
+        }
+        body = {'foo': 'example@example.com'}
+        self._test_validate_pass(schema, body)
+
+
+class TestRestClientJSONSchemaValidatorVersion(TestJSONSchemaValidationBase):
+
+    schema = {
+        'status_code': [200],
+        'response_body': {
+            'type': 'object',
+            'properties': {
+                'foo': {'type': 'string'}
+            }
+        }
+    }
+
+    def test_current_json_schema_validator_version(self):
+        with mockpatch.PatchObject(jsonschema.Draft4Validator,
+                                   "check_schema") as chk_schema:
+            body = {'foo': 'test'}
+            self._test_validate_pass(self.schema, body)
+            chk_schema.mock.assert_called_once_with(
+                self.schema['response_body'])
diff --git a/tempest/tests/lib/test_ssh.py b/tempest/tests/lib/test_ssh.py
new file mode 100644
index 0000000..f6efd47
--- /dev/null
+++ b/tempest/tests/lib/test_ssh.py
@@ -0,0 +1,260 @@
+# Copyright 2014 OpenStack Foundation
+#
+#    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 io import StringIO
+import socket
+
+import mock
+import six
+import testtools
+
+from tempest.lib.common import ssh
+from tempest.lib import exceptions
+from tempest.tests.lib import base
+import tempest.tests.utils as utils
+
+
+class TestSshClient(base.TestCase):
+
+    SELECT_POLLIN = 1
+
+    @mock.patch('paramiko.RSAKey.from_private_key')
+    @mock.patch('six.StringIO')
+    def test_pkey_calls_paramiko_RSAKey(self, cs_mock, rsa_mock):
+        cs_mock.return_value = mock.sentinel.csio
+        pkey = 'mykey'
+        ssh.Client('localhost', 'root', pkey=pkey)
+        rsa_mock.assert_called_once_with(mock.sentinel.csio)
+        cs_mock.assert_called_once_with('mykey')
+        rsa_mock.reset_mock()
+        cs_mock.reset_mock()
+        pkey = mock.sentinel.pkey
+        # Shouldn't call out to load a file from RSAKey, since
+        # a sentinel isn't a basestring...
+        ssh.Client('localhost', 'root', pkey=pkey)
+        self.assertEqual(0, rsa_mock.call_count)
+        self.assertEqual(0, cs_mock.call_count)
+
+    def _set_ssh_connection_mocks(self):
+        client_mock = mock.MagicMock()
+        client_mock.connect.return_value = True
+        return (self.patch('paramiko.SSHClient'),
+                self.patch('paramiko.AutoAddPolicy'),
+                client_mock)
+
+    def test_get_ssh_connection(self):
+        c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
+        s_mock = self.patch('time.sleep')
+
+        c_mock.return_value = client_mock
+        aa_mock.return_value = mock.sentinel.aa
+
+        # Test normal case for successful connection on first try
+        client = ssh.Client('localhost', 'root', timeout=2)
+        client._get_ssh_connection(sleep=1)
+
+        aa_mock.assert_called_once_with()
+        client_mock.set_missing_host_key_policy.assert_called_once_with(
+            mock.sentinel.aa)
+        expected_connect = [mock.call(
+            'localhost',
+            username='root',
+            pkey=None,
+            key_filename=None,
+            look_for_keys=False,
+            timeout=10.0,
+            password=None
+        )]
+        self.assertEqual(expected_connect, client_mock.connect.mock_calls)
+        self.assertEqual(0, s_mock.call_count)
+
+    @mock.patch('time.sleep')
+    def test_get_ssh_connection_two_attemps(self, sleep_mock):
+        c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
+
+        c_mock.return_value = client_mock
+        client_mock.connect.side_effect = [
+            socket.error,
+            mock.MagicMock()
+        ]
+
+        client = ssh.Client('localhost', 'root', timeout=1)
+        client._get_ssh_connection(sleep=1)
+        # We slept 2 seconds: because sleep is "1" and backoff is "1" too
+        sleep_mock.assert_called_once_with(2)
+        self.assertEqual(2, client_mock.connect.call_count)
+
+    def test_get_ssh_connection_timeout(self):
+        c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
+
+        timeout = 2
+        time_mock = self.patch('time.time')
+        time_mock.side_effect = utils.generate_timeout_series(timeout + 1)
+
+        c_mock.return_value = client_mock
+        client_mock.connect.side_effect = [
+            socket.error,
+            socket.error,
+            socket.error,
+        ]
+
+        client = ssh.Client('localhost', 'root', timeout=timeout)
+        # We need to mock LOG here because LOG.info() calls time.time()
+        # in order to preprend a timestamp.
+        with mock.patch.object(ssh, 'LOG'):
+            self.assertRaises(exceptions.SSHTimeout,
+                              client._get_ssh_connection)
+
+        # time.time() should be called twice, first to start the timer
+        # and then to compute the timedelta
+        self.assertEqual(2, time_mock.call_count)
+
+    @mock.patch('select.POLLIN', SELECT_POLLIN, create=True)
+    def test_timeout_in_exec_command(self):
+        chan_mock, poll_mock, _ = self._set_mocks_for_select([0, 0, 0], True)
+
+        # Test for a timeout condition immediately raised
+        client = ssh.Client('localhost', 'root', timeout=2)
+        with testtools.ExpectedException(exceptions.TimeoutException):
+            client.exec_command("test")
+
+        chan_mock.fileno.assert_called_once_with()
+        chan_mock.exec_command.assert_called_once_with("test")
+        chan_mock.shutdown_write.assert_called_once_with()
+
+        poll_mock.register.assert_called_once_with(
+            chan_mock, self.SELECT_POLLIN)
+        poll_mock.poll.assert_called_once_with(10)
+
+    @mock.patch('select.POLLIN', SELECT_POLLIN, create=True)
+    def test_exec_command(self):
+        chan_mock, poll_mock, select_mock = (
+            self._set_mocks_for_select([[1, 0, 0]], True))
+        closed_prop = mock.PropertyMock(return_value=True)
+        type(chan_mock).closed = closed_prop
+
+        chan_mock.recv_exit_status.return_value = 0
+        chan_mock.recv.return_value = b''
+        chan_mock.recv_stderr.return_value = b''
+
+        client = ssh.Client('localhost', 'root', timeout=2)
+        client.exec_command("test")
+
+        chan_mock.fileno.assert_called_once_with()
+        chan_mock.exec_command.assert_called_once_with("test")
+        chan_mock.shutdown_write.assert_called_once_with()
+
+        select_mock.assert_called_once_with()
+        poll_mock.register.assert_called_once_with(
+            chan_mock, self.SELECT_POLLIN)
+        poll_mock.poll.assert_called_once_with(10)
+        chan_mock.recv_ready.assert_called_once_with()
+        chan_mock.recv.assert_called_once_with(1024)
+        chan_mock.recv_stderr_ready.assert_called_once_with()
+        chan_mock.recv_stderr.assert_called_once_with(1024)
+        chan_mock.recv_exit_status.assert_called_once_with()
+        closed_prop.assert_called_once_with()
+
+    def _set_mocks_for_select(self, poll_data, ito_value=False):
+        gsc_mock = self.patch('tempest.lib.common.ssh.Client.'
+                              '_get_ssh_connection')
+        ito_mock = self.patch('tempest.lib.common.ssh.Client._is_timed_out')
+        csp_mock = self.patch(
+            'tempest.lib.common.ssh.Client._can_system_poll')
+        csp_mock.return_value = True
+
+        select_mock = self.patch('select.poll', create=True)
+        client_mock = mock.MagicMock()
+        tran_mock = mock.MagicMock()
+        chan_mock = mock.MagicMock()
+        poll_mock = mock.MagicMock()
+
+        select_mock.return_value = poll_mock
+        gsc_mock.return_value = client_mock
+        ito_mock.return_value = ito_value
+        client_mock.get_transport.return_value = tran_mock
+        tran_mock.open_session.return_value = chan_mock
+        if isinstance(poll_data[0], list):
+            poll_mock.poll.side_effect = poll_data
+        else:
+            poll_mock.poll.return_value = poll_data
+
+        return chan_mock, poll_mock, select_mock
+
+    _utf8_string = six.unichr(1071)
+    _utf8_bytes = _utf8_string.encode("utf-8")
+
+    @mock.patch('select.POLLIN', SELECT_POLLIN, create=True)
+    def test_exec_good_command_output(self):
+        chan_mock, poll_mock, _ = self._set_mocks_for_select([1, 0, 0])
+        closed_prop = mock.PropertyMock(return_value=True)
+        type(chan_mock).closed = closed_prop
+
+        chan_mock.recv_exit_status.return_value = 0
+        chan_mock.recv.side_effect = [self._utf8_bytes[0:1],
+                                      self._utf8_bytes[1:], b'R', b'']
+        chan_mock.recv_stderr.return_value = b''
+
+        client = ssh.Client('localhost', 'root', timeout=2)
+        out_data = client.exec_command("test")
+        self.assertEqual(self._utf8_string + 'R', out_data)
+
+    @mock.patch('select.POLLIN', SELECT_POLLIN, create=True)
+    def test_exec_bad_command_output(self):
+        chan_mock, poll_mock, _ = self._set_mocks_for_select([1, 0, 0])
+        closed_prop = mock.PropertyMock(return_value=True)
+        type(chan_mock).closed = closed_prop
+
+        chan_mock.recv_exit_status.return_value = 1
+        chan_mock.recv.return_value = b''
+        chan_mock.recv_stderr.side_effect = [b'R', self._utf8_bytes[0:1],
+                                             self._utf8_bytes[1:], b'']
+
+        client = ssh.Client('localhost', 'root', timeout=2)
+        exc = self.assertRaises(exceptions.SSHExecCommandFailed,
+                                client.exec_command, "test")
+        self.assertIn('R' + self._utf8_string, six.text_type(exc))
+
+    def test_exec_command_no_select(self):
+        gsc_mock = self.patch('tempest.lib.common.ssh.Client.'
+                              '_get_ssh_connection')
+        csp_mock = self.patch(
+            'tempest.lib.common.ssh.Client._can_system_poll')
+        csp_mock.return_value = False
+
+        select_mock = self.patch('select.poll', create=True)
+        client_mock = mock.MagicMock()
+        tran_mock = mock.MagicMock()
+        chan_mock = mock.MagicMock()
+
+        # Test for proper reading of STDOUT and STDERROR
+
+        gsc_mock.return_value = client_mock
+        client_mock.get_transport.return_value = tran_mock
+        tran_mock.open_session.return_value = chan_mock
+        chan_mock.recv_exit_status.return_value = 0
+
+        std_out_mock = mock.MagicMock(StringIO)
+        std_err_mock = mock.MagicMock(StringIO)
+        chan_mock.makefile.return_value = std_out_mock
+        chan_mock.makefile_stderr.return_value = std_err_mock
+
+        client = ssh.Client('localhost', 'root', timeout=2)
+        client.exec_command("test")
+
+        chan_mock.makefile.assert_called_once_with('rb', 1024)
+        chan_mock.makefile_stderr.assert_called_once_with('rb', 1024)
+        std_out_mock.read.assert_called_once_with()
+        std_err_mock.read.assert_called_once_with()
+        self.assertFalse(select_mock.called)
diff --git a/tempest/tests/lib/test_tempest_lib.py b/tempest/tests/lib/test_tempest_lib.py
new file mode 100644
index 0000000..9731e96
--- /dev/null
+++ b/tempest/tests/lib/test_tempest_lib.py
@@ -0,0 +1,28 @@
+# -*- 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
+#
+#      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.
+
+"""
+test_tempest.lib
+----------------------------------
+
+Tests for `tempest.lib` module.
+"""
+
+from tempest.tests.lib import base
+
+
+class TestTempest_lib(base.TestCase):
+
+    def test_something(self):
+        pass
diff --git a/tempest/tests/services/compute/test_base_compute_client.py b/tempest/tests/services/compute/test_base_compute_client.py
index 7a55cdb..1a78247 100644
--- a/tempest/tests/services/compute/test_base_compute_client.py
+++ b/tempest/tests/services/compute/test_base_compute_client.py
@@ -13,10 +13,12 @@
 #    under the License.
 
 import httplib2
+import mock
 from oslotest import mockpatch
-from tempest_lib.common import rest_client
 
+from tempest.api.compute import api_microversion_fixture
 from tempest import exceptions
+from tempest.lib.common import rest_client
 from tempest.services.compute.json import base_compute_client
 from tempest.tests import fake_auth_provider
 from tempest.tests.services.compute import base
@@ -29,7 +31,7 @@
         fake_auth = fake_auth_provider.FakeAuthProvider()
         self.client = base_compute_client.BaseComputeClient(
             fake_auth, 'compute', 'regionOne')
-        self.client.set_api_microversion('2.2')
+        self.useFixture(api_microversion_fixture.APIMicroversionFixture('2.2'))
 
     def _check_microverion_header_in_response(self, fake_response):
         def request(*args, **kwargs):
@@ -75,7 +77,8 @@
         super(TestSchemaVersionsNone, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
         self.client = DummyServiceClient1(fake_auth, 'compute', 'regionOne')
-        self.client.api_microversion = self.api_microversion
+        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+            self.api_microversion))
 
     def test_schema(self):
         self.assertEqual(self.expected_schema,
@@ -129,8 +132,62 @@
         super(TestSchemaVersionsNotFound, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
         self.client = DummyServiceClient2(fake_auth, 'compute', 'regionOne')
-        self.client.api_microversion = self.api_microversion
+        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+            self.api_microversion))
 
     def test_schema(self):
         self.assertRaises(exceptions.JSONSchemaNotFound,
                           self.client.return_selected_schema)
+
+
+class TestClientWithoutMicroversionHeader(base.BaseComputeServiceTest):
+
+    def setUp(self):
+        super(TestClientWithoutMicroversionHeader, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = base_compute_client.BaseComputeClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def test_no_microverion_header(self):
+        header = self.client.get_headers()
+        self.assertNotIn('X-OpenStack-Nova-API-Version', header)
+
+    def test_no_microverion_header_in_raw_request(self):
+        def raw_request(*args, **kwargs):
+            self.assertNotIn('X-OpenStack-Nova-API-Version', kwargs['headers'])
+            return (httplib2.Response({'status': 200}), {})
+
+        with mock.patch.object(rest_client.RestClient,
+                               'raw_request') as mock_get:
+            mock_get.side_effect = raw_request
+            self.client.get('fake_url')
+
+
+class TestClientWithMicroversionHeader(base.BaseComputeServiceTest):
+
+    def setUp(self):
+        super(TestClientWithMicroversionHeader, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = base_compute_client.BaseComputeClient(
+            fake_auth, 'compute', 'regionOne')
+        self.useFixture(api_microversion_fixture.APIMicroversionFixture('2.2'))
+
+    def test_microverion_header(self):
+        header = self.client.get_headers()
+        self.assertIn('X-OpenStack-Nova-API-Version', header)
+        self.assertEqual('2.2',
+                         header['X-OpenStack-Nova-API-Version'])
+
+    def test_microverion_header_in_raw_request(self):
+        def raw_request(*args, **kwargs):
+            self.assertIn('X-OpenStack-Nova-API-Version', kwargs['headers'])
+            self.assertEqual('2.2',
+                             kwargs['headers']['X-OpenStack-Nova-API-Version'])
+            return (httplib2.Response(
+                {'status': 200,
+                 self.client.api_microversion_header_name: '2.2'}), {})
+
+        with mock.patch.object(rest_client.RestClient,
+                               'raw_request') as mock_get:
+            mock_get.side_effect = raw_request
+            self.client.get('fake_url')
diff --git a/tempest/tests/services/compute/test_keypairs_client.py b/tempest/tests/services/compute/test_keypairs_client.py
index 03aee53..e8f8280 100644
--- a/tempest/tests/services/compute/test_keypairs_client.py
+++ b/tempest/tests/services/compute/test_keypairs_client.py
@@ -14,9 +14,8 @@
 
 import copy
 
-from tempest_lib.tests import fake_auth_provider
-
 from tempest.services.compute.json import keypairs_client
+from tempest.tests.lib import fake_auth_provider
 from tempest.tests.services.compute import base
 
 
@@ -38,7 +37,7 @@
     def _test_list_keypairs(self, bytes_body=False):
         self.check_service_client_function(
             self.client.list_keypairs,
-            'tempest_lib.common.rest_client.RestClient.get',
+            'tempest.lib.common.rest_client.RestClient.get',
             {"keypairs": []},
             bytes_body)
 
@@ -60,7 +59,7 @@
 
         self.check_service_client_function(
             self.client.show_keypair,
-            'tempest_lib.common.rest_client.RestClient.get',
+            'tempest.lib.common.rest_client.RestClient.get',
             fake_keypair,
             bytes_body,
             keypair_name="test")
@@ -77,7 +76,7 @@
 
         self.check_service_client_function(
             self.client.create_keypair,
-            'tempest_lib.common.rest_client.RestClient.post',
+            'tempest.lib.common.rest_client.RestClient.post',
             fake_keypair,
             bytes_body,
             name="test")
@@ -91,5 +90,5 @@
     def test_delete_keypair(self):
         self.check_service_client_function(
             self.client.delete_keypair,
-            'tempest_lib.common.rest_client.RestClient.delete',
+            'tempest.lib.common.rest_client.RestClient.delete',
             {}, status=202, keypair_name='test')
diff --git a/tempest/tests/services/test_base_microversion_client.py b/tempest/tests/services/test_base_microversion_client.py
deleted file mode 100644
index 11b8170..0000000
--- a/tempest/tests/services/test_base_microversion_client.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# 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 httplib2
-import mock
-from tempest_lib.common import rest_client
-
-from tempest.services import base_microversion_client
-from tempest.tests import fake_auth_provider
-from tempest.tests.services.compute import base
-
-
-class TestClientWithoutMicroversionHeader(base.BaseComputeServiceTest):
-
-    def setUp(self):
-        super(TestClientWithoutMicroversionHeader, self).setUp()
-        fake_auth = fake_auth_provider.FakeAuthProvider()
-        self.client = base_microversion_client.BaseMicroversionClient(
-            fake_auth, 'compute', 'regionOne', 'X-OpenStack-Nova-API-Version')
-
-    def test_no_microverion_header(self):
-        header = self.client.get_headers()
-        self.assertNotIn(self.client.api_microversion_header_name, header)
-
-    def test_no_microverion_header_in_raw_request(self):
-        def raw_request(*args, **kwargs):
-            self.assertNotIn(self.client.api_microversion_header_name,
-                             kwargs['headers'])
-            return (httplib2.Response({'status': 200}), {})
-
-        with mock.patch.object(rest_client.RestClient,
-                               'raw_request') as mock_get:
-            mock_get.side_effect = raw_request
-            self.client.get('fake_url')
-
-
-class TestClientWithMicroversionHeader(base.BaseComputeServiceTest):
-
-    def setUp(self):
-        super(TestClientWithMicroversionHeader, self).setUp()
-        fake_auth = fake_auth_provider.FakeAuthProvider()
-        self.client = base_microversion_client.BaseMicroversionClient(
-            fake_auth, 'compute', 'regionOne', 'X-OpenStack-Nova-API-Version')
-        self.client.set_api_microversion('2.2')
-
-    def test_microverion_header(self):
-        header = self.client.get_headers()
-        self.assertIn(self.client.api_microversion_header_name, header)
-        self.assertEqual(self.client.api_microversion,
-                         header[self.client.api_microversion_header_name])
-
-    def test_microverion_header_in_raw_request(self):
-        def raw_request(*args, **kwargs):
-            self.assertIn(self.client.api_microversion_header_name,
-                          kwargs['headers'])
-            self.assertEqual(
-                self.client.api_microversion,
-                kwargs['headers'][self.client.api_microversion_header_name])
-            return (httplib2.Response({'status': 200}), {})
-
-        with mock.patch.object(rest_client.RestClient,
-                               'raw_request') as mock_get:
-            mock_get.side_effect = raw_request
-            self.client.get('fake_url')
diff --git a/tempest/tests/stress/test_stress.py b/tempest/tests/stress/test_stress.py
index 0ec2a5d..dfe0291 100644
--- a/tempest/tests/stress/test_stress.py
+++ b/tempest/tests/stress/test_stress.py
@@ -16,9 +16,8 @@
 import shlex
 import subprocess
 
-from tempest_lib import exceptions
-
 from oslo_log import log as logging
+from tempest.lib import exceptions
 from tempest.tests import base
 
 LOG = logging.getLogger(__name__)
diff --git a/tempest/tests/utils.py b/tempest/tests/utils.py
new file mode 100644
index 0000000..9c3049d
--- /dev/null
+++ b/tempest/tests/utils.py
@@ -0,0 +1,29 @@
+#    Copyright 2016 OpenStack Foundation
+#
+#    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.
+#
+
+
+def generate_timeout_series(timeout):
+    """Generate a series of times that exceeds the given timeout.
+
+    Yields a series of fake time.time() floating point numbers
+    such that the difference between each pair in the series just
+    exceeds the timeout value that is passed in.  Useful for
+    mocking time.time() in methods that otherwise wait for timeout
+    seconds.
+    """
+    iteration = 0
+    while True:
+        iteration += 1
+        yield (iteration * timeout) + iteration
diff --git a/tempest/version.py b/tempest/version.py
new file mode 100644
index 0000000..bc9f651
--- /dev/null
+++ b/tempest/version.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
+#
+# 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 pbr.version
+
+version_info = pbr.version.VersionInfo('tempest')
diff --git a/test-requirements.txt b/test-requirements.txt
index eb43f31..be3a4f1 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -6,6 +6,7 @@
 sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD
 python-subunit>=0.0.18 # Apache-2.0/BSD
 oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
+reno>=0.1.1 # Apache2
 mox>=0.5.3 # Apache-2.0
 mock>=1.2 # BSD
 coverage>=3.6 # Apache-2.0
diff --git a/tools/use_tempest_lib.sh b/tools/use_tempest_lib.sh
deleted file mode 100755
index ca62c4a..0000000
--- a/tools/use_tempest_lib.sh
+++ /dev/null
@@ -1,141 +0,0 @@
-#!/bin/bash
-#
-# Use this script to use interfaces/files from tempest-lib.
-# Many files have been migrated to tempest-lib and tempest has
-# its own copy too.
-# This script helps to remove those from tempest and make use of tempest-lib.
-# It adds the change-id of each file on which they were migrated in lib.
-# This should only be done for files which were migrated to lib with
-# "Migrated" in commit message as done by tempest-lib/tools/migrate_from_tempest.sh script.
-# "Migrated" keyword is used to fetch the migration commit history from lib.
-# To use:
-#  1. Create a new branch in the tempest repo so not to destroy your current
-#     working branch
-#  2. Run the script from the repo dir and specify the file paths relative to
-#     the root tempest dir(only code and unit tests):
-#
-#   tools/use_tempest_lib.sh.sh tempest/file1.py tempest/file2.py
-
-
-function usage {
-    echo "Usage: $0 [OPTION] file1 file2 .."
-    echo "Use files from tempest-lib"
-    echo -e "Input files should be tempest files with path. \n  Example- tempest/file1.py tempest/file2.py .."
-    echo ""
-    echo "-s, --service_client Specify if files are service clients."
-    echo "-u, --tempest_lib_git_url Specify the repo to clone tempest-lib from."
-}
-
-function check_all_files_valid {
-    failed=0
-    for file in $files; do
-        # Get the latest change-id for each file
-        latest_commit_id=`git log -n1 -- $file | grep "^commit" | awk '{print $2}'`
-        cd $tmpdir
-        filename=`basename $file`
-        lib_path=`find ./ -name $filename`
-        if [ -z $lib_path ]; then
-            echo "ERROR: $filename does not exist in tempest-lib."
-            failed=$(( failed + 1))
-            cd - > /dev/null
-            continue
-        fi
-        # Get the CHANGE_ID of tempest-lib patch where file was migrated
-        migration_change_id=`git log  -n1 --grep "Migrated" -- $lib_path | grep "Change-Id: " | awk '{print $2}'`
-        MIGRATION_IDS=`echo -e "$MIGRATION_IDS\n * $filename: $migration_change_id"`
-        # Get tempest CHANGE_ID of file which was migrated to lib
-        migrated_change_id=`git log  -n1 --grep "Migrated" -- $lib_path | grep "* $filename"`
-        migrated_change_id=${migrated_change_id#*:}
-        cd - > /dev/null
-        # Get the commit-id of tempest which was migrated to tempest-lib
-        migrated_commit_id=`git log --grep "$migrated_change_id" -- $file | grep "^commit" | awk '{print $2}'`
-        DIFF=$(git diff $latest_commit_id $migrated_commit_id $file)
-        if [ "$DIFF" != "" ]; then
-            echo "ERROR: $filename in tempest has been updated after migration to tempest-lib. First sync the file to tempest-lib."
-            failed=$(( failed + 1))
-        fi
-    done
-    if [[ $failed -gt 0 ]]; then
-        echo "$failed files had issues"
-        exit $failed
-    fi
-}
-
-set -e
-
-service_client=0
-file_list=''
-
-while [ $# -gt 0 ]; do
-    case "$1" in
-        -h|--help) usage; exit;;
-        -u|--tempest_lib_git_url) tempest_lib_git_url="$2"; shift;;
-        -s|--service_client) service_client=1;;
-        *) files="$files $1";;
-    esac
-    shift
-done
-
-if [ -z "$files" ]; then
-    usage; exit
-fi
-
-TEMPEST_LIB_GIT_URL=${tempest_lib_git_url:-git://git.openstack.org/openstack/tempest-lib}
-
-tmpdir=$(mktemp -d -t use-tempest-lib.XXXX)
-
-# Clone tempest-lib
-git clone $TEMPEST_LIB_GIT_URL $tmpdir
-
-# Checks all provided files are present in lib and
-# not updated in tempest after migration to lib.
-check_all_files_valid
-
-for file in $files; do
-    rm -f $file
-    tempest_dir=`pwd`
-    tempest_dir="$tempest_dir/tempest/"
-    tempest_dirname=`dirname $file`
-    lib_dirname=`echo $tempest_dirname | sed s@tempest\/@tempest_lib/\@`
-    # Convert tempest dirname to import string
-    tempest_import="${tempest_dirname//\//.}"
-    tempest_import=${tempest_import:2:${#tempest_import}}
-    if [ $service_client -eq 1 ]; then
-        # Remove /json path because tempest-lib supports JSON only without XML
-        lib_dirname=`echo $lib_dirname | sed s@\/json@@`
-    fi
-    # Convert tempest-lib dirname to import string
-    tempest_lib_import="${lib_dirname//\//.}"
-    tempest_lib_import=${tempest_lib_import:2:${#tempest_lib_import}}
-    module_name=`basename $file .py`
-    tempest_import1="from $tempest_import.$module_name"
-    tempest_lib_import1="from $tempest_lib_import.$module_name"
-    tempest_import2="from $tempest_import import $module_name"
-    tempest_lib_import2="from $tempest_lib_import import $module_name"
-    set +e
-    grep -rl "$tempest_import1" $tempest_dir | xargs sed -i'' s/"$tempest_import1"/"$tempest_lib_import1"/g 2> /dev/null
-    grep -rl "$tempest_import2" $tempest_dir | xargs sed -i'' s/"$tempest_import2"/"$tempest_lib_import2"/g 2> /dev/null
-    set -e
-    if [[ -z "$file_list" ]]; then
-        file_list="$module_name"
-    else
-        tmp_file_list="$file_list, $module_name"
-        char_size=`echo $tmp_file_list | wc -c`
-        if [ $char_size -lt 27 ]; then
-            file_list="$file_list, $module_name"
-        fi
-    fi
-done
-
-rm -rf $tmpdir
-echo "Completed. Run pep8 and fix error if any"
-
-git add -A tempest/
-# Generate a migration commit
-commit_message="Use $file_list from tempest-lib"
-pre_list=$"The files below have been migrated to tempest-lib\n"
-pre_list=`echo -e $pre_list`
-post_list=$"Now Tempest-lib provides those as stable interfaces. So Tempest should\nstart using those from lib and remove its own copy."
-post_list=`echo -e $post_list`
-
-git commit -m "$commit_message" -m "$pre_list" -m "$MIGRATION_IDS" -m "$post_list"
diff --git a/tox.ini b/tox.ini
index 95f2cf1..28dfe8b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -70,14 +70,6 @@
   find . -type f -name "*.pyc" -delete
   bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}'
 
-[testenv:large-ops]
-sitepackages = {[tempestenv]sitepackages}
-setenv = {[tempestenv]setenv}
-deps = {[tempestenv]deps}
-commands =
-  find . -type f -name "*.pyc" -delete
-  python setup.py testr --slowest --testr-args='tempest.scenario.test_large_ops {posargs}'
-
 [testenv:smoke]
 sitepackages = {[tempestenv]sitepackages}
 setenv = {[tempestenv]setenv}
@@ -132,3 +124,6 @@
 ignore = E125,E123,E129
 show-source = True
 exclude = .git,.venv,.tox,dist,doc,openstack,*egg
+
+[testenv:releasenotes]
+commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html