Merge "Fix usage of rest_client expected_success() in tests"
diff --git a/HACKING.rst b/HACKING.rst
index 4095c4b..ec7ff6a 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -16,7 +16,7 @@
 - [T107] Check that a service tag isn't in the module path
 - [T108] Check no hyphen at the end of rand_name() argument
 - [T109] Cannot use testtools.skip decorator; instead use
-         decorators.skip_because from tempest-lib
+         decorators.skip_because from tempest.lib
 - [T110] Check that service client names of GET should be consistent
 - [T111] Check that service client names of DELETE should be consistent
 - [T112] Check that tempest.lib should not import local tempest code
@@ -132,6 +132,7 @@
 
 Set-up is split in a series of steps (setup stages), which can be overwritten
 by test classes. Set-up stages are:
+
 - `skip_checks`
 - `setup_credentials`
 - `setup_clients`
@@ -140,6 +141,7 @@
 Tear-down is also split in a series of steps (teardown stages), which are
 stacked for execution only if the corresponding setup stage had been
 reached during the setup phase. Tear-down stages are:
+
 - `clear_credentials` (defined in the base test class)
 - `resource_cleanup`
 
@@ -157,33 +159,7 @@
 
 Negative Tests
 --------------
-Newly added negative tests should use the negative test framework. First step
-is to create an interface description in a python file under
-`tempest/api_schema/request/`. These descriptions consists of two important
-sections for the test (one of those is mandatory):
-
- - A resource (part of the URL of the request): Resources needed for a test
-   must be created in `setUpClass` and registered with `set_resource` e.g.:
-   `cls.set_resource("server", server['id'])`
-
- - A json schema: defines properties for a request.
-
-After that a test class must be added to automatically generate test scenarios
-out of the given interface description::
-
-    load_tests = test.NegativeAutoTest.load_tests
-
-    @test.SimpleNegativeAutoTest
-    class SampleTestNegativeTestJSON(<your base class>, test.NegativeAutoTest):
-        _service = 'compute'
-        _schema = <your schema file>
-
-The class decorator `SimpleNegativeAutoTest` will automatically generate test
-cases out of the given schema in the attribute `_schema`.
-
-All negative tests should be added into a separate negative test file.
-If such a file doesn't exist for the particular resource being tested a new
-test file should be added.
+TODO: Write the guideline related to negative tests.
 
 Test skips because of Known Bugs
 --------------------------------
@@ -333,9 +309,9 @@
         # The created server should be in the detailed list of all servers
         ...
 
-Tempest-lib includes a ``check-uuid`` tool that will test for the existence
+Tempest.lib includes a ``check-uuid`` tool that will test for the existence
 and uniqueness of idempotent_id metadata for every test. If you have
-tempest-lib installed you run the tool against Tempest by calling from the
+tempest installed you run the tool against Tempest by calling from the
 tempest repo::
 
     check-uuid
diff --git a/README.rst b/README.rst
index 7da83cd..650a1ed 100644
--- a/README.rst
+++ b/README.rst
@@ -58,7 +58,7 @@
 #. You first need to install Tempest. This is done with pip after you check out
    the Tempest repo::
 
-    $ git clone https://github.com/openstack/tempest/
+    $ git clone http://git.openstack.org/openstack/tempest
     $ pip install tempest/
 
    This can be done within a venv, but the assumption for this guide is that
@@ -71,14 +71,14 @@
    it's recommended that you copy or rename tempest.conf.sample to tempest.conf
    and make those changes to that file in /etc/tempest
 
-#. Setup a local working Tempest dir. This is done using the tempest init
+#. Setup a local working Tempest dir. This is done by using the tempest init
    command::
 
-    tempest init cloud-01
+    $ tempest init cloud-01
 
    works the same as::
 
-    mkdir cloud-01 && cd cloud-01 && tempest init
+    $ mkdir cloud-01 && cd cloud-01 && tempest init
 
    This will create a new directory for running a single Tempest configuration.
    If you'd like to run Tempest against multiple OpenStack deployments the idea
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index 245386b..9a7ce15 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -9,23 +9,30 @@
 config file which explains the purpose of each individual option. You can see
 the sample config file here: :ref:`tempest-sampleconf`
 
-Auth/Credentials
+Test Credentials
 ----------------
 
-Tempest currently has two different ways in configuration to provide credentials
-to use when running Tempest. One is a traditional set of configuration options
-in the tempest.conf file. These options are clearly labelled in the ``identity``
-section and let you specify a set of credentials for a regular user, a global
-admin user, and an alternate user, consisting of a username, password, and
-project name.
+Tempest allows for configuring a set of admin credentials in the ``auth``
+section, via the following parameters:
 
-The other method to provide credentials is using the accounts.yaml file. This
-file is used to specify an arbitrary number of users available to run tests
-with. You can specify the location of the file in the ``auth`` section in the
+ #. ``admin_username``
+ #. ``admin_password``
+ #. ``admin_project_name``
+ #. ``admin_domain_name``
+
+Admin credentials are not mandatory to run Tempest, but when provided they
+can be used to:
+
+- Run tests for admin APIs
+- Generate test credentials on the fly (see `Dynamic Credentials`_)
+
+Tempest allows for configuring pre-provisioned test credentials as well.
+This can be done using the accounts.yaml file (see
+`Pre-Provisioned Credentials`_). This file is used to specify an arbitrary
+number of users available to run tests with.
+You can specify the location of the file in the ``auth`` section in the
 tempest.conf file. To see the specific format used in the file please refer to
-the accounts.yaml.sample file included in Tempest.  Eventually the config
-options for providing credentials to Tempest will be deprecated and removed in
-favor of the accounts.yaml file.
+the accounts.yaml.sample file included in Tempest.
 
 Keystone Connection Info
 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -81,8 +88,9 @@
 configured to use dynamic credentials.
 
 
-Pre-Provisioned Credentials (aka accounts.yaml or accounts file)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Pre-Provisioned Credentials
+"""""""""""""""""""""""""""
+
 For a long time using dynamic credentials was the only method available if you
 wanted to enable parallel execution of Tempest tests. However, this was
 insufficient for certain use cases because of the admin credentials requirement
@@ -116,47 +124,7 @@
 to the tests using the credentials, and failure to do this will likely cause
 unexpected failures in some tests.
 
-
-Legacy Credentials (aka credentials config options)
-"""""""""""""""""""""""""""""""""""""""""""""""""""
-**Starting in the Liberty release this mechanism was deprecated; it will be
-removed in a future release.**
-
-When Tempest was refactored to allow for locking test accounts, the original
-non-project isolated case was converted to internally work similarly to the
-accounts.yaml file. This mechanism was then called the legacy test accounts
-provider. To use the legacy test accounts provider you can specify the sets of
-credentials in the configuration file as detailed above with following nine
-options in the ``identity`` section:
-
- #. ``username``
- #. ``password``
- #. ``project_name``
- #. ``admin_username``
- #. ``admin_password``
- #. ``admin_project_name``
- #. ``alt_username``
- #. ``alt_password``
- #. ``alt_project_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``
- #. Comment out ``test_accounts_file`` or keep it empty.
-
-It only makes sense to use this if parallel execution isn't needed, since
-Tempest won't be able to properly isolate tests using this. Additionally, using
-the traditional config options for credentials is not able to provide
-credentials to tests requiring specific roles on accounts. This is because the
-config options do not give sufficient flexibility to describe the roles assigned
-to a user for running the tests. There are additional limitations with regard to
-network configuration when using this credential provider mechanism - see the
-`Networking`_ section below.
+Pre-Provisioned Credentials are also know as accounts.yaml or accounts file.
 
 Compute
 -------
@@ -380,11 +348,14 @@
     service catalog should be in a standard format (which is going to be
     standardized at the keystone level).
     Tempest expects URLs in the Service catalog in the following format:
-     * ``http://example.com:1234/<version-info>``
+
+    * ``http://example.com:1234/<version-info>``
+
     Examples:
-     * Good - ``http://example.com:1234/v2.0``
-     * Wouldn’t work -  ``http://example.com:1234/xyz/v2.0/``
-       (adding prefix/suffix around version etc)
+
+    * Good - ``http://example.com:1234/v2.0``
+    * Wouldn’t work -  ``http://example.com:1234/xyz/v2.0/``
+      (adding prefix/suffix around version etc)
 
 Service Feature Configuration
 -----------------------------
diff --git a/doc/source/library.rst b/doc/source/library.rst
index 64bd2c2..a89512c 100644
--- a/doc/source/library.rst
+++ b/doc/source/library.rst
@@ -7,15 +7,14 @@
 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)
+goes into maintaining backwards compatibility with any change.
+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.
+Any code that lives in tempest/lib will be treated as a stable interface.
 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
diff --git a/doc/source/library/auth.rst b/doc/source/library/auth.rst
new file mode 100644
index 0000000..e1d92ed
--- /dev/null
+++ b/doc/source/library/auth.rst
@@ -0,0 +1,11 @@
+.. _auth:
+
+Authentication Framework Usage
+==============================
+
+---------------
+The auth module
+---------------
+
+.. automodule:: tempest.lib.auth
+   :members:
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index fc05b12..3568470 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -24,6 +24,7 @@
 
   Those should be defined under respective section of each service.
   For example::
+
       [compute]
       min_microversion = None
       max_microversion = latest
@@ -159,7 +160,8 @@
 
 
 Notes about Compute Microversion Tests
-"""""""""""""""""""""""""""""""""""
+""""""""""""""""""""""""""""""""""""""
+
 Some of the compute Microversion tests have been already implemented
 with the Microversion testing framework. So for further tests only
 step 4 is needed.
diff --git a/doc/source/plugin.rst b/doc/source/plugin.rst
index 2622c22..9640469 100644
--- a/doc/source/plugin.rst
+++ b/doc/source/plugin.rst
@@ -11,14 +11,26 @@
 =================
 
 Creating a plugin is fairly straightforward and doesn't require much additional
-effort on top of creating a test suite using tempest-lib. One thing to note with
+effort on top of creating a test suite using tempest.lib. One thing to note with
 doing this is that the interfaces exposed by tempest are not considered stable
 (with the exception of configuration variables which ever effort goes into
 ensuring backwards compatibility). You should not need to import anything from
-tempest itself except where explicitly noted. If there is an interface from
-tempest that you need to rely on in your plugin it likely needs to be migrated
-to tempest-lib. In that situation, file a bug, push a migration patch, etc. to
-expedite providing the interface in a reliable manner.
+tempest itself except where explicitly noted.
+
+Stable Tempest APIs plugins may use
+-----------------------------------
+
+As noted above, several tempest APIs are acceptable to use from plugins, while
+others are not. A list of stable APIs available to plugins is provided below:
+
+* tempest.lib.*
+* tempest.config
+* tempest.test_discover.plugins
+
+If there is an interface from tempest that you need to rely on in your plugin
+which is not listed above, it likely needs to be migrated to tempest.lib. In
+that situation, file a bug, push a migration patch, etc. to expedite providing
+the interface in a reliable manner.
 
 Plugin Cookiecutter
 -------------------
@@ -102,11 +114,6 @@
 Then you need to ensure you locally define all of the methods in the abstract
 class, you can refer to the api doc below for a reference of what that entails.
 
-Also, note eventually this abstract class will likely live in tempest-lib, when
-that migration occurs a deprecation shim will be added to tempest so as to not
-break any existing plugins. But, when that occurs migrating to using tempest-lib
-as the source for the abstract class will be prudent.
-
 Abstract Plugin Class
 ---------------------
 
diff --git a/etc/javelin-resources.yaml.sample b/etc/javelin-resources.yaml.sample
index fb270a4..1565686 100644
--- a/etc/javelin-resources.yaml.sample
+++ b/etc/javelin-resources.yaml.sample
@@ -61,5 +61,3 @@
     owner: javelin
     file: /etc/hosts
     swift_role: Member
-
-telemetry: true
\ No newline at end of file
diff --git a/releasenotes/notes/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml b/releasenotes/notes/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml
new file mode 100644
index 0000000..9baf035
--- /dev/null
+++ b/releasenotes/notes/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml
@@ -0,0 +1,12 @@
+---
+prelude: >
+    This release is marking the end of Kilo release support in Tempest
+other:
+    - OpenStack Releases Supported after this release are **Liberty**
+      and **Mitaka**
+
+      The release under current development as of this tag is Newton,
+      meaning that every Tempest commit is also tested against master during
+      the Newton cycle. However, this does not necessarily mean that using
+      Tempest as of this tag will work against a Newton (or future releases)
+      cloud.
diff --git a/releasenotes/notes/add-scope-to-auth-b5a82493ea89f41e.yaml b/releasenotes/notes/add-scope-to-auth-b5a82493ea89f41e.yaml
new file mode 100644
index 0000000..297279f
--- /dev/null
+++ b/releasenotes/notes/add-scope-to-auth-b5a82493ea89f41e.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - Tempest library auth interface now supports scope. Scope allows to control
+    the scope of tokens requested via the identity API. Identity V2 supports
+    unscoped and project scoped tokens, but only the latter are implemented.
+    Identity V3 supports unscoped, project and domain scoped token, all three
+    are available.
\ No newline at end of file
diff --git a/releasenotes/notes/remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml b/releasenotes/notes/remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml
new file mode 100644
index 0000000..89b3f41
--- /dev/null
+++ b/releasenotes/notes/remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml
@@ -0,0 +1,5 @@
+---
+upgrade:
+  - The deprecated legacy credential provider has been removed. The only way to
+    configure credentials in tempest now is to use the dynamic or preprovisioned
+    credential providers
diff --git a/releasenotes/notes/support-chunked-encoding-d71f53225f68edf3.yaml b/releasenotes/notes/support-chunked-encoding-d71f53225f68edf3.yaml
new file mode 100644
index 0000000..eb45523
--- /dev/null
+++ b/releasenotes/notes/support-chunked-encoding-d71f53225f68edf3.yaml
@@ -0,0 +1,9 @@
+---
+features:
+  - The RestClient (in tempest.lib.common.rest_client) now supports POSTing
+    and PUTing data with chunked transfer encoding. Just pass an `iterable`
+    object as the `body` argument and set the `chunked` argument to `True`.
+  - A new generator called `chunkify` is added in
+    tempest.lib.common.utils.data_utils that yields fixed-size chunks (slices)
+    from a Python sequence.
+
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index b617b22..2c22408 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -5,6 +5,7 @@
  .. toctree::
     :maxdepth: 1
 
+    v12.0.0
     v11.0.0
     v10.0.0
     unreleased
diff --git a/releasenotes/source/v12.0.0.rst b/releasenotes/source/v12.0.0.rst
new file mode 100644
index 0000000..0bc8343
--- /dev/null
+++ b/releasenotes/source/v12.0.0.rst
@@ -0,0 +1,6 @@
+=====================
+v12.0.0 Release Notes
+=====================
+
+.. release-notes:: 12.0.0 Release Notes
+   :version: 12.0.0
diff --git a/requirements.txt b/requirements.txt
index 79ae42e..d567082 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,10 +3,9 @@
 # process, which may cause wedges in the gate later.
 pbr>=1.6 # Apache-2.0
 cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
-anyjson>=0.3.3 # BSD
 jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
 testtools>=1.4.0 # MIT
-paramiko>=1.16.0 # LGPL
+paramiko>=2.0 # LGPL
 netaddr!=0.7.16,>=0.7.12 # BSD
 testrepository>=0.0.18 # Apache-2.0/BSD
 pyOpenSSL>=0.14 # Apache-2.0
@@ -17,11 +16,10 @@
 oslo.serialization>=1.10.0 # Apache-2.0
 oslo.utils>=3.5.0 # Apache-2.0
 six>=1.9.0 # MIT
-iso8601>=0.1.9 # MIT
 fixtures<2.0,>=1.3.1 # Apache-2.0/BSD
 testscenarios>=0.4 # Apache-2.0/BSD
 PyYAML>=3.1.0 # MIT
-stevedore>=1.9.0 # Apache-2.0
+stevedore>=1.10.0 # Apache-2.0
 PrettyTable<0.8,>=0.7 # BSD
 os-testr>=0.4.1 # Apache-2.0
-urllib3>=1.8.3 # MIT
+urllib3>=1.15.1 # MIT
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index f6ea3a4..a9e9644 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -49,7 +49,7 @@
     @test.idempotent_id('c6ddbadb-c94e-4500-b12f-8ffc43843ff8')
     def test_list_hosts_with_nonexistent_zone(self):
         # If send the request with a nonexistent zone, the request will be
-        # successful and no hosts will be retured
+        # successful and no hosts will be returned
         hosts = self.client.list_hosts(zone='xxx')['hosts']
         self.assertEqual(0, len(hosts))
 
diff --git a/tempest/api/compute/admin/test_migrations.py b/tempest/api/compute/admin/test_migrations.py
index f81d665..6113c04 100644
--- a/tempest/api/compute/admin/test_migrations.py
+++ b/tempest/api/compute/admin/test_migrations.py
@@ -15,8 +15,10 @@
 import testtools
 
 from tempest.api.compute import base
+from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import exceptions
 from tempest import test
 
 CONF = config.CONF
@@ -28,6 +30,7 @@
     def setup_clients(cls):
         super(MigrationsAdminTest, cls).setup_clients()
         cls.client = cls.os_adm.migrations_client
+        cls.flavors_admin_client = cls.os_adm.flavors_client
 
     @test.idempotent_id('75c0b83d-72a0-4cf8-a153-631e83e7d53f')
     def test_list_migrations(self):
@@ -53,3 +56,50 @@
 
         instance_uuids = [x['instance_uuid'] for x in body]
         self.assertIn(server_id, instance_uuids)
+
+    def _flavor_clean_up(self, flavor_id):
+        try:
+            self.flavors_admin_client.delete_flavor(flavor_id)
+            self.flavors_admin_client.wait_for_resource_deletion(flavor_id)
+        except exceptions.NotFound:
+            pass
+
+    @test.idempotent_id('33f1fec3-ba18-4470-8e4e-1d888e7c3593')
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
+    def test_resize_server_revert_deleted_flavor(self):
+        # Tests that we can revert the resize on an instance whose original
+        # flavor has been deleted.
+
+        # First we have to create a flavor that we can delete so make a copy
+        # of the normal flavor from which we'd create a server.
+        flavor = self.flavors_admin_client.show_flavor(
+            self.flavor_ref)['flavor']
+        flavor = self.flavors_admin_client.create_flavor(
+            name=data_utils.rand_name('test_resize_flavor_'),
+            ram=flavor['ram'],
+            disk=flavor['disk'],
+            vcpus=flavor['vcpus']
+        )['flavor']
+        self.addCleanup(self._flavor_clean_up, flavor['id'])
+
+        # Now boot a server with the copied flavor.
+        server = self.create_test_server(
+            wait_until='ACTIVE', flavor=flavor['id'])
+
+        # Delete the flavor we used to boot the instance.
+        self._flavor_clean_up(flavor['id'])
+
+        # Now resize the server and wait for it to go into verify state.
+        self.servers_client.resize_server(server['id'], self.flavor_ref_alt)
+        waiters.wait_for_server_status(self.servers_client, server['id'],
+                                       'VERIFY_RESIZE')
+
+        # Now revert the resize, it should be OK even though the original
+        # flavor used to boot the server was deleted.
+        self.servers_client.revert_resize_server(server['id'])
+        waiters.wait_for_server_status(self.servers_client, server['id'],
+                                       'ACTIVE')
+
+        server = self.servers_client.show_server(server['id'])['server']
+        self.assertEqual(flavor['id'], server['flavor']['id'])
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 2907e26..b1f0755 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -185,7 +185,7 @@
         # increment all of the values for updating the default quota class
         for quota, default in six.iteritems(body):
             # NOTE(sdague): we need to increment a lot, otherwise
-            # there is a real chance that we go from -1 (unlimitted)
+            # there is a real chance that we go from -1 (unlimited)
             # to a very small number which causes issues.
             body[quota] = default + 100
         LOG.debug("update limits for the default quota class set")
diff --git a/tempest/api/compute/admin/test_servers_on_multinodes.py b/tempest/api/compute/admin/test_servers_on_multinodes.py
index 814a876..1bbde98 100644
--- a/tempest/api/compute/admin/test_servers_on_multinodes.py
+++ b/tempest/api/compute/admin/test_servers_on_multinodes.py
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 from tempest.api.compute import base
 from tempest import config
 from tempest import test
@@ -34,6 +36,9 @@
             server_id)['server']['OS-EXT-SRV-ATTR:host']
 
     @test.idempotent_id('26a9d5df-6890-45f2-abc4-a659290cb130')
+    @testtools.skipUnless(
+        test.is_scheduler_filter_enabled("SameHostFilter"),
+        'SameHostFilter is not available.')
     def test_create_servers_on_same_host(self):
         server01 = self.create_test_server(wait_until='ACTIVE')['id']
 
@@ -45,6 +50,9 @@
         self.assertEqual(host01, host02)
 
     @test.idempotent_id('cc7ca884-6e3e-42a3-a92f-c522fcf25e8e')
+    @testtools.skipUnless(
+        test.is_scheduler_filter_enabled("DifferentHostFilter"),
+        'DifferentHostFilter is not available.')
     def test_create_servers_on_different_hosts(self):
         server01 = self.create_test_server(wait_until='ACTIVE')['id']
 
@@ -56,6 +64,9 @@
         self.assertNotEqual(host01, host02)
 
     @test.idempotent_id('7869cc84-d661-4e14-9f00-c18cdc89cf57')
+    @testtools.skipUnless(
+        test.is_scheduler_filter_enabled("DifferentHostFilter"),
+        'DifferentHostFilter is not available.')
     def test_create_servers_on_different_hosts_with_list_of_servers(self):
         server01 = self.create_test_server(wait_until='ACTIVE')['id']
 
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 4fb4e9a..fdf55e5 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -16,6 +16,7 @@
 import time
 
 from tempest.api.compute import base
+from tempest.common.utils import net_utils
 from tempest import config
 from tempest import exceptions
 from tempest.lib import exceptions as lib_exc
@@ -44,6 +45,8 @@
     def setup_clients(cls):
         super(AttachInterfacesTestJSON, cls).setup_clients()
         cls.client = cls.os.interfaces_client
+        cls.networks_client = cls.os.networks_client
+        cls.subnets_client = cls.os.subnets_client
         cls.ports_client = cls.os.ports_client
 
     def wait_for_interface_status(self, server, port_id, status):
@@ -120,6 +123,25 @@
         self._check_interface(iface, port_id=port_id)
         return iface
 
+    def _test_create_interface_by_fixed_ips(self, server, ifs):
+        network_id = ifs[0]['net_id']
+        subnet_id = ifs[0]['fixed_ips'][0]['subnet_id']
+        ip_list = net_utils.get_unused_ip_addresses(self.ports_client,
+                                                    self.subnets_client,
+                                                    network_id,
+                                                    subnet_id,
+                                                    1)
+
+        fixed_ips = [{'ip_address': ip_list[0]}]
+        iface = self.client.create_interface(
+            server['id'], net_id=network_id,
+            fixed_ips=fixed_ips)['interfaceAttachment']
+        self.addCleanup(self.ports_client.delete_port, iface['port_id'])
+        iface = self.wait_for_interface_status(
+            server['id'], iface['port_id'], 'ACTIVE')
+        self._check_interface(iface, fixed_ip=ip_list[0])
+        return iface
+
     def _test_show_interface(self, server, ifs):
         iface = ifs[0]
         _iface = self.client.show_interface(
@@ -182,6 +204,9 @@
         iface = self._test_create_interface_by_port_id(server, ifs)
         ifs.append(iface)
 
+        iface = self._test_create_interface_by_fixed_ips(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_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 87f3c86..07423ff 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -119,7 +119,9 @@
             self.get_server_ip(self.server),
             self.ssh_user,
             self.password,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=self.server,
+            servers_client=self.client)
         self.assertEqual(flavor['vcpus'], linux_client.get_number_of_vcpus())
 
     @test.idempotent_id('ac1ad47f-984b-4441-9274-c9079b7a0666')
@@ -131,7 +133,9 @@
             self.get_server_ip(self.server),
             self.ssh_user,
             self.password,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=self.server,
+            servers_client=self.client)
         self.assertTrue(linux_client.hostname_equals_servername(self.name))
 
     @test.idempotent_id('ed20d3fb-9d1f-4329-b160-543fbd5d9811')
@@ -200,10 +204,6 @@
     @test.idempotent_id('1678d144-ed74-43f8-8e57-ab10dbf9b3c2')
     @testtools.skipUnless(CONF.service_available.neutron,
                           'Neutron service must be available.')
-    # The below skipUnless should be removed once Kilo-eol happens.
-    @testtools.skipUnless(CONF.compute_feature_enabled.
-                          allow_duplicate_networks,
-                          'Duplicate networks must be allowed')
     def test_verify_duplicate_network_nics(self):
         # Verify that server creation does not fail when more than one nic
         # is created on the same network.
@@ -322,7 +322,9 @@
             self.get_server_ip(server_no_eph_disk),
             self.ssh_user,
             admin_pass,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=server_no_eph_disk,
+            servers_client=self.client)
         partition_num = len(linux_client.get_partitions().split('\n'))
 
         # Explicit server deletion necessary for Juno compatibility
@@ -340,7 +342,9 @@
             self.get_server_ip(server_with_eph_disk),
             self.ssh_user,
             admin_pass,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=server_with_eph_disk,
+            servers_client=self.client)
         partition_num_emph = len(linux_client.get_partitions().split('\n'))
         self.assertEqual(partition_num + 1, partition_num_emph)
 
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index 6796bb5..079465d 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -16,6 +16,7 @@
 import testtools
 
 from tempest.api.compute import base
+from tempest.common import compute
 from tempest.common import waiters
 from tempest import config
 from tempest import test
@@ -84,16 +85,8 @@
     def test_delete_server_while_in_shelved_state(self):
         # Delete a server while it's VM state is Shelved
         server = self.create_test_server(wait_until='ACTIVE')
-        self.client.shelve_server(server['id'])
+        compute.shelve_server(self.client, server['id'])
 
-        offload_time = CONF.compute.shelved_offload_time
-        if offload_time >= 0:
-            waiters.wait_for_server_status(self.client, server['id'],
-                                           'SHELVED_OFFLOADED',
-                                           extra_timeout=offload_time)
-        else:
-            waiters.wait_for_server_status(self.client, server['id'],
-                                           'SHELVED')
         self.client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.client, server['id'])
 
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 5b4417a..66aec84 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -19,6 +19,7 @@
 import testtools
 
 from tempest.api.compute import base
+from tempest.common import compute
 from tempest.common.utils import data_utils
 from tempest.common.utils.linux import remote_client
 from tempest.common import waiters
@@ -90,7 +91,9 @@
             linux_client = remote_client.RemoteClient(
                 self.get_server_ip(server),
                 self.ssh_user,
-                new_password)
+                new_password,
+                server=server,
+                servers_client=self.client)
             linux_client.validate_authentication()
 
     def _test_reboot_server(self, reboot_type):
@@ -101,7 +104,9 @@
                 self.get_server_ip(server),
                 self.ssh_user,
                 self.password,
-                self.validation_resources['keypair']['private_key'])
+                self.validation_resources['keypair']['private_key'],
+                server=server,
+                servers_client=self.client)
             boot_time = linux_client.get_boot_time()
 
         self.client.reboot_server(self.server_id, type=reboot_type)
@@ -113,7 +118,9 @@
                 self.get_server_ip(server),
                 self.ssh_user,
                 self.password,
-                self.validation_resources['keypair']['private_key'])
+                self.validation_resources['keypair']['private_key'],
+                server=server,
+                servers_client=self.client)
             new_boot_time = linux_client.get_boot_time()
             self.assertTrue(new_boot_time > boot_time,
                             '%s > %s' % (new_boot_time, boot_time))
@@ -182,7 +189,9 @@
                 self.get_server_ip(rebuilt_server),
                 self.ssh_user,
                 password,
-                self.validation_resources['keypair']['private_key'])
+                self.validation_resources['keypair']['private_key'],
+                server=rebuilt_server,
+                servers_client=self.client)
             linux_client.validate_authentication()
 
     @test.idempotent_id('30449a88-5aff-4f9b-9866-6ee9b17f906d')
@@ -217,6 +226,35 @@
 
         self.client.start_server(self.server_id)
 
+    @test.idempotent_id('b68bd8d6-855d-4212-b59b-2e704044dace')
+    @test.services('volume')
+    def test_rebuild_server_with_volume_attached(self):
+        # create a new volume and attach it to the server
+        volume = self.volumes_client.create_volume(
+            size=CONF.volume.volume_size)
+        volume = volume['volume']
+        self.addCleanup(self.volumes_client.delete_volume, volume['id'])
+        waiters.wait_for_volume_status(self.volumes_client, volume['id'],
+                                       'available')
+
+        self.client.attach_volume(self.server_id, volumeId=volume['id'])
+        self.addCleanup(waiters.wait_for_volume_status, self.volumes_client,
+                        volume['id'], 'available')
+        self.addCleanup(self.client.detach_volume,
+                        self.server_id, volume['id'])
+        waiters.wait_for_volume_status(self.volumes_client, volume['id'],
+                                       'in-use')
+
+        # run general rebuild test
+        self.test_rebuild_server()
+
+        # make sure the volume is attached to the instance after rebuild
+        vol_after_rebuild = self.volumes_client.show_volume(volume['id'])
+        vol_after_rebuild = vol_after_rebuild['volume']
+        self.assertEqual('in-use', vol_after_rebuild['status'])
+        self.assertEqual(self.server_id,
+                         vol_after_rebuild['attachments'][0]['server_id'])
+
     def _test_resize_server_confirm(self, stop=False):
         # The server's RAM and disk space should be modified to that of
         # the provided flavor
@@ -303,7 +341,8 @@
 
         image1_id = data_utils.parse_image_id(resp['location'])
         self.addCleanup(_clean_oldest_backup, image1_id)
-        self.os.image_client.wait_for_image_status(image1_id, 'active')
+        waiters.wait_for_image_status(self.os.image_client,
+                                      image1_id, 'active')
 
         backup2 = data_utils.rand_name('backup-2')
         waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
@@ -313,7 +352,8 @@
                                          name=backup2).response
         image2_id = data_utils.parse_image_id(resp['location'])
         self.addCleanup(self.os.image_client.delete_image, image2_id)
-        self.os.image_client.wait_for_image_status(image2_id, 'active')
+        waiters.wait_for_image_status(self.os.image_client,
+                                      image2_id, 'active')
 
         # verify they have been created
         properties = {
@@ -440,20 +480,8 @@
     @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
                           'Shelve is not available.')
     def test_shelve_unshelve_server(self):
-        self.client.shelve_server(self.server_id)
-
-        offload_time = CONF.compute.shelved_offload_time
-        if offload_time >= 0:
-            waiters.wait_for_server_status(self.client, self.server_id,
-                                           'SHELVED_OFFLOADED',
-                                           extra_timeout=offload_time)
-        else:
-            waiters.wait_for_server_status(self.client, self.server_id,
-                                           'SHELVED')
-
-            self.client.shelve_offload_server(self.server_id)
-            waiters.wait_for_server_status(self.client, self.server_id,
-                                           'SHELVED_OFFLOADED')
+        compute.shelve_server(self.client, self.server_id,
+                              force_shelve_offload=True)
 
         server = self.client.show_server(self.server_id)['server']
         image_name = server['name'] + '-shelved'
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index 74d34a2..baa4f9a 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -66,7 +66,9 @@
             linux_client = remote_client.RemoteClient(
                 self.get_server_ip(server),
                 self.ssh_user, password,
-                self.validation_resources['keypair']['private_key'])
+                self.validation_resources['keypair']['private_key'],
+                server=server,
+                servers_client=self.client)
             self.assertEqual(file_contents,
                              linux_client.exec_command(
                                  'sudo cat %s' % file_path))
@@ -130,7 +132,9 @@
             linux_client = remote_client.RemoteClient(
                 self.get_server_ip(server),
                 self.ssh_user, password,
-                self.validation_resources['keypair']['private_key'])
+                self.validation_resources['keypair']['private_key'],
+                server=server,
+                servers_client=self.client)
             for i in person:
                 self.assertEqual(base64.b64decode(i['contents']),
                                  linux_client.exec_command(
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 8f0e430..10ea31d 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -18,6 +18,7 @@
 import testtools
 
 from tempest.api.compute import base
+from tempest.common import compute
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
@@ -453,18 +454,7 @@
     @test.attr(type=['negative'])
     def test_shelve_shelved_server(self):
         # shelve a shelved server.
-        self.client.shelve_server(self.server_id)
-
-        offload_time = CONF.compute.shelved_offload_time
-        if offload_time >= 0:
-            waiters.wait_for_server_status(self.client,
-                                           self.server_id,
-                                           'SHELVED_OFFLOADED',
-                                           extra_timeout=offload_time)
-        else:
-            waiters.wait_for_server_status(self.client,
-                                           self.server_id,
-                                           'SHELVED')
+        compute.shelve_server(self.client, self.server_id)
 
         server = self.client.show_server(self.server_id)['server']
         image_name = server['name'] + '-shelved'
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index e9c8e30..fa3fdfe 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -16,6 +16,7 @@
 import testtools
 
 from tempest.api.compute import base
+from tempest.common import compute
 from tempest.common.utils.linux import remote_client
 from tempest.common import waiters
 from tempest import config
@@ -25,6 +26,7 @@
 
 
 class AttachVolumeTestJSON(base.BaseV2ComputeTest):
+    max_microversion = '2.19'
 
     def __init__(self, *args, **kwargs):
         super(AttachVolumeTestJSON, self).__init__(*args, **kwargs)
@@ -62,7 +64,7 @@
             self.volumes_client.wait_for_resource_deletion(self.volume['id'])
             self.volume = None
 
-    def _create_and_attach(self):
+    def _create_and_attach(self, shelve_server=False):
         # Start a server and wait for it to become ready
         self.admin_pass = self.image_ssh_password
         self.server = self.create_test_server(
@@ -81,6 +83,22 @@
         waiters.wait_for_volume_status(self.volumes_client,
                                        self.volume['id'], 'available')
 
+        if shelve_server:
+            # NOTE(andreaf) If we are going to shelve a server, we should
+            # check first whether the server is ssh-able. Otherwise we won't
+            # be able to distinguish failures introduced by shelve from
+            # pre-existing ones. Also it's good to wait for cloud-init to be
+            # done and sshd server to be running before shelving to avoid
+            # breaking the VM
+            linux_client = remote_client.RemoteClient(
+                self.get_server_ip(self.server),
+                self.image_ssh_user,
+                self.admin_pass,
+                self.validation_resources['keypair']['private_key'])
+            linux_client.validate_authentication()
+            # If validation went ok, shelve the server
+            compute.shelve_server(self.servers_client, self.server['id'])
+
         # Attach the volume to the server
         self.attachment = self.servers_client.attach_volume(
             self.server['id'],
@@ -111,7 +129,9 @@
             self.get_server_ip(self.server),
             self.image_ssh_user,
             self.admin_pass,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=self.server,
+            servers_client=self.servers_client)
 
         partitions = linux_client.get_partitions()
         self.assertIn(self.device, partitions)
@@ -130,7 +150,9 @@
             self.get_server_ip(self.server),
             self.image_ssh_user,
             self.admin_pass,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=self.server,
+            servers_client=self.servers_client)
 
         partitions = linux_client.get_partitions()
         self.assertNotIn(self.device, partitions)
@@ -152,3 +174,68 @@
         self.assertEqual(self.server['id'], body['serverId'])
         self.assertEqual(self.volume['id'], body['volumeId'])
         self.assertEqual(self.attachment['id'], body['id'])
+
+
+class AttachVolumeShelveTestJSON(AttachVolumeTestJSON):
+    """Testing volume with shelved instance.
+
+    This test checks the attaching and detaching volumes from
+    a shelved or shelved ofload instance.
+    """
+
+    min_microversion = '2.20'
+    max_microversion = 'latest'
+
+    def _unshelve_server_and_check_volumes(self, number_of_partition):
+        # Unshelve the instance and check that there are expected volumes
+        self.servers_client.unshelve_server(self.server['id'])
+        waiters.wait_for_server_status(self.servers_client,
+                                       self.server['id'],
+                                       'ACTIVE')
+        linux_client = remote_client.RemoteClient(
+            self.get_server_ip(self.server['id']),
+            self.image_ssh_user,
+            self.admin_pass,
+            self.validation_resources['keypair']['private_key'],
+            server=self.server,
+            servers_client=self.servers_client)
+
+        command = 'grep vd /proc/partitions | wc -l'
+        nb_partitions = linux_client.exec_command(command).strip()
+        self.assertEqual(number_of_partition, nb_partitions)
+
+    @test.idempotent_id('13a940b6-3474-4c3c-b03f-29b89112bfee')
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
+    @testtools.skipUnless(CONF.validation.run_validation,
+                          'SSH required for this test')
+    def test_attach_volume_shelved_or_offload_server(self):
+        self._create_and_attach(shelve_server=True)
+
+        # Unshelve the instance and check that there are two volumes
+        self._unshelve_server_and_check_volumes('2')
+
+        # Get Volume attachment of the server
+        volume_attachment = self.servers_client.show_volume_attachment(
+            self.server['id'],
+            self.attachment['id'])['volumeAttachment']
+        self.assertEqual(self.server['id'], volume_attachment['serverId'])
+        self.assertEqual(self.attachment['id'], volume_attachment['id'])
+        # Check the mountpoint is not None after unshelve server even in
+        # case of shelved_offloaded.
+        self.assertIsNotNone(volume_attachment['device'])
+
+    @test.idempotent_id('b54e86dd-a070-49c4-9c07-59ae6dae15aa')
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
+    @testtools.skipUnless(CONF.validation.run_validation,
+                          'SSH required for this test')
+    def test_detach_volume_shelved_or_offload_server(self):
+        self._create_and_attach(shelve_server=True)
+
+        # Detach the volume
+        self._detach(self.server['id'], self.volume['id'])
+        self.attachment = None
+
+        # Unshelve the instance and check that there is only one volume
+        self._unshelve_server_and_check_volumes('1')
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index 990e429..f709c91 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -27,7 +27,7 @@
     # ensure that the backing file for the volume group that Nova uses
     # has space for at least 3 1G volumes!
     # If you are running a Devstack environment, ensure that the
-    # VOLUME_BACKING_FILE_SIZE is atleast 4G in your localrc
+    # VOLUME_BACKING_FILE_SIZE is at least 4G in your localrc
 
     @classmethod
     def skip_checks(cls):
diff --git a/tempest/api/database/flavors/test_flavors.py b/tempest/api/database/flavors/test_flavors.py
index bdb4383..bb7a0a4 100644
--- a/tempest/api/database/flavors/test_flavors.py
+++ b/tempest/api/database/flavors/test_flavors.py
@@ -27,6 +27,7 @@
 
     @test.attr(type='smoke')
     @test.idempotent_id('c94b825e-0132-4686-8049-8a4a2bc09525')
+    @decorators.skip_because(bug='1567134')
     def test_get_db_flavor(self):
         # The expected flavor details should be returned
         flavor = (self.client.show_db_flavor(self.db_flavor_ref)
@@ -38,6 +39,7 @@
 
     @test.attr(type='smoke')
     @test.idempotent_id('685025d6-0cec-4673-8a8d-995cb8e0d3bb')
+    @decorators.skip_because(bug='1567134')
     def test_list_db_flavors(self):
         flavor = (self.client.show_db_flavor(self.db_flavor_ref)
                   ['flavor'])
diff --git a/tempest/api/identity/admin/v2/test_users_negative.py b/tempest/api/identity/admin/v2/test_users_negative.py
index 46ecba1..5fda4c14 100644
--- a/tempest/api/identity/admin/v2/test_users_negative.py
+++ b/tempest/api/identity/admin/v2/test_users_negative.py
@@ -83,13 +83,14 @@
         token = self.client.auth_provider.get_token()
         # Delete the token from database
         self.client.delete_token(token)
+
+        # Unset the token to allow further tests to generate a new token
+        self.addCleanup(self.client.auth_provider.clear_auth)
+
         self.assertRaises(lib_exc.Unauthorized, self.users_client.create_user,
                           self.alt_user, self.alt_password,
                           self.data.tenant['id'], self.alt_email)
 
-        # Unset the token to allow further tests to generate a new token
-        self.client.auth_provider.clear_auth()
-
     @test.attr(type=['negative'])
     @test.idempotent_id('23a2f3da-4a1a-41da-abdd-632328a861ad')
     def test_create_user_with_enabled_non_bool(self):
@@ -119,11 +120,12 @@
         token = self.client.auth_provider.get_token()
         # Delete the token from database
         self.client.delete_token(token)
-        self.assertRaises(lib_exc.Unauthorized, self.users_client.update_user,
-                          self.alt_user)
 
         # Unset the token to allow further tests to generate a new token
-        self.client.auth_provider.clear_auth()
+        self.addCleanup(self.client.auth_provider.clear_auth)
+
+        self.assertRaises(lib_exc.Unauthorized, self.users_client.update_user,
+                          self.alt_user)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('424868d5-18a7-43e1-8903-a64f95ee3aac')
@@ -159,11 +161,12 @@
         token = self.client.auth_provider.get_token()
         # Delete the token from database
         self.client.delete_token(token)
-        self.assertRaises(lib_exc.Unauthorized, self.users_client.delete_user,
-                          self.alt_user)
 
         # Unset the token to allow further tests to generate a new token
-        self.client.auth_provider.clear_auth()
+        self.addCleanup(self.client.auth_provider.clear_auth)
+
+        self.assertRaises(lib_exc.Unauthorized, self.users_client.delete_user,
+                          self.alt_user)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('593a4981-f6d4-460a-99a1-57a78bf20829')
@@ -229,8 +232,11 @@
         # Request to get list of users without a valid token should fail
         token = self.client.auth_provider.get_token()
         self.client.delete_token(token)
+
+        # Unset the token to allow further tests to generate a new token
+        self.addCleanup(self.client.auth_provider.clear_auth)
+
         self.assertRaises(lib_exc.Unauthorized, self.users_client.list_users)
-        self.client.auth_provider.clear_auth()
 
     @test.attr(type=['negative'])
     @test.idempotent_id('f5d39046-fc5f-425c-b29e-bac2632da28e')
diff --git a/tempest/api/identity/v2/test_users.py b/tempest/api/identity/v2/test_users.py
index 62ddead..79f2576 100644
--- a/tempest/api/identity/v2/test_users.py
+++ b/tempest/api/identity/v2/test_users.py
@@ -13,13 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import copy
 import time
 
 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
 
 
@@ -35,23 +33,26 @@
 
     @test.idempotent_id('165859c9-277f-4124-9479-a7d1627b0ca7')
     def test_user_update_own_password(self):
-        self.new_creds = copy.copy(self.creds.credentials)
-        self.new_creds.password = data_utils.rand_password()
-        # we need new non-admin Identity Client with new credentials, since
-        # current non_admin_client token will be revoked after updating
-        # password
-        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
 
+        def _restore_password(client, user_id, old_pass, new_pass):
+            # Reset auth to get a new token with the new password
+            client.auth_provider.clear_auth()
+            client.auth_provider.credentials.password = new_pass
+            client.update_user_own_password(user_id, password=old_pass,
+                                            original_password=new_pass)
+            # Reset auth again to verify the password restore does work.
+            # Clear auth restores the original credentials and deletes
+            # cached auth data
+            client.auth_provider.clear_auth()
+            client.auth_provider.set_auth()
+
+        old_pass = self.creds.credentials.password
+        new_pass = data_utils.rand_password()
+        user_id = self.creds.credentials.user_id
         # to change password back. important for allow_tenant_isolation = false
-        self.addCleanup(
-            self.non_admin_users_client_for_cleanup.update_user_own_password,
-            user_id, original_password=new_pass, password=old_pass)
+        self.addCleanup(_restore_password, self.non_admin_users_client,
+                        user_id, old_pass=old_pass, new_pass=new_pass)
+
         # user updates own password
         self.non_admin_users_client.update_user_own_password(
             user_id, password=new_pass, original_password=old_pass)
diff --git a/tempest/api/identity/v3/test_projects.py b/tempest/api/identity/v3/test_projects.py
index 995b77e..1574ab7 100644
--- a/tempest/api/identity/v3/test_projects.py
+++ b/tempest/api/identity/v3/test_projects.py
@@ -33,7 +33,7 @@
         # 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
+            # '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,
diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py
index 593bf2a..d5bed96 100644
--- a/tempest/api/identity/v3/test_tokens.py
+++ b/tempest/api/identity/v3/test_tokens.py
@@ -30,7 +30,7 @@
         password = creds.password
         user_domain_id = creds.user_domain_id
 
-        # 'user_domain_id' needs to be specified otherwise tempest_lib assumes
+        # '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,
diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py
index 60fbe12..76b46c0 100644
--- a/tempest/api/identity/v3/test_users.py
+++ b/tempest/api/identity/v3/test_users.py
@@ -13,13 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import copy
 import time
 
 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
 
 
@@ -35,24 +33,25 @@
 
     @test.idempotent_id('ad71bd23-12ad-426b-bb8b-195d2b635f27')
     def test_user_update_own_password(self):
-        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_users_client token will be revoked after updating
-        # password
-        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
+
+        def _restore_password(client, user_id, old_pass, new_pass):
+            # Reset auth to get a new token with the new password
+            client.auth_provider.clear_auth()
+            client.auth_provider.credentials.password = new_pass
+            client.update_user_password(user_id, password=old_pass,
+                                        original_password=new_pass)
+            # Reset auth again to verify the password restore does work.
+            # Clear auth restores the original credentials and deletes
+            # cached auth data
+            client.auth_provider.clear_auth()
+            client.auth_provider.set_auth()
+
         old_pass = self.creds.credentials.password
-        new_pass = self.new_creds.password
+        new_pass = data_utils.rand_password()
+        user_id = self.creds.credentials.user_id
         # to change password back. important for allow_tenant_isolation = false
-        self.addCleanup(
-            self.non_admin_users_client_for_cleanup.update_user_password,
-            user_id,
-            password=old_pass,
-            original_password=new_pass)
+        self.addCleanup(_restore_password, self.non_admin_users_client,
+                        user_id, old_pass=old_pass, new_pass=new_pass)
 
         # user updates own password
         self.non_admin_users_client.update_user_password(
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index 1a84d06..6d5559d 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -17,6 +17,7 @@
 
 from tempest.api.image import base
 from tempest.common.utils import data_utils
+from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
 from tempest import test
@@ -32,7 +33,7 @@
 
     if container_format in a_formats and container_format != disk_format:
         msg = ("The container format and the disk format don't match. "
-               "Contaiter format: %(container)s, Disk format: %(disk)s." %
+               "Container format: %(container)s, Disk format: %(disk)s." %
                {'container': container_format, 'disk': disk_format})
         raise exceptions.InvalidConfiguration(message=msg)
 
@@ -95,7 +96,7 @@
         image_id = body.get('id')
         self.assertEqual('New Http Image', body.get('name'))
         self.assertFalse(body.get('is_public'))
-        self.client.wait_for_image_status(image_id, 'active')
+        waiters.wait_for_image_status(self.client, image_id, 'active')
         self.client.show_image(image_id)
 
     @test.idempotent_id('05b19d55-140c-40d0-b36b-fafd774d421b')
@@ -305,7 +306,7 @@
     @test.idempotent_id('01752c1c-0275-4de3-9e5b-876e44541928')
     def test_list_image_metadata(self):
         # All metadata key/value pairs for an image should be returned
-        resp_metadata = self.client.get_image_meta(self.image_id)
+        resp_metadata = self.client.check_image(self.image_id)
         expected = {'key1': 'value1'}
         self.assertEqual(expected, resp_metadata['properties'])
 
@@ -313,12 +314,12 @@
     def test_update_image_metadata(self):
         # The metadata for the image should match the updated values
         req_metadata = {'key1': 'alt1', 'key2': 'value2'}
-        metadata = self.client.get_image_meta(self.image_id)
+        metadata = self.client.check_image(self.image_id)
         self.assertEqual(metadata['properties'], {'key1': 'value1'})
         metadata['properties'].update(req_metadata)
         metadata = self.client.update_image(
             self.image_id, properties=metadata['properties'])['image']
 
-        resp_metadata = self.client.get_image_meta(self.image_id)
+        resp_metadata = self.client.check_image(self.image_id)
         expected = {'key1': 'alt1', 'key2': 'value2'}
         self.assertEqual(expected, resp_metadata['properties'])
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index 2156e64..2abbf93 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -13,10 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import netaddr
-
 from tempest.api.network import base
 from tempest.common.utils import data_utils
+from tempest.common.utils import net_utils
 from tempest import config
 from tempest import test
 
@@ -192,8 +191,12 @@
     @test.idempotent_id('45c4c683-ea97-41ef-9c51-5e9802f2f3d7')
     def test_create_update_floatingip_with_port_multiple_ip_address(self):
         # Find out ips that can be used for tests
-        ips = list(netaddr.IPNetwork(self.subnet['cidr']))
-        list_ips = [str(ip) for ip in ips[-3:-1]]
+        list_ips = net_utils.get_unused_ip_addresses(
+            self.ports_client,
+            self.subnets_client,
+            self.subnet['network_id'],
+            self.subnet['id'],
+            2)
         fixed_ips = [{'ip_address': list_ips[0]}, {'ip_address': list_ips[1]}]
         # Create port
         body = self.ports_client.create_port(network_id=self.network['id'],
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 3654b2e..46b068b 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -364,6 +364,23 @@
         self._verify_router_interface(router['id'], subnet02['id'],
                                       interface02['port_id'])
 
+    @test.idempotent_id('96522edf-b4b5-45d9-8443-fa11c26e6eff')
+    def test_router_interface_port_update_with_fixed_ip(self):
+        network = self.create_network()
+        subnet = self.create_subnet(network)
+        router = self._create_router(data_utils.rand_name('router-'))
+        fixed_ip = [{'subnet_id': subnet['id']}]
+        interface = self._add_router_interface_with_subnet_id(router['id'],
+                                                              subnet['id'])
+        self.assertIn('port_id', interface)
+        self.assertIn('subnet_id', interface)
+        port = self.ports_client.show_port(interface['port_id'])
+        self.assertEqual(port['port']['id'], interface['port_id'])
+        router_port = self.ports_client.update_port(port['port']['id'],
+                                                    fixed_ips=fixed_ip)
+        self.assertEqual(subnet['id'],
+                         router_port['port']['fixed_ips'][0]['subnet_id'])
+
     def _verify_router_interface(self, router_id, subnet_id, port_id):
         show_port_body = self.ports_client.show_port(port_id)
         interface_port = show_port_body['port']
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index b9765c8..a3b0a82 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -153,6 +153,7 @@
 
         # Create rule for icmp protocol with invalid ports
         states = [(1, 256, 'Invalid value for ICMP code'),
+                  (-1, 25, 'Invalid value'),
                   (None, 6, 'ICMP type (port-range-min) is missing'),
                   (300, 1, 'Invalid value for ICMP type')]
         for pmin, pmax, msg in states:
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index e8b035b..a88e4f4 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -20,7 +20,6 @@
 import zlib
 
 import six
-from six import moves
 
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
@@ -179,23 +178,14 @@
     @test.idempotent_id('84dafe57-9666-4f6d-84c8-0814d37923b8')
     def test_create_object_with_expect_continue(self):
         # create object with expect_continue
+
         object_name = data_utils.rand_name(name='TestObject')
         data = data_utils.arbitrary_string()
-        metadata = {'Expect': '100-continue'}
-        resp = self.object_client.create_object_continue(
-            self.container_name,
-            object_name,
-            data,
-            metadata=metadata)
 
-        self.assertIn('status', resp)
-        self.assertEqual(resp['status'], '100')
+        status, _ = self.object_client.create_object_continue(
+            self.container_name, object_name, data)
 
-        self.object_client.create_object_continue(
-            self.container_name,
-            object_name,
-            data,
-            metadata=None)
+        self.assertEqual(status, 201)
 
         # check uploaded content
         _, body = self.object_client.get_object(self.container_name,
@@ -210,8 +200,8 @@
         status, _, resp_headers = self.object_client.put_object_with_chunk(
             container=self.container_name,
             name=object_name,
-            contents=moves.cStringIO(data),
-            chunk_size=512)
+            contents=data_utils.chunkify(data, 512)
+        )
         self.assertHeaders(resp_headers, 'Object', 'PUT')
 
         # check uploaded content
diff --git a/tempest/api/telemetry/base.py b/tempest/api/telemetry/base.py
deleted file mode 100644
index 7238098..0000000
--- a/tempest/api/telemetry/base.py
+++ /dev/null
@@ -1,196 +0,0 @@
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import time
-
-from oslo_utils import timeutils
-
-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
-
-
-class BaseTelemetryTest(tempest.test.BaseTestCase):
-
-    """Base test case class for all Telemetry API tests."""
-
-    credentials = ['primary']
-
-    @classmethod
-    def skip_checks(cls):
-        super(BaseTelemetryTest, cls).skip_checks()
-        if not CONF.service_available.ceilometer:
-            raise cls.skipException("Ceilometer support is required")
-
-    @classmethod
-    def setup_credentials(cls):
-        cls.set_network_resources()
-        super(BaseTelemetryTest, cls).setup_credentials()
-
-    @classmethod
-    def setup_clients(cls):
-        super(BaseTelemetryTest, cls).setup_clients()
-        cls.telemetry_client = cls.os.telemetry_client
-        cls.servers_client = cls.os.servers_client
-        cls.flavors_client = cls.os.flavors_client
-        cls.image_client = cls.os.image_client
-        cls.image_client_v2 = cls.os.image_client_v2
-
-    @classmethod
-    def resource_setup(cls):
-        super(BaseTelemetryTest, cls).resource_setup()
-        cls.nova_notifications = ['memory', 'vcpus', 'disk.root.size',
-                                  'disk.ephemeral.size']
-
-        cls.glance_notifications = ['image.size']
-
-        cls.glance_v2_notifications = ['image.download', 'image.serve']
-
-        cls.server_ids = []
-        cls.image_ids = []
-
-    @classmethod
-    def create_server(cls):
-        tenant_network = cls.get_tenant_network()
-        body, server = compute.create_test_server(
-            cls.os,
-            tenant_network=tenant_network,
-            name=data_utils.rand_name('ceilometer-instance'),
-            wait_until='ACTIVE')
-        cls.server_ids.append(body['id'])
-        return body
-
-    @classmethod
-    def create_image(cls, client, **kwargs):
-        body = client.create_image(name=data_utils.rand_name('image'),
-                                   container_format='bare',
-                                   disk_format='raw',
-                                   **kwargs)
-        # TODO(jswarren) Move ['image'] up to initial body value assignment
-        # once both v1 and v2 glance clients include the full response
-        # object.
-        if 'image' in body:
-            body = body['image']
-        cls.image_ids.append(body['id'])
-        return body
-
-    @staticmethod
-    def cleanup_resources(method, list_of_ids):
-        for resource_id in list_of_ids:
-            try:
-                method(resource_id)
-            except lib_exc.NotFound:
-                pass
-
-    @classmethod
-    def wait_for_server_termination(cls, server_id):
-        waiters.wait_for_server_termination(cls.servers_client,
-                                            server_id)
-
-    @classmethod
-    def resource_cleanup(cls):
-        cls.cleanup_resources(cls.servers_client.delete_server, cls.server_ids)
-        cls.cleanup_resources(cls.wait_for_server_termination, cls.server_ids)
-        cls.cleanup_resources(cls.image_client.delete_image, cls.image_ids)
-        super(BaseTelemetryTest, cls).resource_cleanup()
-
-    def await_samples(self, metric, query):
-        """This method is to wait for sample to add it to database.
-
-        There are long time delays when using Postgresql (or Mysql)
-        database as ceilometer backend
-        """
-        timeout = CONF.compute.build_timeout
-        start = timeutils.utcnow()
-        while timeutils.delta_seconds(start, timeutils.utcnow()) < timeout:
-            body = self.telemetry_client.list_samples(metric, query)
-            if body:
-                return body
-            time.sleep(CONF.compute.build_interval)
-
-        raise exceptions.TimeoutException(
-            'Sample for metric:%s with query:%s has not been added to the '
-            'database within %d seconds' % (metric, query,
-                                            CONF.compute.build_timeout))
-
-
-class BaseTelemetryAdminTest(BaseTelemetryTest):
-    """Base test case class for admin Telemetry API tests."""
-
-    credentials = ['primary', 'admin']
-
-    @classmethod
-    def setup_clients(cls):
-        super(BaseTelemetryAdminTest, cls).setup_clients()
-        cls.telemetry_admin_client = cls.os_adm.telemetry_client
-
-    def await_events(self, query):
-        timeout = CONF.compute.build_timeout
-        start = timeutils.utcnow()
-        while timeutils.delta_seconds(start, timeutils.utcnow()) < timeout:
-            body = self.telemetry_admin_client.list_events(query)
-            if body:
-                return body
-            time.sleep(CONF.compute.build_interval)
-
-        raise exceptions.TimeoutException(
-            'Event with query:%s has not been added to the '
-            'database within %d seconds' % (query, CONF.compute.build_timeout))
-
-
-class BaseAlarmingTest(tempest.test.BaseTestCase):
-    """Base test case class for all Alarming API tests."""
-
-    credentials = ['primary']
-
-    @classmethod
-    def skip_checks(cls):
-        super(BaseAlarmingTest, cls).skip_checks()
-        if not CONF.service_available.aodh:
-            raise cls.skipException("Aodh support is required")
-
-    @classmethod
-    def setup_clients(cls):
-        super(BaseAlarmingTest, cls).setup_clients()
-        cls.alarming_client = cls.os.alarming_client
-
-    @classmethod
-    def resource_setup(cls):
-        super(BaseAlarmingTest, cls).resource_setup()
-        cls.alarm_ids = []
-
-    @classmethod
-    def create_alarm(cls, **kwargs):
-        body = cls.alarming_client.create_alarm(
-            name=data_utils.rand_name('telemetry_alarm'),
-            type='threshold', **kwargs)
-        cls.alarm_ids.append(body['alarm_id'])
-        return body
-
-    @staticmethod
-    def cleanup_resources(method, list_of_ids):
-        for resource_id in list_of_ids:
-            try:
-                method(resource_id)
-            except lib_exc.NotFound:
-                pass
-
-    @classmethod
-    def resource_cleanup(cls):
-        cls.cleanup_resources(cls.alarming_client.delete_alarm, cls.alarm_ids)
-        super(BaseAlarmingTest, cls).resource_cleanup()
diff --git a/tempest/api/telemetry/test_alarming_api.py b/tempest/api/telemetry/test_alarming_api.py
deleted file mode 100644
index 586bb42..0000000
--- a/tempest/api/telemetry/test_alarming_api.py
+++ /dev/null
@@ -1,110 +0,0 @@
-#    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.telemetry import base
-from tempest.common.utils import data_utils
-from tempest.lib import exceptions as lib_exc
-from tempest import test
-
-
-class TelemetryAlarmingAPITestJSON(base.BaseAlarmingTest):
-
-    @classmethod
-    def resource_setup(cls):
-        super(TelemetryAlarmingAPITestJSON, cls).resource_setup()
-        cls.rule = {'meter_name': 'cpu_util',
-                    'comparison_operator': 'gt',
-                    'threshold': 80.0,
-                    'period': 70}
-        for i in range(2):
-            cls.create_alarm(threshold_rule=cls.rule)
-
-    @test.idempotent_id('1c918e06-210b-41eb-bd45-14676dd77cd6')
-    def test_alarm_list(self):
-        # List alarms
-        alarm_list = self.alarming_client.list_alarms()
-
-        # Verify created alarm in the list
-        fetched_ids = [a['alarm_id'] for a in alarm_list]
-        missing_alarms = [a for a in self.alarm_ids if a not in fetched_ids]
-        self.assertEqual(0, len(missing_alarms),
-                         "Failed to find the following created alarm(s)"
-                         " in a fetched list: %s" %
-                         ', '.join(str(a) for a in missing_alarms))
-
-    @test.idempotent_id('1297b095-39c1-4e74-8a1f-4ae998cedd67')
-    def test_create_update_get_delete_alarm(self):
-        # Create an alarm
-        alarm_name = data_utils.rand_name('telemetry_alarm')
-        body = self.alarming_client.create_alarm(
-            name=alarm_name, type='threshold', threshold_rule=self.rule)
-        self.assertEqual(alarm_name, body['name'])
-        alarm_id = body['alarm_id']
-        self.assertDictContainsSubset(self.rule, body['threshold_rule'])
-        # Update alarm with new rule and new name
-        new_rule = {'meter_name': 'cpu',
-                    'comparison_operator': 'eq',
-                    'threshold': 70.0,
-                    'period': 60}
-        alarm_name_updated = data_utils.rand_name('telemetry-alarm-update')
-        body = self.alarming_client.update_alarm(
-            alarm_id,
-            threshold_rule=new_rule,
-            name=alarm_name_updated,
-            type='threshold')
-        self.assertEqual(alarm_name_updated, body['name'])
-        self.assertDictContainsSubset(new_rule, body['threshold_rule'])
-        # Get and verify details of an alarm after update
-        body = self.alarming_client.show_alarm(alarm_id)
-        self.assertEqual(alarm_name_updated, body['name'])
-        self.assertDictContainsSubset(new_rule, body['threshold_rule'])
-        # Get history for the alarm and verify the same
-        body = self.alarming_client.show_alarm_history(alarm_id)
-        self.assertEqual("rule change", body[0]['type'])
-        self.assertIn(alarm_name_updated, body[0]['detail'])
-        self.assertEqual("creation", body[1]['type'])
-        self.assertIn(alarm_name, body[1]['detail'])
-        # Delete alarm and verify if deleted
-        self.alarming_client.delete_alarm(alarm_id)
-        self.assertRaises(lib_exc.NotFound,
-                          self.alarming_client.show_alarm, alarm_id)
-
-    @test.idempotent_id('aca49486-70bb-4016-87e0-f6131374f741')
-    def test_set_get_alarm_state(self):
-        alarm_states = ['ok', 'alarm', 'insufficient data']
-        alarm = self.create_alarm(threshold_rule=self.rule)
-        # Set alarm state and verify
-        new_state =\
-            [elem for elem in alarm_states if elem != alarm['state']][0]
-        state = self.alarming_client.alarm_set_state(alarm['alarm_id'],
-                                                     new_state)
-        self.assertEqual(new_state, state.data)
-        # Get alarm state and verify
-        state = self.alarming_client.show_alarm_state(alarm['alarm_id'])
-        self.assertEqual(new_state, state.data)
-
-    @test.idempotent_id('08d7e45a-1344-4e5c-ba6f-f6cbb77f55b9')
-    def test_create_delete_alarm_with_combination_rule(self):
-        rule = {"alarm_ids": self.alarm_ids,
-                "operator": "or"}
-        # Verifies alarm create
-        alarm_name = data_utils.rand_name('combination_alarm')
-        body = self.alarming_client.create_alarm(name=alarm_name,
-                                                 combination_rule=rule,
-                                                 type='combination')
-        self.assertEqual(alarm_name, body['name'])
-        alarm_id = body['alarm_id']
-        self.assertDictContainsSubset(rule, body['combination_rule'])
-        # Verify alarm delete
-        self.alarming_client.delete_alarm(alarm_id)
-        self.assertRaises(lib_exc.NotFound,
-                          self.alarming_client.show_alarm, alarm_id)
diff --git a/tempest/api/telemetry/test_alarming_api_negative.py b/tempest/api/telemetry/test_alarming_api_negative.py
deleted file mode 100644
index 3e34f8b..0000000
--- a/tempest/api/telemetry/test_alarming_api_negative.py
+++ /dev/null
@@ -1,69 +0,0 @@
-#    Copyright 2015 GlobalLogic.  All rights reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.api.telemetry import base
-from tempest.common.utils import data_utils
-from tempest.lib import exceptions as lib_exc
-from tempest import test
-
-
-class TelemetryAlarmingNegativeTest(base.BaseAlarmingTest):
-    """Negative tests for show_alarm, update_alarm, show_alarm_history tests
-
-        ** show non-existent alarm
-        ** show the deleted alarm
-        ** delete deleted alarm
-        ** update deleted alarm
-    """
-
-    @test.attr(type=['negative'])
-    @test.idempotent_id('668743d5-08ad-4480-b2b8-15da34f81e7d')
-    def test_get_non_existent_alarm(self):
-        # get the non-existent alarm
-        non_existent_id = data_utils.rand_uuid()
-        self.assertRaises(lib_exc.NotFound, self.alarming_client.show_alarm,
-                          non_existent_id)
-
-    @test.attr(type=['negative'])
-    @test.idempotent_id('ef45000d-0a72-4781-866d-4cb7bf2582ad')
-    def test_get_update_show_history_delete_deleted_alarm(self):
-        # get, update and delete the deleted alarm
-        alarm_name = data_utils.rand_name('telemetry_alarm')
-        rule = {'meter_name': 'cpu',
-                'comparison_operator': 'eq',
-                'threshold': 100.0,
-                'period': 90}
-        body = self.alarming_client.create_alarm(
-            name=alarm_name,
-            type='threshold',
-            threshold_rule=rule)
-        alarm_id = body['alarm_id']
-        self.alarming_client.delete_alarm(alarm_id)
-        # get the deleted alarm
-        self.assertRaises(lib_exc.NotFound, self.alarming_client.show_alarm,
-                          alarm_id)
-
-        # update the deleted alarm
-        updated_alarm_name = data_utils.rand_name('telemetry_alarm_updated')
-        updated_rule = {'meter_name': 'cpu_new',
-                        'comparison_operator': 'eq',
-                        'threshold': 70,
-                        'period': 50}
-        self.assertRaises(lib_exc.NotFound, self.alarming_client.update_alarm,
-                          alarm_id, threshold_rule=updated_rule,
-                          name=updated_alarm_name,
-                          type='threshold')
-        # delete the deleted alarm
-        self.assertRaises(lib_exc.NotFound, self.alarming_client.delete_alarm,
-                          alarm_id)
diff --git a/tempest/api/telemetry/test_telemetry_notification_api.py b/tempest/api/telemetry/test_telemetry_notification_api.py
deleted file mode 100644
index 53d457f..0000000
--- a/tempest/api/telemetry/test_telemetry_notification_api.py
+++ /dev/null
@@ -1,84 +0,0 @@
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import testtools
-
-from tempest.api.telemetry import base
-from tempest import config
-from tempest.lib import decorators
-from tempest import test
-
-CONF = config.CONF
-
-
-class TelemetryNotificationAPITestJSON(base.BaseTelemetryTest):
-
-    @test.idempotent_id('d7f8c1c8-d470-4731-8604-315d3956caad')
-    @test.services('compute')
-    def test_check_nova_notification(self):
-
-        body = self.create_server()
-
-        query = ('resource', 'eq', body['id'])
-
-        for metric in self.nova_notifications:
-            self.await_samples(metric, query)
-
-    @test.attr(type="smoke")
-    @test.idempotent_id('04b10bfe-a5dc-47af-b22f-0460426bf498')
-    @test.services("image")
-    @testtools.skipIf(not CONF.image_feature_enabled.api_v1,
-                      "Glance api v1 is disabled")
-    def test_check_glance_v1_notifications(self):
-        body = self.create_image(self.image_client, is_public=False)
-        self.image_client.update_image(body['id'], data='data')
-
-        query = 'resource', 'eq', body['id']
-
-        self.image_client.delete_image(body['id'])
-
-        for metric in self.glance_notifications:
-            self.await_samples(metric, query)
-
-    @test.attr(type="smoke")
-    @test.idempotent_id('c240457d-d943-439b-8aea-85e26d64fe8e')
-    @test.services("image")
-    @testtools.skipIf(not CONF.image_feature_enabled.api_v2,
-                      "Glance api v2 is disabled")
-    def test_check_glance_v2_notifications(self):
-        body = self.create_image(self.image_client_v2, visibility='private')
-
-        self.image_client_v2.store_image_file(body['id'], "file")
-        self.image_client_v2.show_image_file(body['id'])
-
-        query = 'resource', 'eq', body['id']
-
-        for metric in self.glance_v2_notifications:
-            self.await_samples(metric, query)
-
-
-class TelemetryNotificationAdminAPITestJSON(base.BaseTelemetryAdminTest):
-
-    @test.idempotent_id('29604198-8b45-4fc0-8af8-1cae4f94ebe9')
-    @test.services('compute')
-    @decorators.skip_because(bug='1480490')
-    def test_check_nova_notification_event_and_meter(self):
-
-        body = self.create_server()
-
-        if CONF.telemetry_feature_enabled.events:
-            query = ('instance_id', 'eq', body['id'])
-            self.await_events(query)
-
-        query = ('resource', 'eq', body['id'])
-        for metric in self.nova_notifications:
-            self.await_samples(metric, query)
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index f19717e..00acc7d 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -32,14 +32,9 @@
     @classmethod
     def resource_setup(cls):
         super(VolumeMultiBackendV2Test, cls).resource_setup()
-        # support 2 backends names, deprecated_for_removal.
-        # keep support 2 backend names, in case they are not empty
-        if CONF.volume.backend1_name and CONF.volume.backend2_name:
-            cls.backend_names = {CONF.volume.backend1_name,
-                                 CONF.volume.backend2_name}
-        else:
-            # read backend name from a list .
-            cls.backend_names = set(CONF.volume.backend_names)
+
+        # read backend name from a list .
+        cls.backend_names = set(CONF.volume.backend_names)
 
         cls.name_field = cls.special_fields['name_field']
         cls.volume_type_id_list = []
diff --git a/tempest/api/volume/test_qos.py b/tempest/api/volume/admin/test_qos.py
similarity index 100%
rename from tempest/api/volume/test_qos.py
rename to tempest/api/volume/admin/test_qos.py
diff --git a/tempest/api/volume/admin/test_volume_pools.py b/tempest/api/volume/admin/test_volume_pools.py
new file mode 100644
index 0000000..c662e8c
--- /dev/null
+++ b/tempest/api/volume/admin/test_volume_pools.py
@@ -0,0 +1,43 @@
+# Copyright 2016 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.volume import base
+from tempest import test
+
+
+class VolumePoolsAdminV2TestsJSON(base.BaseVolumeAdminTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(VolumePoolsAdminV2TestsJSON, cls).resource_setup()
+        # Create a test shared volume for tests
+        cls.volume = cls.create_volume()
+
+    @test.idempotent_id('0248a46c-e226-4933-be10-ad6fca8227e7')
+    def test_get_pools_without_details(self):
+        volume_info = self.admin_volume_client. \
+            show_volume(self.volume['id'])['volume']
+        cinder_pools = self.admin_volume_client.show_pools()['pools']
+        self.assertIn(volume_info['os-vol-host-attr:host'],
+                      [pool['name'] for pool in cinder_pools])
+
+    @test.idempotent_id('d4bb61f7-762d-4437-b8a4-5785759a0ced')
+    def test_get_pools_with_details(self):
+        volume_info = self.admin_volume_client. \
+            show_volume(self.volume['id'])['volume']
+        cinder_pools = self.admin_volume_client.\
+            show_pools(detail=True)['pools']
+        self.assertIn(volume_info['os-vol-host-attr:host'],
+                      [pool['name'] for pool in cinder_pools])
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 7202881..6fc6f1c 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -28,9 +28,6 @@
         self.volumes_client.delete_volume(volume_id)
         self.volumes_client.wait_for_resource_deletion(volume_id)
 
-    def _delete_volume_type(self, volume_type_id):
-        self.volume_types_client.delete_volume_type(volume_type_id)
-
     @test.idempotent_id('9d9b28e3-1b2e-4483-a2cc-24aa0ea1de54')
     def test_volume_type_list(self):
         # List volume types.
@@ -54,7 +51,8 @@
                 name=vol_type_name,
                 extra_specs=extra_specs)['volume_type']
             volume_types.append(vol_type)
-            self.addCleanup(self._delete_volume_type, vol_type['id'])
+            self.addCleanup(self.volume_types_client.delete_volume_type,
+                            vol_type['id'])
         params = {self.name_field: vol_name,
                   'volume_type': volume_types[0]['id']}
 
@@ -103,7 +101,8 @@
             name=name,
             extra_specs=extra_specs)['volume_type']
         self.assertIn('id', body)
-        self.addCleanup(self._delete_volume_type, body['id'])
+        self.addCleanup(self.volume_types_client.delete_volume_type,
+                        body['id'])
         self.assertIn('name', body)
         self.assertEqual(body['name'], name,
                          "The created volume_type name is not equal "
@@ -130,7 +129,8 @@
         name = data_utils.rand_name("volume-type")
         body = self.volume_types_client.create_volume_type(
             name=name)['volume_type']
-        self.addCleanup(self._delete_volume_type, body['id'])
+        self.addCleanup(self.volume_types_client.delete_volume_type,
+                        body['id'])
 
         # Create encryption type
         encryption_type = self.volume_types_client.create_encryption_type(
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index e52216f..5975231 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -125,7 +125,7 @@
             disk_format=CONF.volume.disk_format)['os-volume_upload_image']
         image_id = body["image_id"]
         self.addCleanup(self._cleanup_image, image_id)
-        self.image_client.wait_for_image_status(image_id, 'active')
+        waiters.wait_for_image_status(self.image_client, image_id, 'active')
         waiters.wait_for_volume_status(self.client,
                                        self.volume['id'], 'available')
 
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 866e676..6707121 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -14,6 +14,7 @@
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -34,6 +35,9 @@
 
         cls.name_field = cls.special_fields['name_field']
         cls.descrip_field = cls.special_fields['descrip_field']
+        # Create 2 snapshots
+        for _ in xrange(2):
+            cls.create_snapshot(cls.volume_origin['id'])
 
     def _detach(self, volume_id):
         """Detach volume."""
@@ -58,6 +62,14 @@
                       ('details' if with_detail else '', key)
                 self.assertEqual(params[key], snap[key], msg)
 
+    def _list_snapshots_by_param_limit(self, limit, expected_elements):
+        """list snapshots by limit param"""
+        # Get snapshots list using limit parameter
+        fetched_snap_list = self.snapshots_client.list_snapshots(
+            limit=limit)['snapshots']
+        # Validating filtered snapshots length equals to expected_elements
+        self.assertEqual(expected_elements, len(fetched_snap_list))
+
     @test.idempotent_id('b467b54c-07a4-446d-a1cf-651dedcc3ff1')
     @test.services('compute')
     def test_snapshot_create_with_volume_in_use(self):
@@ -178,6 +190,25 @@
         self.volumes_client.wait_for_resource_deletion(volume['id'])
         self.cleanup_snapshot(snapshot)
 
+    @test.idempotent_id('db4d8e0a-7a2e-41cc-a712-961f6844e896')
+    def test_snapshot_list_param_limit(self):
+        # List returns limited elements
+        self._list_snapshots_by_param_limit(limit=1, expected_elements=1)
+
+    @test.idempotent_id('a1427f61-420e-48a5-b6e3-0b394fa95400')
+    def test_snapshot_list_param_limit_equals_infinite(self):
+        # List returns all elements when request limit exceeded
+        # snapshots number
+        snap_list = self.snapshots_client.list_snapshots()['snapshots']
+        self._list_snapshots_by_param_limit(limit=100000,
+                                            expected_elements=len(snap_list))
+
+    @decorators.skip_because(bug='1540893')
+    @test.idempotent_id('e3b44b7f-ae87-45b5-8a8c-66110eb24d0a')
+    def test_snapshot_list_param_limit_equals_zero(self):
+        # List returns zero elements
+        self._list_snapshots_by_param_limit(limit=0, expected_elements=0)
+
     def cleanup_snapshot(self, snapshot):
         # Delete the snapshot
         self.snapshots_client.delete_snapshot(snapshot['id'])
diff --git a/tempest/api/volume/v2/test_volumes_list.py b/tempest/api/volume/v2/test_volumes_list.py
index bedbad4..1fa54c2 100644
--- a/tempest/api/volume/v2/test_volumes_list.py
+++ b/tempest/api/volume/v2/test_volumes_list.py
@@ -18,6 +18,7 @@
 from six.moves.urllib import parse
 
 from tempest.api.volume import base
+from tempest.lib import decorators
 from tempest import test
 
 
@@ -188,6 +189,7 @@
         self._test_pagination('volumes', ids=self.volume_id_list, detail=False)
 
     @test.idempotent_id('46eff077-100b-427f-914e-3db2abcdb7e2')
+    @decorators.skip_because(bug='1572765')
     def test_volume_list_with_detail_param_marker(self):
         # Choosing a random volume from a list of volumes for 'marker'
         # parameter
diff --git a/tempest/clients.py b/tempest/clients.py
index 0eded8b..19f1a2a 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -131,16 +131,14 @@
 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.image.v2.json.images_client import \
+    ImagesClient as ImagesV2Client
 from tempest.services.network.json.routers_client import RoutersClient
 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
 from tempest.services.orchestration.json.orchestration_client import \
     OrchestrationClient
-from tempest.services.telemetry.json.alarming_client import AlarmingClient
-from tempest.services.telemetry.json.telemetry_client import \
-    TelemetryClient
 from tempest.services.volume.v1.json.admin.hosts_client import \
     HostsClient as VolumeHostsClient
 from tempest.services.volume.v1.json.admin.quotas_client import \
@@ -200,14 +198,15 @@
     }
     default_params_with_timeout_values.update(default_params)
 
-    def __init__(self, credentials, service=None):
+    def __init__(self, credentials, service=None, scope='project'):
         """Initialization of Manager class.
 
         Setup all services clients and make them available for tests cases.
         :param credentials: type Credentials or TestResources
         :param service: Service name
+        :param scope: default scope for tokens produced by the auth provider
         """
-        super(Manager, self).__init__(credentials=credentials)
+        super(Manager, self).__init__(credentials=credentials, scope=scope)
         self._set_compute_clients()
         self._set_database_clients()
         self._set_identity_clients()
@@ -324,20 +323,6 @@
             build_interval=CONF.network.build_interval,
             build_timeout=CONF.network.build_timeout,
             **self.default_params)
-        if CONF.service_available.ceilometer:
-            self.telemetry_client = TelemetryClient(
-                self.auth_provider,
-                CONF.telemetry.catalog_type,
-                CONF.identity.region,
-                endpoint_type=CONF.telemetry.endpoint_type,
-                **self.default_params_with_timeout_values)
-        if CONF.service_available.aodh:
-            self.alarming_client = AlarmingClient(
-                self.auth_provider,
-                CONF.alarming.catalog_type,
-                CONF.identity.region,
-                endpoint_type=CONF.alarming.endpoint_type,
-                **self.default_params_with_timeout_values)
         if CONF.service_available.glance:
             self.image_client = ImagesClient(
                 self.auth_provider,
@@ -347,7 +332,7 @@
                 build_interval=CONF.image.build_interval,
                 build_timeout=CONF.image.build_timeout,
                 **self.default_params)
-            self.image_client_v2 = ImagesClientV2(
+            self.image_client_v2 = ImagesV2Client(
                 self.auth_provider,
                 CONF.image.catalog_type,
                 CONF.image.region or CONF.identity.region,
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index a154d0b..5fab961 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -262,7 +262,7 @@
             user = identity.get_user_by_username(tenants_admin,
                                                  tenant['id'], u['name'])
         except tempest.lib.exceptions.NotFound:
-            LOG.error("User: %s - not found" % u['user'])
+            LOG.error("User: %s - not found" % u['name'])
             continue
         for r in u['role_ids']:
             try:
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index f51fc53..9e86b48 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -33,7 +33,6 @@
 CONF_TENANTS = None
 CONF_USERS = None
 
-IS_AODH = None
 IS_CINDER = None
 IS_GLANCE = None
 IS_HEAT = None
@@ -51,14 +50,12 @@
     global CONF_PUB_ROUTER
     global CONF_TENANTS
     global CONF_USERS
-    global IS_AODH
     global IS_CINDER
     global IS_GLANCE
     global IS_HEAT
     global IS_NEUTRON
     global IS_NOVA
 
-    IS_AODH = CONF.service_available.aodh
     IS_CINDER = CONF.service_available.cinder
     IS_GLANCE = CONF.service_available.glance
     IS_HEAT = CONF.service_available.heat
@@ -706,32 +703,6 @@
         self.data['subnets'] = subnets
 
 
-# Telemetry services
-class TelemetryAlarmService(BaseService):
-    def __init__(self, manager, **kwargs):
-        super(TelemetryAlarmService, self).__init__(kwargs)
-        self.client = manager.alarming_client
-
-    def list(self):
-        client = self.client
-        alarms = client.list_alarms()
-        LOG.debug("List count, %s Alarms" % len(alarms))
-        return alarms
-
-    def delete(self):
-        client = self.client
-        alarms = self.list()
-        for alarm in alarms:
-            try:
-                client.delete_alarm(alarm['id'])
-            except Exception:
-                LOG.exception("Delete Alarms exception.")
-
-    def dry_run(self):
-        alarms = self.list()
-        self.data['alarms'] = alarms
-
-
 # begin global services
 class FlavorService(BaseService):
     def __init__(self, manager, **kwargs):
@@ -976,8 +947,8 @@
 
 def get_tenant_cleanup_services():
     tenant_services = []
-    if IS_AODH:
-        tenant_services.append(TelemetryAlarmService)
+    # TODO(gmann): Tempest should provide some plugin hook for cleanup
+    # script extension to plugin tests also.
     if IS_NOVA:
         tenant_services.append(ServerService)
         tenant_services.append(KeyPairService)
diff --git a/tempest/cmd/init.py b/tempest/cmd/init.py
index ac67ce4..633b9e9 100644
--- a/tempest/cmd/init.py
+++ b/tempest/cmd/init.py
@@ -54,21 +54,28 @@
     real_prefix = getattr(sys, 'real_prefix', None)
     base_prefix = getattr(sys, 'base_prefix', None)
     prefix = sys.prefix
+    global_conf_dir = '/etc/tempest'
     if (real_prefix is None and
-            (base_prefix is None or base_prefix == prefix)):
+            (base_prefix is None or base_prefix == prefix) and
+            os.path.isdir(global_conf_dir)):
         # Probably not running in a virtual environment.
         # NOTE(andreaf) we cannot distinguish this case from the case of
         # a virtual environment created with virtualenv, and running python3.
         # Also if it appears we are not in virtual env and fail to find
         # global config: '/etc/tempest', fall back to
         # '[sys.prefix]/etc/tempest'
-        global_conf_dir = '/etc/tempest'
-        if os.path.isdir(global_conf_dir):
-            return global_conf_dir
-        else:
-            return os.path.join(prefix, 'etc/tempest')
+        return global_conf_dir
     else:
-        return os.path.join(prefix, 'etc/tempest')
+        conf_dir = os.path.join(prefix, 'etc/tempest')
+        if os.path.isdir(conf_dir):
+            return conf_dir
+        else:
+            # NOTE: The prefix is gotten from the path which pyconfig.h is
+            # installed under. Some envs contain it under /usr/include, not
+            # /user/local/include. Then prefix becomes /usr on such envs.
+            # However, etc/tempest is installed under /usr/local and the bove
+            # path logic mismatches. This is a workaround for such envs.
+            return os.path.join(prefix, 'local/etc/tempest')
 
 
 class TempestInit(command.Command):
@@ -78,6 +85,10 @@
         parser = super(TempestInit, self).get_parser(prog_name)
         parser.add_argument('dir', nargs='?', default=os.getcwd())
         parser.add_argument('--config-dir', '-c', default=None)
+        parser.add_argument('--show-global-config-dir', '-s',
+                            action='store_true', dest='show_global_dir',
+                            help="Print the global config dir location, "
+                                 "then exit")
         return parser
 
     def generate_testr_conf(self, local_path):
@@ -91,8 +102,7 @@
     def update_local_conf(self, conf_path, lock_dir, log_dir):
         config_parse = moves.configparser.SafeConfigParser()
         config_parse.optionxform = str
-        with open(conf_path, 'w+') as conf_file:
-            config_parse.readfp(conf_file)
+        with open(conf_path, 'a+') as conf_file:
             # Set local lock_dir in tempest conf
             if not config_parse.has_section('oslo_concurrency'):
                 config_parse.add_section('oslo_concurrency')
@@ -101,6 +111,7 @@
             config_parse.set('DEFAULT', 'log_dir', log_dir)
             # Set default log filename to tempest.log
             config_parse.set('DEFAULT', 'log_file', 'tempest.log')
+            config_parse.write(conf_file)
 
     def copy_config(self, etc_dir, config_dir):
         shutil.copytree(config_dir, etc_dir)
@@ -149,4 +160,7 @@
 
     def take_action(self, parsed_args):
         config_dir = parsed_args.config_dir or get_tempest_default_config_dir()
+        if parsed_args.show_global_dir:
+            print("Global config dir is located at: %s" % config_dir)
+            sys.exit(0)
         self.create_working_dir(parsed_args.dir, config_dir)
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 2a4e314..17ee618 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -113,7 +113,6 @@
 
 import netaddr
 from oslo_log import log as logging
-from oslo_utils import timeutils
 import six
 import yaml
 
@@ -138,8 +137,6 @@
 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
-from tempest.services.telemetry.json import telemetry_client
 from tempest.services.volume.v1.json import volumes_client
 
 CONF = config.CONF
@@ -236,7 +233,7 @@
                                                   **object_storage_params)
         self.containers = container_client.ContainerClient(
             _auth, **object_storage_params)
-        self.images = images_client.ImagesClientV2(
+        self.images = images_client.ImagesClient(
             _auth,
             CONF.image.catalog_type,
             CONF.image.region or CONF.identity.region,
@@ -244,18 +241,6 @@
             build_interval=CONF.image.build_interval,
             build_timeout=CONF.image.build_timeout,
             **default_params)
-        self.telemetry = telemetry_client.TelemetryClient(
-            _auth,
-            CONF.telemetry.catalog_type,
-            CONF.identity.region,
-            endpoint_type=CONF.telemetry.endpoint_type,
-            **default_params_with_timeout_values)
-        self.alarming = alarming_client.AlarmingClient(
-            _auth,
-            CONF.alarm.catalog_type,
-            CONF.identity.region,
-            endpoint_type=CONF.alarm.endpoint_type,
-            **default_params_with_timeout_values)
         self.volumes = volumes_client.VolumesClient(
             _auth,
             CONF.volume.catalog_type,
@@ -461,7 +446,6 @@
         self.check_objects()
         self.check_servers()
         self.check_volumes()
-        self.check_telemetry()
         self.check_secgroups()
 
         # validate neutron is enabled and ironic disabled:
@@ -563,27 +547,6 @@
                 found,
                 "Couldn't find expected secgroup %s" % secgroup['name'])
 
-    def check_telemetry(self):
-        """Check that ceilometer provides a sane sample.
-
-        Confirm that there is more than one sample and that they have the
-        expected metadata.
-
-        If in check mode confirm that the oldest sample available is from
-        before the upgrade.
-        """
-        if not self.res.get('telemetry'):
-            return
-        LOG.info("checking telemetry")
-        for server in self.res['servers']:
-            client = client_for_user(server['owner'])
-            body = client.telemetry.list_samples(
-                'instance',
-                query=('metadata.display_name', 'eq', server['name'])
-            )
-            self.assertTrue(len(body) >= 1, 'expecting at least one sample')
-            self._confirm_telemetry_sample(server, body[-1])
-
     def check_volumes(self):
         """Check that the volumes are still there and attached."""
         if not self.res.get('volumes'):
@@ -602,26 +565,6 @@
             self.assertEqual(vol_body['id'], attachment['volume_id'])
             self.assertEqual(server_id, attachment['server_id'])
 
-    def _confirm_telemetry_sample(self, server, sample):
-        """Check this sample matches the expected resource metadata."""
-        # Confirm display_name
-        self.assertEqual(server['name'],
-                         sample['resource_metadata']['display_name'])
-        # Confirm instance_type of flavor
-        flavor = sample['resource_metadata'].get(
-            'flavor.name',
-            sample['resource_metadata'].get('instance_type')
-        )
-        self.assertEqual(server['flavor'], flavor)
-        # Confirm the oldest sample was created before upgrade.
-        if OPTS.mode == 'check':
-            oldest_timestamp = timeutils.normalize_time(
-                timeutils.parse_isotime(sample['timestamp']))
-            self.assertTrue(
-                oldest_timestamp < JAVELIN_START,
-                'timestamp should come before start of second javelin run'
-            )
-
     def check_networking(self):
         """Check that the networks are still there."""
         for res_type in ('networks', 'subnets', 'routers'):
diff --git a/tempest/cmd/resources.yaml b/tempest/cmd/resources.yaml
index 2d6664c..5c62ee3 100644
--- a/tempest/cmd/resources.yaml
+++ b/tempest/cmd/resources.yaml
@@ -93,4 +93,3 @@
     name: javelin1
     owner: javelin
     file: /etc/hosts
-telemetry: true
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index f29973d..72ea894 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -16,6 +16,7 @@
 
 import argparse
 import os
+import re
 import sys
 import traceback
 
@@ -77,9 +78,16 @@
                             not CONF.image_feature_enabled.api_v2, update)
 
 
+def _remove_version_project(url_path):
+    # The regex matches strings like /v2.0, /v3/, /v2.1/project-id/
+    return re.sub(r'/v\d+(\.\d+)?(/[^/]+)?', '', url_path)
+
+
 def _get_unversioned_endpoint(base_url):
     endpoint_parts = urlparse.urlparse(base_url)
-    endpoint = endpoint_parts.scheme + '://' + endpoint_parts.netloc
+    new_path = _remove_version_project(endpoint_parts.path)
+    endpoint_parts = endpoint_parts._replace(path=new_path)
+    endpoint = urlparse.urlunparse(endpoint_parts)
     return endpoint
 
 
@@ -89,7 +97,9 @@
         'keystone': os.identity_client,
         'cinder': os.volumes_client,
     }
-    client_dict[service].skip_path()
+    if service != 'keystone':
+        # Since keystone may be listening on a path, do not remove the path.
+        client_dict[service].skip_path()
     endpoint = _get_unversioned_endpoint(client_dict[service].base_url)
 
     http = tempest.lib.common.http.ClosingHttp(
@@ -272,8 +282,6 @@
         'object_storage': 'swift',
         'compute': 'nova',
         'orchestration': 'heat',
-        'metering': 'ceilometer',
-        'telemetry': 'ceilometer',
         'data_processing': 'sahara',
         'baremetal': 'ironic',
         'identity': 'keystone',
@@ -365,7 +373,16 @@
         CONF_PARSER = moves.configparser.SafeConfigParser()
         CONF_PARSER.optionxform = str
         CONF_PARSER.readfp(conf_file)
-    icreds = credentials.get_credentials_provider('verify_tempest_config')
+
+    # Indicate not to create network resources as part of getting credentials
+    net_resources = {
+        'network': False,
+        'router': False,
+        'subnet': False,
+        'dhcp': False
+    }
+    icreds = credentials.get_credentials_provider(
+        'verify_tempest_config', network_resources=net_resources)
     try:
         os = clients.Manager(icreds.get_primary_creds())
         services = check_service_availability(os, update)
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index b5c4547..7ebc283 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -157,3 +157,29 @@
                                           % server['id'])
 
     return body, servers
+
+
+def shelve_server(client, server_id, force_shelve_offload=False):
+    """Common wrapper utility to shelve server.
+
+    This method is a common wrapper to make server in 'SHELVED'
+    or 'SHELVED_OFFLOADED' state.
+
+    :param server_id: Server to make in shelve state
+    :param force_shelve_offload: Forcefully offload shelve server if it
+                                 is configured not to offload server
+                                 automatically after offload time.
+    """
+    client.shelve_server(server_id)
+
+    offload_time = CONF.compute.shelved_offload_time
+    if offload_time >= 0:
+        waiters.wait_for_server_status(client, server_id,
+                                       'SHELVED_OFFLOADED',
+                                       extra_timeout=offload_time)
+    else:
+        waiters.wait_for_server_status(client, server_id, 'SHELVED')
+        if force_shelve_offload:
+            client.shelve_offload_server(server_id)
+            waiters.wait_for_server_status(client, server_id,
+                                           'SHELVED_OFFLOADED')
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
index a4b2ae8..5cce0bb 100644
--- a/tempest/common/cred_provider.py
+++ b/tempest/common/cred_provider.py
@@ -88,6 +88,11 @@
     def __getattr__(self, item):
         return getattr(self._credentials, item)
 
+    def __str__(self):
+        _format = "Credentials: %s, Network: %s, Subnet: %s, Router: %s"
+        return _format % (self._credentials, self.network, self.subnet,
+                          self.router)
+
     def set_resources(self, **kwargs):
         for key in kwargs.keys():
             if hasattr(self, key):
diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py
index 58157ef..286e01f 100644
--- a/tempest/common/credentials_factory.py
+++ b/tempest/common/credentials_factory.py
@@ -14,7 +14,6 @@
 from oslo_concurrency import lockutils
 
 from tempest import clients
-from tempest.common import cred_provider
 from tempest.common import dynamic_creds
 from tempest.common import preprov_creds
 from tempest import config
@@ -26,7 +25,7 @@
 
 """This module provides factories of credential and credential providers
 
-Credentials providers and clients are (going to be) part of tempest-lib,
+Credentials providers and clients are (going to be) part of tempest.lib,
 and so they may not hold any dependency to tempest configuration.
 
 Methods in this module collect the relevant configuration details and pass
@@ -62,89 +61,6 @@
     ]))
 
 
-class LegacyCredentialProvider(cred_provider.CredentialProvider):
-
-    def __init__(self, identity_version):
-        """Credentials provider which returns credentials from tempest.conf
-
-        Credentials provider which always returns the first and second
-        configured accounts as primary and alt users.
-        Credentials from tempest.conf are deprecated, and this credential
-        provider is also accordingly.
-
-        This credential provider can be used in case of serial test execution
-        to preserve the current behaviour of the serial tempest run.
-
-        :param identity_version: Version of the identity API
-        :return: CredentialProvider
-        """
-        super(LegacyCredentialProvider, self).__init__(
-            identity_version=identity_version)
-        self._creds = {}
-
-    def _unique_creds(self, cred_arg=None):
-        """Verify that the configured credentials are valid and distinct """
-        try:
-            user = self.get_primary_creds()
-            alt_user = self.get_alt_creds()
-            return getattr(user, cred_arg) != getattr(alt_user, cred_arg)
-        except exceptions.InvalidCredentials as ic:
-            msg = "At least one of the configured credentials is " \
-                  "not valid: %s" % ic.message
-            raise exceptions.InvalidConfiguration(msg)
-
-    def is_multi_user(self):
-        return self._unique_creds('username')
-
-    def is_multi_tenant(self):
-        return self._unique_creds('tenant_id')
-
-    def get_primary_creds(self):
-        if self._creds.get('primary'):
-            return self._creds.get('primary')
-        primary_credential = get_configured_credentials(
-            credential_type='user', fill_in=False,
-            identity_version=self.identity_version)
-        self._creds['primary'] = cred_provider.TestResources(
-            primary_credential)
-        return self._creds['primary']
-
-    def get_alt_creds(self):
-        if self._creds.get('alt'):
-            return self._creds.get('alt')
-        alt_credential = get_configured_credentials(
-            credential_type='alt_user', fill_in=False,
-            identity_version=self.identity_version)
-        self._creds['alt'] = cred_provider.TestResources(
-            alt_credential)
-        return self._creds['alt']
-
-    def clear_creds(self):
-        self._creds = {}
-
-    def get_admin_creds(self):
-        if self._creds.get('admin'):
-            return self._creds.get('admin')
-        creds = get_configured_credentials(
-            "identity_admin", fill_in=False)
-        self._creds['admin'] = cred_provider.TestResources(creds)
-        return self._creds['admin']
-
-    def get_creds_by_roles(self, roles, force_new=False):
-        msg = "Credentials being specified through the config file can not be"\
-              " used with tests that specify using credentials by roles. "\
-              "Either exclude/skip the tests doing this or use either an "\
-              "test_accounts_file or dynamic credentials."
-        raise exceptions.InvalidConfiguration(msg)
-
-    def is_role_available(self, role):
-        # NOTE(andreaf) LegacyCredentialProvider does not support credentials
-        # by role, so returning always False.
-        # Test that rely on credentials by role should use this to skip
-        # when this is credential provider is used
-        return False
-
-
 # Return the right implementation of CredentialProvider based on config
 # Dropping interface and password, as they are never used anyways
 # TODO(andreaf) Drop them from the CredentialsProvider interface completely
@@ -157,8 +73,8 @@
     # the test should be skipped else it would fail.
     identity_version = identity_version or CONF.identity.auth_version
     if CONF.auth.use_dynamic_credentials or force_tenant_isolation:
-        admin_creds = get_configured_credentials(
-            'identity_admin', fill_in=True, identity_version=identity_version)
+        admin_creds = get_configured_admin_credentials(
+            fill_in=True, identity_version=identity_version)
         return dynamic_creds.DynamicCredentialProvider(
             name=name,
             network_resources=network_resources,
@@ -172,9 +88,8 @@
                 name=name, identity_version=identity_version,
                 **_get_preprov_provider_params())
         else:
-            # Dynamic credentials are disabled, and the account file is not
-            # defined - we fall back on credentials configured in tempest.conf
-            return LegacyCredentialProvider(identity_version=identity_version)
+            raise exceptions.InvalidConfiguration(
+                'A valid credential provider is needed')
 
 
 # We want a helper function here to check and see if admin credentials
@@ -196,8 +111,8 @@
             is_admin = False
     else:
         try:
-            get_configured_credentials('identity_admin', fill_in=False,
-                                       identity_version=identity_version)
+            get_configured_admin_credentials(fill_in=False,
+                                             identity_version=identity_version)
         except exceptions.InvalidConfiguration:
             is_admin = False
     return is_admin
@@ -218,7 +133,9 @@
             identity_version=identity_version, name='check_alt',
             **_get_preprov_provider_params())
     else:
-        check_accounts = LegacyCredentialProvider(identity_version)
+        raise exceptions.InvalidConfiguration(
+            'A valid credential provider is needed')
+
     try:
         if not check_accounts.is_multi_user():
             return False
@@ -246,44 +163,32 @@
 
 # Read credentials from configuration, builds a Credentials object
 # based on the specified or configured version
-def get_configured_credentials(credential_type, fill_in=True,
-                               identity_version=None):
+def get_configured_admin_credentials(fill_in=True, identity_version=None):
     identity_version = identity_version or CONF.identity.auth_version
 
     if identity_version not in ('v2', 'v3'):
         raise exceptions.InvalidConfiguration(
             'Unsupported auth version: %s' % identity_version)
 
-    if credential_type not in CREDENTIAL_TYPES:
-        raise exceptions.InvalidCredentials()
-    conf_attributes = ['username', 'password', 'project_name']
+    conf_attributes = ['username', 'password',
+                       'project_name']
 
     if identity_version == 'v3':
         conf_attributes.append('domain_name')
     # Read the parts of credentials from config
     params = DEFAULT_PARAMS.copy()
-    section, prefix = CREDENTIAL_TYPES[credential_type]
     for attr in conf_attributes:
-        _section = getattr(CONF, section)
-        if prefix is None:
-            params[attr] = getattr(_section, attr)
-        else:
-            params[attr] = getattr(_section, prefix + "_" + attr)
-    # NOTE(andreaf) v2 API still uses tenants, so we must translate project
-    # to tenant before building the Credentials object
-    if identity_version == 'v2':
-        params['tenant_name'] = params.get('project_name')
-        params.pop('project_name', None)
+        params[attr] = getattr(CONF.auth, 'admin_' + attr)
     # Build and validate credentials. We are reading configured credentials,
     # so validate them even if fill_in is False
     credentials = get_credentials(fill_in=fill_in,
                                   identity_version=identity_version, **params)
     if not fill_in:
         if not credentials.is_valid():
-            msg = ("The %s credentials are incorrectly set in the config file."
-                   " Double check that all required values are assigned" %
-                   credential_type)
-            raise exceptions.InvalidConfiguration(msg)
+            msg = ("The admin credentials are incorrectly set in the config "
+                   "file for identity version %s. Double check that all "
+                   "required values are assigned.")
+            raise exceptions.InvalidConfiguration(msg % identity_version)
     return credentials
 
 
@@ -311,19 +216,10 @@
 # === Credential / client managers
 
 
-class ConfiguredUserManager(clients.Manager):
-    """Manager that uses user credentials for its managed client objects"""
-
-    def __init__(self, service=None):
-        super(ConfiguredUserManager, self).__init__(
-            credentials=get_configured_credentials('user'),
-            service=service)
-
-
 class AdminManager(clients.Manager):
     """Manager that uses admin credentials for its managed client objects"""
 
     def __init__(self, service=None):
         super(AdminManager, self).__init__(
-            credentials=get_configured_credentials('identity_admin'),
+            credentials=get_configured_admin_credentials(),
             service=service)
diff --git a/tempest/common/dynamic_creds.py b/tempest/common/dynamic_creds.py
index d374be4..a63af38 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -154,6 +154,20 @@
         return cred_provider.TestResources(creds)
 
     def _create_network_resources(self, tenant_id):
+        """The function creates network resources in the given tenant.
+
+        The function checks if network_resources class member is empty,
+        In case it is, it will create a network, a subnet and a router for
+        the tenant according to the given tenant id parameter.
+        Otherwise it will create a network resource according
+        to the values from network_resources dict.
+
+        :param tenant_id: The tenant id to create resources for.
+        :type tenant_id: str
+        :raises: InvalidConfiguration, Exception
+        :returns: network resources(network,subnet,router)
+        :rtype: tuple
+        """
         network = None
         subnet = None
         router = None
diff --git a/tempest/common/generator/base_generator.py b/tempest/common/generator/base_generator.py
index 3a51f2e..0647edb 100644
--- a/tempest/common/generator/base_generator.py
+++ b/tempest/common/generator/base_generator.py
@@ -169,7 +169,7 @@
             expected_result = generator_result[2]
             element = path.pop()
             if len(path) > 0:
-                schema_snip = reduce(dict.get, path, schema)
+                schema_snip = six.moves.reduce(dict.get, path, schema)
                 schema_snip[element] = invalid_snippet
             else:
                 schema[element] = invalid_snippet
diff --git a/tempest/common/preprov_creds.py b/tempest/common/preprov_creds.py
index f3df387..7350222 100644
--- a/tempest/common/preprov_creds.py
+++ b/tempest/common/preprov_creds.py
@@ -43,6 +43,11 @@
 
 class PreProvisionedCredentialProvider(cred_provider.CredentialProvider):
 
+    # Exclude from the hash fields specific to v2 or v3 identity API
+    # i.e. only include user*, project*, tenant* and password
+    HASH_CRED_FIELDS = (set(auth.KeystoneV2Credentials.ATTRIBUTES) &
+                        set(auth.KeystoneV3Credentials.ATTRIBUTES))
+
     def __init__(self, identity_version, test_accounts_file,
                  accounts_lock_dir, name=None, credentials_domain=None,
                  admin_role=None, object_storage_operator_role=None,
@@ -104,6 +109,7 @@
                       object_storage_operator_role=None,
                       object_storage_reseller_admin_role=None):
         hash_dict = {'roles': {}, 'creds': {}, 'networks': {}}
+
         # Loop over the accounts read from the yaml file
         for account in accounts:
             roles = []
@@ -116,7 +122,9 @@
             if 'resources' in account:
                 resources = account.pop('resources')
             temp_hash = hashlib.md5()
-            temp_hash.update(six.text_type(account).encode('utf-8'))
+            account_for_hash = dict((k, v) for (k, v) in six.iteritems(account)
+                                    if k in cls.HASH_CRED_FIELDS)
+            temp_hash.update(six.text_type(account_for_hash).encode('utf-8'))
             temp_hash_key = temp_hash.hexdigest()
             hash_dict['creds'][temp_hash_key] = account
             for role in roles:
@@ -219,9 +227,9 @@
         else:
             hashes = self.hash_dict['creds'].keys()
         # NOTE(mtreinish): admin is a special case because of the increased
-        # privlege set which could potentially cause issues on tests where that
-        # is not expected. So unless the admin role isn't specified do not
-        # allocate admin.
+        # privilege set which could potentially cause issues on tests where
+        # that is not expected. So unless the admin role isn't specified do
+        # not allocate admin.
         admin_hashes = self.hash_dict['roles'].get(self.admin_role,
                                                    None)
         if ((not roles or self.admin_role not in roles) and
@@ -262,13 +270,13 @@
         for _hash in self.hash_dict['creds']:
             # Comparing on the attributes that are expected in the YAML
             init_attributes = creds.get_init_attributes()
+            # Only use the attributes initially used to calculate the hash
+            init_attributes = [x for x in init_attributes if
+                               x in self.HASH_CRED_FIELDS]
             hash_attributes = self.hash_dict['creds'][_hash].copy()
-            if ('user_domain_name' in init_attributes and 'user_domain_name'
-                    not in hash_attributes):
-                # Allow for the case of domain_name populated from config
-                domain_name = self.credentials_domain
-                hash_attributes['user_domain_name'] = domain_name
-            if all([getattr(creds, k) == hash_attributes[k] for
+            # NOTE(andreaf) Not all fields may be available on all credentials
+            # so defaulting to None for that case.
+            if all([getattr(creds, k, None) == hash_attributes.get(k, None) for
                    k in init_attributes]):
                 return _hash
         raise AttributeError('Invalid credentials %s' % creds)
@@ -351,23 +359,20 @@
         return net_creds
 
     def _extend_credentials(self, creds_dict):
-        # In case of v3, adds a user_domain_name field to the creds
-        # dict if not defined
+        # Add or remove credential domain fields to fit the identity version
+        domain_fields = set(x for x in auth.KeystoneV3Credentials.ATTRIBUTES
+                            if 'domain' in x)
+        msg = 'Assuming they are valid in the default domain.'
         if self.identity_version == 'v3':
-            user_domain_fields = set(['user_domain_name', 'user_domain_id'])
-            if not user_domain_fields.intersection(set(creds_dict.keys())):
-                creds_dict['user_domain_name'] = self.credentials_domain
-        # NOTE(andreaf) In case of v2, replace project with tenant if project
-        # is provided and tenant is not
+            if not domain_fields.intersection(set(creds_dict.keys())):
+                msg = 'Using credentials %s for v3 API calls. ' + msg
+                LOG.warning(msg, self._sanitize_creds(creds_dict))
+                creds_dict['domain_name'] = self.credentials_domain
         if self.identity_version == 'v2':
-            if ('project_name' in creds_dict and
-                    'tenant_name' in creds_dict and
-                    creds_dict['project_name'] != creds_dict['tenant_name']):
-                clean_creds = self._sanitize_creds(creds_dict)
-                msg = 'Cannot specify project and tenant at the same time %s'
-                raise exceptions.InvalidCredentials(msg % clean_creds)
-            if ('project_name' in creds_dict and
-                    'tenant_name' not in creds_dict):
-                creds_dict['tenant_name'] = creds_dict['project_name']
-                creds_dict.pop('project_name')
+            if domain_fields.intersection(set(creds_dict.keys())):
+                msg = 'Using credentials %s for v2 API calls. ' + msg
+                LOG.warning(msg, self._sanitize_creds(creds_dict))
+            # Remove all valid domain attributes
+            for attr in domain_fields.intersection(set(creds_dict.keys())):
+                creds_dict.pop(attr)
         return creds_dict
diff --git a/tempest/common/utils/file_utils.py b/tempest/common/utils/file_utils.py
deleted file mode 100644
index 43083f4..0000000
--- a/tempest/common/utils/file_utils.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# 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.
-
-
-def have_effective_read_access(path):
-    try:
-        fh = open(path, "rb")
-    except IOError:
-        return False
-    fh.close()
-    return True
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 3a215a0..3f573b7 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -12,6 +12,8 @@
 
 import netaddr
 import re
+import six
+import sys
 import time
 
 from oslo_log import log as logging
@@ -19,6 +21,7 @@
 from tempest import config
 from tempest import exceptions
 from tempest.lib.common import ssh
+from tempest.lib.common.utils import misc as misc_utils
 import tempest.lib.exceptions
 
 CONF = config.CONF
@@ -26,16 +29,61 @@
 LOG = logging.getLogger(__name__)
 
 
+def debug_ssh(function):
+    """Decorator to generate extra debug info in case off SSH failure"""
+    def wrapper(self, *args, **kwargs):
+        try:
+            return function(self, *args, **kwargs)
+        except tempest.lib.exceptions.SSHTimeout:
+            try:
+                original_exception = sys.exc_info()
+                caller = misc_utils.find_test_caller() or "not found"
+                if self.server:
+                    msg = 'Caller: %s. Timeout trying to ssh to server %s'
+                    LOG.debug(msg, caller, self.server)
+                    if self.log_console and self.servers_client:
+                        try:
+                            msg = 'Console log for server %s: %s'
+                            console_log = (
+                                self.servers_client.get_console_output(
+                                    self.server['id'])['output'])
+                            LOG.debug(msg, self.server['id'], console_log)
+                        except Exception:
+                            msg = 'Could not get console_log for server %s'
+                            LOG.debug(msg, self.server['id'])
+                # re-raise the original ssh timeout exception
+                six.reraise(*original_exception)
+            finally:
+                # Delete the traceback to avoid circular references
+                _, _, trace = original_exception
+                del trace
+    return wrapper
+
+
 class RemoteClient(object):
 
-    def __init__(self, ip_address, username, password=None, pkey=None):
+    def __init__(self, ip_address, username, password=None, pkey=None,
+                 server=None, servers_client=None):
+        """Executes commands in a VM over ssh
+
+        :param ip_address: IP address to ssh to
+        :param username: ssh username
+        :param password: ssh password (optional)
+        :param pkey: ssh public key (optional)
+        :param server: server dict, used for debugging purposes
+        :param servers_client: servers client, used for debugging purposes
+        """
+        self.server = server
+        self.servers_client = servers_client
         ssh_timeout = CONF.validation.ssh_timeout
         connect_timeout = CONF.validation.connect_timeout
+        self.log_console = CONF.compute_feature_enabled.console_output
 
         self.ssh_client = ssh.Client(ip_address, username, password,
                                      ssh_timeout, pkey=pkey,
                                      channel_timeout=connect_timeout)
 
+    @debug_ssh
     def exec_command(self, cmd):
         # Shell options below add more clearness on failures,
         # path is extended for some non-cirros guest oses (centos7)
@@ -43,6 +91,7 @@
         LOG.debug("Remote command: %s" % cmd)
         return self.ssh_client.exec_command(cmd)
 
+    @debug_ssh
     def validate_authentication(self):
         """Validate ssh connection and authentication
 
diff --git a/tempest/common/utils/net_utils.py b/tempest/common/utils/net_utils.py
new file mode 100644
index 0000000..d98fb32
--- /dev/null
+++ b/tempest/common/utils/net_utils.py
@@ -0,0 +1,48 @@
+# Copyright 2016 Hewlett Packard Enterprise Development Company
+#
+# 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
+
+from tempest.lib import exceptions as lib_exc
+
+
+def get_unused_ip_addresses(ports_client, subnets_client,
+                            network_id, subnet_id, count):
+
+    """Return a list with the specified number of unused IP addresses
+
+    This method uses the given ports_client to find the specified number of
+    unused IP addresses on the given subnet using the supplied subnets_client
+    """
+
+    ports = ports_client.list_ports(network_id=network_id)['ports']
+    subnet = subnets_client.show_subnet(subnet_id)
+    ip_net = netaddr.IPNetwork(subnet['subnet']['cidr'])
+    subnet_set = netaddr.IPSet(ip_net.iter_hosts())
+    alloc_set = netaddr.IPSet()
+
+    # prune out any addresses already allocated to existing ports
+    for port in ports:
+        for fixed_ip in port.get('fixed_ips'):
+            alloc_set.add(fixed_ip['ip_address'])
+
+    av_set = subnet_set - alloc_set
+    ip_list = [str(ip) for ip in itertools.islice(av_set, count)]
+
+    if len(ip_list) != count:
+        msg = "Insufficient IP addresses available"
+        raise lib_exc.BadRequest(message=msg)
+
+    return ip_list
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index 95305f3..23d7f88 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -19,6 +19,7 @@
 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.image.v1.json import images_client as images_v1_client
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
@@ -122,42 +123,44 @@
     The client should have a show_image(image_id) method to get the image.
     The client should also have build_interval and build_timeout attributes.
     """
-    image = client.show_image(image_id)
-    # Compute image client return response wrapped in 'image' element
-    # which is not case with glance image client.
-    if 'image' in image:
-        image = image['image']
-    start = int(time.time())
+    if isinstance(client, images_v1_client.ImagesClient):
+        # The 'check_image' method is used here because the show_image method
+        # returns image details plus the image itself which is very expensive.
+        # The 'check_image' method returns just image details.
+        show_image = client.check_image
+    else:
+        show_image = client.show_image
 
-    while image['status'] != status:
-        time.sleep(client.build_interval)
-        image = client.show_image(image_id)
-        # Compute image client return response wrapped in 'image' element
-        # which is not case with glance image client.
+    current_status = 'An unknown status'
+    start = int(time.time())
+    while int(time.time()) - start < client.build_timeout:
+        image = show_image(image_id)
+        # Compute image client returns response wrapped in 'image' element
+        # which is not case with Glance image client.
         if 'image' in image:
             image = image['image']
-        status_curr = image['status']
-        if status_curr == 'ERROR':
+
+        current_status = image['status']
+        if current_status == status:
+            return
+        if current_status.lower() == 'killed':
+            raise exceptions.ImageKilledException(image_id=image_id,
+                                                  status=status)
+        if current_status.lower() == 'error':
             raise exceptions.AddImageException(image_id=image_id)
 
-        # check the status again to avoid a false negative where we hit
-        # the timeout at the same time that the image reached the expected
-        # status
-        if status_curr == status:
-            return
+        time.sleep(client.build_interval)
 
-        if int(time.time()) - start >= client.build_timeout:
-            message = ('Image %(image_id)s failed to reach %(status)s state'
-                       '(current state %(status_curr)s) '
-                       'within the required time (%(timeout)s s).' %
-                       {'image_id': image_id,
-                        'status': status,
-                        'status_curr': status_curr,
-                        'timeout': client.build_timeout})
-            caller = misc_utils.find_test_caller()
-            if caller:
-                message = '(%s) %s' % (caller, message)
-            raise exceptions.TimeoutException(message)
+    message = ('Image %(image_id)s failed to reach %(status)s state '
+               '(current state %(current_status)s) within the required '
+               'time (%(timeout)s s).' % {'image_id': image_id,
+                                          'status': status,
+                                          'current_status': current_status,
+                                          'timeout': client.build_timeout})
+    caller = misc_utils.find_test_caller()
+    if caller:
+        message = '(%s) %s' % (caller, message)
+    raise exceptions.TimeoutException(message)
 
 
 def wait_for_volume_status(client, volume_id, status):
diff --git a/tempest/config.py b/tempest/config.py
index b787b19..71b25d0 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -15,6 +15,7 @@
 
 from __future__ import print_function
 
+import functools
 import logging as std_logging
 import os
 import tempfile
@@ -22,6 +23,7 @@
 from oslo_concurrency import lockutils
 from oslo_config import cfg
 from oslo_log import log as logging
+import testtools
 
 from tempest.test_discover import plugins
 
@@ -91,7 +93,7 @@
                     "create users and projects",
                deprecated_group='identity'),
     cfg.StrOpt('admin_project_name',
-               help="Project name to use for an  administrative user. This is "
+               help="Project name to use for an administrative user. This is "
                     "needed for authenticating requests made by project "
                     "isolation to create users and projects",
                deprecated_opts=[cfg.DeprecatedOpt('admin_tenant_name',
@@ -99,7 +101,7 @@
                                 cfg.DeprecatedOpt('admin_tenant_name',
                                                   group='identity')]),
     cfg.StrOpt('admin_password',
-               help="Password to use for an  administrative user. This is "
+               help="Password to use for an administrative user. This is "
                     "needed for authenticating requests made by project "
                     "isolation to create users and projects",
                secret=True,
@@ -158,41 +160,9 @@
                         'publicURL', 'adminURL', 'internalURL'],
                help="The endpoint type to use for OpenStack Identity "
                     "(Keystone) API v3"),
-    cfg.StrOpt('username',
-               help="Username to use for Nova API requests.",
-               deprecated_for_removal=True),
-    cfg.StrOpt('project_name',
-               deprecated_name='tenant_name',
-               help="Project name to use for Nova API requests.",
-               deprecated_for_removal=True),
     cfg.StrOpt('admin_role',
                default='admin',
                help="Role required to administrate keystone."),
-    cfg.StrOpt('password',
-               help="API key to use when authenticating.",
-               secret=True,
-               deprecated_for_removal=True),
-    cfg.StrOpt('domain_name',
-               help="Domain name for authentication (Keystone V3)."
-                    "The same domain applies to user and project",
-               deprecated_for_removal=True),
-    cfg.StrOpt('alt_username',
-               help="Username of alternate user to use for Nova API "
-                    "requests.",
-               deprecated_for_removal=True),
-    cfg.StrOpt('alt_project_name',
-               deprecated_name='alt_tenant_name',
-               help="Alternate user's Project name to use for Nova API "
-                    "requests.",
-               deprecated_for_removal=True),
-    cfg.StrOpt('alt_password',
-               help="API key to use when authenticating as alternate user.",
-               secret=True,
-               deprecated_for_removal=True),
-    cfg.StrOpt('alt_domain_name',
-               help="Alternate domain name for authentication (Keystone V3)."
-                    "The same domain applies to user and project",
-               deprecated_for_removal=True),
     cfg.StrOpt('default_domain_id',
                default='default',
                help="ID of the default domain"),
@@ -400,14 +370,6 @@
                      'encrypted volume to a running server instance? This may '
                      'depend on the combination of compute_driver in nova and '
                      'the volume_driver(s) in cinder.'),
-    # TODO(mriedem): Remove allow_duplicate_networks once kilo-eol happens
-    # since the option was removed from nova in Liberty and is the default
-    # behavior starting in Liberty.
-    cfg.BoolOpt('allow_duplicate_networks',
-                default=False,
-                help='Does the test environment support creating instances '
-                     'with multiple ports on the same network? This is only '
-                     'valid when using Neutron.'),
     cfg.BoolOpt('config_drive',
                 default=True,
                 help='Enable special configuration drive with metadata.'),
@@ -670,7 +632,7 @@
     cfg.StrOpt('network_for_ssh',
                default='public',
                help="Network used for SSH connections. Ignored if "
-                    "use_floatingip_for_ssh=true or run_validation=false.",
+                    "connect_method=floating or run_validation=false.",
                deprecated_opts=[cfg.DeprecatedOpt('network_for_ssh',
                                                   group='compute')]),
 ]
@@ -700,22 +662,10 @@
                choices=['public', 'admin', 'internal',
                         'publicURL', 'adminURL', 'internalURL'],
                help="The endpoint type to use for the volume service."),
-    cfg.StrOpt('backend1_name',
-               default='',
-               help='Name of the backend1 (must be declared in cinder.conf)',
-               deprecated_for_removal=True),
-    cfg.StrOpt('backend2_name',
-               default='',
-               help='Name of the backend2 (must be declared in cinder.conf)',
-               deprecated_for_removal=True),
     cfg.ListOpt('backend_names',
                 default=['BACKEND_1', 'BACKEND_2'],
                 help='A list of backend names separated by comma. '
-                     'The backend name must be declared in cinder.conf',
-                deprecated_opts=[cfg.DeprecatedOpt('BACKEND_1',
-                                                   group='volume'),
-                                 cfg.DeprecatedOpt('BACKEND_2',
-                                                   group='volume')]),
+                     'The backend name must be declared in cinder.conf'),
     cfg.StrOpt('storage_protocol',
                default='iSCSI',
                help='Backend protocol to target when creating volume types'),
@@ -892,50 +842,6 @@
 ]
 
 
-telemetry_group = cfg.OptGroup(name='telemetry',
-                               title='Telemetry Service Options')
-
-TelemetryGroup = [
-    cfg.StrOpt('catalog_type',
-               default='metering',
-               help="Catalog type of the Telemetry service."),
-    cfg.StrOpt('endpoint_type',
-               default='publicURL',
-               choices=['public', 'admin', 'internal',
-                        'publicURL', 'adminURL', 'internalURL'],
-               help="The endpoint type to use for the telemetry service."),
-    cfg.BoolOpt('too_slow_to_test',
-                default=True,
-                deprecated_for_removal=True,
-                help="This variable is used as flag to enable "
-                     "notification tests")
-]
-
-alarming_group = cfg.OptGroup(name='alarming',
-                              title='Alarming Service Options')
-
-AlarmingGroup = [
-    cfg.StrOpt('catalog_type',
-               default='alarming',
-               help="Catalog type of the Alarming service."),
-    cfg.StrOpt('endpoint_type',
-               default='publicURL',
-               choices=['public', 'admin', 'internal',
-                        'publicURL', 'adminURL', 'internalURL'],
-               help="The endpoint type to use for the alarming service."),
-]
-
-
-telemetry_feature_group = cfg.OptGroup(name='telemetry-feature-enabled',
-                                       title='Enabled Ceilometer Features')
-
-TelemetryFeaturesGroup = [
-    cfg.BoolOpt('events',
-                default=False,
-                help="Runs Ceilometer event-related tests"),
-]
-
-
 dashboard_group = cfg.OptGroup(name="dashboard",
                                title="Dashboard options")
 
@@ -1080,12 +986,6 @@
     cfg.BoolOpt('heat',
                 default=False,
                 help="Whether or not Heat is expected to be available"),
-    cfg.BoolOpt('ceilometer',
-                default=True,
-                help="Whether or not Ceilometer is expected to be available"),
-    cfg.BoolOpt('aodh',
-                default=False,
-                help="Whether or not Aodh is expected to be available"),
     cfg.BoolOpt('horizon',
                 default=True,
                 help="Whether or not Horizon is expected to be available"),
@@ -1159,7 +1059,7 @@
                                     'shelve, snapshot, and suspend')
 
 
-# NOTE(deva): Ironic tests have been ported to tempest-lib. New config options
+# NOTE(deva): Ironic tests have been ported to tempest.lib. New config options
 #             should be added to ironic/ironic_tempest_plugin/config.py.
 #             However, these options need to remain here for testing stable
 #             branches until Liberty release reaches EOL.
@@ -1231,9 +1131,6 @@
     (object_storage_feature_group, ObjectStoreFeaturesGroup),
     (database_group, DatabaseGroup),
     (orchestration_group, OrchestrationGroup),
-    (telemetry_group, TelemetryGroup),
-    (telemetry_feature_group, TelemetryFeaturesGroup),
-    (alarming_group, AlarmingGroup),
     (dashboard_group, DashboardGroup),
     (data_processing_group, DataProcessingGroup),
     (data_processing_feature_group, DataProcessingFeaturesGroup),
@@ -1302,8 +1199,6 @@
             'object-storage-feature-enabled']
         self.database = _CONF.database
         self.orchestration = _CONF.orchestration
-        self.telemetry = _CONF.telemetry
-        self.telemetry_feature_enabled = _CONF['telemetry-feature-enabled']
         self.dashboard = _CONF.dashboard
         self.data_processing = _CONF['data-processing']
         self.data_processing_feature_enabled = _CONF[
@@ -1315,12 +1210,6 @@
         self.baremetal = _CONF.baremetal
         self.input_scenario = _CONF['input-scenario']
         self.negative = _CONF.negative
-        _CONF.set_default('domain_name',
-                          self.auth.default_credentials_domain_name,
-                          group='identity')
-        _CONF.set_default('alt_domain_name',
-                          self.auth.default_credentials_domain_name,
-                          group='identity')
         logging.tempest_set_log_file('tempest.log')
 
     def __init__(self, parse_conf=True, config_path=None):
@@ -1397,3 +1286,72 @@
 
 
 CONF = TempestConfigProxy()
+
+
+def skip_unless_config(*args):
+    """Decorator to raise a skip if a config opt doesn't exist or is False
+
+    :param str group: The first arg, the option group to check
+    :param str name: The second arg, the option name to check
+    :param str msg: Optional third arg, the skip msg to use if a skip is raised
+    :raises testtools.TestCaseskipException: If the specified config option
+        doesn't exist or it exists and evaluates to False
+    """
+    def decorator(f):
+        group = args[0]
+        name = args[1]
+
+        @functools.wraps(f)
+        def wrapper(self, *func_args, **func_kwargs):
+            if not hasattr(CONF, group):
+                msg = "Config group %s doesn't exist" % group
+                raise testtools.TestCase.skipException(msg)
+
+            conf_group = getattr(CONF, group)
+            if not hasattr(conf_group, name):
+                msg = "Config option %s.%s doesn't exist" % (group,
+                                                             name)
+                raise testtools.TestCase.skipException(msg)
+
+            value = getattr(conf_group, name)
+            if not value:
+                if len(args) == 3:
+                    msg = args[2]
+                else:
+                    msg = "Config option %s.%s is false" % (group,
+                                                            name)
+                raise testtools.TestCase.skipException(msg)
+            return f(self, *func_args, **func_kwargs)
+        return wrapper
+    return decorator
+
+
+def skip_if_config(*args):
+    """Raise a skipException if a config exists and is True
+
+    :param str group: The first arg, the option group to check
+    :param str name: The second arg, the option name to check
+    :param str msg: Optional third arg, the skip msg to use if a skip is raised
+    :raises testtools.TestCase.skipException: If the specified config option
+        exists and evaluates to True
+    """
+    def decorator(f):
+        group = args[0]
+        name = args[1]
+
+        @functools.wraps(f)
+        def wrapper(self, *func_args, **func_kwargs):
+            if hasattr(CONF, group):
+                conf_group = getattr(CONF, group)
+                if hasattr(conf_group, name):
+                    value = getattr(conf_group, name)
+                    if value:
+                        if len(args) == 3:
+                            msg = args[2]
+                        else:
+                            msg = "Config option %s.%s is false" % (group,
+                                                                    name)
+                        raise testtools.TestCase.skipException(msg)
+            return f(self, *func_args, **func_kwargs)
+        return wrapper
+    return decorator
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index b8e052f..92f335f 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -116,7 +116,7 @@
 
 
 # NOTE(andreaf) This exception is added here to facilitate the migration
-# of get_network_from_name and preprov_creds to tempest-lib, and it should
+# of get_network_from_name and preprov_creds to tempest.lib, and it should
 # be migrated along with them
 class InvalidTestResource(TempestException):
     message = "%(name) is not a valid %(type), or the name is ambiguous"
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index d0e1fcb..aff9dee 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -19,8 +19,7 @@
 
 
 PYTHON_CLIENTS = ['cinder', 'glance', 'keystone', 'nova', 'swift', 'neutron',
-                  'trove', 'ironic', 'savanna', 'heat', 'ceilometer',
-                  'sahara']
+                  'trove', 'ironic', 'savanna', 'heat', 'sahara']
 
 PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS))
 TEST_DEFINITION = re.compile(r'^\s*def test.*')
@@ -141,7 +140,7 @@
     """
     if TESTTOOLS_SKIP_DECORATOR.match(logical_line):
         yield (0, "T109: Cannot use testtools.skip decorator; instead use "
-               "decorators.skip_because from tempest-lib")
+               "decorators.skip_because from tempest.lib")
 
 
 def _common_service_clients_check(logical_line, physical_line, filename,
diff --git a/tempest/hacking/ignored_list_T110.txt b/tempest/hacking/ignored_list_T110.txt
index 380c173..4ef9012 100644
--- a/tempest/hacking/ignored_list_T110.txt
+++ b/tempest/hacking/ignored_list_T110.txt
@@ -1,6 +1,4 @@
 ./tempest/services/object_storage/object_client.py
-./tempest/services/telemetry/json/alarming_client.py
-./tempest/services/telemetry/json/telemetry_client.py
 ./tempest/services/volume/base/base_qos_client.py
 ./tempest/services/volume/base/base_backups_client.py
 ./tempest/services/baremetal/base.py
diff --git a/tempest/api/telemetry/__init__.py b/tempest/lib/api_schema/response/compute/v2_19/__init__.py
similarity index 100%
copy from tempest/api/telemetry/__init__.py
copy to tempest/lib/api_schema/response/compute/v2_19/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_19/servers.py b/tempest/lib/api_schema/response/compute/v2_19/servers.py
new file mode 100644
index 0000000..883839e
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_19/servers.py
@@ -0,0 +1,49 @@
+# 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import servers as serversv21
+from tempest.lib.api_schema.response.compute.v2_9 import servers as serversv29
+
+get_server = copy.deepcopy(serversv29.get_server)
+get_server['response_body']['properties']['server'][
+    'properties'].update({'description': {'type': ['string', 'null']}})
+get_server['response_body']['properties']['server'][
+    'required'].append('description')
+
+list_servers_detail = copy.deepcopy(serversv29.list_servers_detail)
+list_servers_detail['response_body']['properties']['servers']['items'][
+    'properties'].update({'description': {'type': ['string', 'null']}})
+list_servers_detail['response_body']['properties']['servers']['items'][
+    'required'].append('description')
+
+update_server = copy.deepcopy(serversv21.update_server)
+update_server['response_body']['properties']['server'][
+    'properties'].update({'description': {'type': ['string', 'null']}})
+update_server['response_body']['properties']['server'][
+    'required'].append('description')
+
+rebuild_server = copy.deepcopy(serversv21.rebuild_server)
+rebuild_server['response_body']['properties']['server'][
+    'properties'].update({'description': {'type': ['string', 'null']}})
+rebuild_server['response_body']['properties']['server'][
+    'required'].append('description')
+
+rebuild_server_with_admin_pass = copy.deepcopy(
+    serversv21.rebuild_server_with_admin_pass)
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+    'properties'].update({'description': {'type': ['string', 'null']}})
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+    'required'].append('description')
diff --git a/tempest/api/telemetry/__init__.py b/tempest/lib/api_schema/response/compute/v2_9/__init__.py
similarity index 100%
copy from tempest/api/telemetry/__init__.py
copy to tempest/lib/api_schema/response/compute/v2_9/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_9/servers.py b/tempest/lib/api_schema/response/compute/v2_9/servers.py
new file mode 100644
index 0000000..e9b7249
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_9/servers.py
@@ -0,0 +1,29 @@
+# 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 copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import servers
+
+get_server = copy.deepcopy(servers.get_server)
+get_server['response_body']['properties']['server'][
+    'properties'].update({'locked': {'type': 'boolean'}})
+get_server['response_body']['properties']['server'][
+    'required'].append('locked')
+
+list_servers_detail = copy.deepcopy(servers.list_servers_detail)
+list_servers_detail['response_body']['properties']['servers']['items'][
+    'properties'].update({'locked': {'type': 'boolean'}})
+list_servers_detail['response_body']['properties']['servers']['items'][
+    'required'].append('locked')
diff --git a/tempest/lib/auth.py b/tempest/lib/auth.py
index a6833be..974ba82 100644
--- a/tempest/lib/auth.py
+++ b/tempest/lib/auth.py
@@ -68,10 +68,16 @@
 class AuthProvider(object):
     """Provide authentication"""
 
-    def __init__(self, credentials):
+    SCOPES = set(['project'])
+
+    def __init__(self, credentials, scope='project'):
         """Auth provider __init__
 
         :param credentials: credentials for authentication
+        :param scope: the default scope to be used by the credential providers
+                      when requesting a token. Valid values depend on the
+                      AuthProvider class implementation, and are defined in
+                      the set SCOPES. Default value is 'project'.
         """
         if self.check_credentials(credentials):
             self.credentials = credentials
@@ -88,6 +94,8 @@
                 raise TypeError("credentials object is of type %s, which is"
                                 " not a valid Credentials object type." %
                                 credentials.__class__.__name__)
+        self._scope = None
+        self.scope = scope
         self.cache = None
         self.alt_auth_data = None
         self.alt_part = None
@@ -123,8 +131,14 @@
 
     @property
     def auth_data(self):
+        """Auth data for set scope"""
         return self.get_auth()
 
+    @property
+    def scope(self):
+        """Scope used in auth requests"""
+        return self._scope
+
     @auth_data.deleter
     def auth_data(self):
         self.clear_auth()
@@ -139,7 +153,7 @@
         """Forces setting auth.
 
         Forces setting auth, ignores cache if it exists.
-        Refills credentials
+        Refills credentials.
         """
         self.cache = self._get_auth()
         self._fill_credentials(self.cache[1])
@@ -222,6 +236,19 @@
         """Extracts the base_url based on provided filters"""
         return
 
+    @scope.setter
+    def scope(self, value):
+        """Set the scope to be used in token requests
+
+        :param scope: scope to be used. If the scope is different, clear caches
+        """
+        if value not in self.SCOPES:
+            raise exceptions.InvalidScope(
+                scope=value, auth_provider=self.__class__.__name__)
+        if value != self.scope:
+            self.clear_auth()
+            self._scope = value
+
 
 class KeystoneAuthProvider(AuthProvider):
 
@@ -231,17 +258,18 @@
 
     def __init__(self, credentials, auth_url,
                  disable_ssl_certificate_validation=None,
-                 ca_certs=None, trace_requests=None):
-        super(KeystoneAuthProvider, self).__init__(credentials)
+                 ca_certs=None, trace_requests=None, scope='project'):
+        super(KeystoneAuthProvider, self).__init__(credentials, scope)
         self.dsvm = disable_ssl_certificate_validation
         self.ca_certs = ca_certs
         self.trace_requests = trace_requests
+        self.auth_url = auth_url
         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
+            auth_data = self.get_auth()
         token, _ = auth_data
         base_url = self.base_url(filters=filters, auth_data=auth_data)
         # build authenticated request
@@ -265,6 +293,11 @@
 
     @abc.abstractmethod
     def _auth_params(self):
+        """Auth parameters to be passed to the token request
+
+        By default all fields available in Credentials are passed to the
+        token request. Scope may affect this.
+        """
         return
 
     def _get_auth(self):
@@ -292,10 +325,17 @@
         return expiry
 
     def get_token(self):
-        return self.auth_data[0]
+        return self.get_auth()[0]
 
 
 class KeystoneV2AuthProvider(KeystoneAuthProvider):
+    """Provides authentication based on the Identity V2 API
+
+    The Keystone Identity V2 API defines both unscoped and project scoped
+    tokens. This auth provider only implements 'project'.
+    """
+
+    SCOPES = set(['project'])
 
     def _auth_client(self, auth_url):
         return json_v2id.TokenClient(
@@ -303,6 +343,10 @@
             ca_certs=self.ca_certs, trace_requests=self.trace_requests)
 
     def _auth_params(self):
+        """Auth parameters to be passed to the token request
+
+        All fields available in Credentials are passed to the token request.
+        """
         return dict(
             user=self.credentials.username,
             password=self.credentials.password,
@@ -332,7 +376,7 @@
         - skip_path: take just the base URL
         """
         if auth_data is None:
-            auth_data = self.auth_data
+            auth_data = self.get_auth()
         token, _auth_data = auth_data
         service = filters.get('service')
         region = filters.get('region')
@@ -365,6 +409,9 @@
 
 
 class KeystoneV3AuthProvider(KeystoneAuthProvider):
+    """Provides authentication based on the Identity V3 API"""
+
+    SCOPES = set(['project', 'domain', 'unscoped', None])
 
     def _auth_client(self, auth_url):
         return json_v3id.V3TokenClient(
@@ -372,20 +419,36 @@
             ca_certs=self.ca_certs, trace_requests=self.trace_requests)
 
     def _auth_params(self):
-        return dict(
+        """Auth parameters to be passed to the token request
+
+        Fields available in Credentials are passed to the token request,
+        depending on the value of scope. Valid values for scope are: "project",
+        "domain". Any other string (e.g. "unscoped") or None will lead to an
+        unscoped token request.
+        """
+
+        auth_params = 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,
+            password=self.credentials.password,
             auth_data=True)
 
+        if self.scope == 'project':
+            auth_params.update(
+                project_domain_id=self.credentials.project_domain_id,
+                project_domain_name=self.credentials.project_domain_name,
+                project_id=self.credentials.project_id,
+                project_name=self.credentials.project_name)
+
+        if self.scope == 'domain':
+            auth_params.update(
+                domain_id=self.credentials.domain_id,
+                domain_name=self.credentials.domain_name)
+
+        return auth_params
+
     def _fill_credentials(self, auth_data_body):
         # project or domain, depending on the scope
         project = auth_data_body.get('project', None)
@@ -422,6 +485,10 @@
     def base_url(self, filters, auth_data=None):
         """Base URL from catalog
 
+        If scope is not 'project', it may be that there is not catalog in
+        the auth_data. In such case, as long as the requested service is
+        'identity', we can use the original auth URL to build the base_url.
+
         Filters can be:
         - service: compute, image, etc
         - region: the service region
@@ -430,7 +497,7 @@
         - skip_path: take just the base URL
         """
         if auth_data is None:
-            auth_data = self.auth_data
+            auth_data = self.get_auth()
         token, _auth_data = auth_data
         service = filters.get('service')
         region = filters.get('region')
@@ -442,14 +509,20 @@
         if 'URL' in endpoint_type:
             endpoint_type = endpoint_type.replace('URL', '')
         _base_url = None
-        catalog = _auth_data['catalog']
+        catalog = _auth_data.get('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)
+            if len(catalog) == 0 and service == 'identity':
+                # NOTE(andreaf) If there's no catalog at all and the service
+                # is identity, it's a valid use case. Having a non-empty
+                # catalog with no identity in it is not valid instead.
+                return apply_url_filters(self.auth_url, filters)
+            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]
@@ -465,7 +538,7 @@
         # 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)
+            raise exceptions.EndpointNotFound(service)
         return apply_url_filters(_base_url, filters)
 
     def is_expired(self, auth_data):
@@ -532,6 +605,7 @@
     """
 
     ATTRIBUTES = []
+    COLLISIONS = []
 
     def __init__(self, **kwargs):
         """Enforce the available attributes at init time (only).
@@ -543,6 +617,13 @@
         self._apply_credentials(kwargs)
 
     def _apply_credentials(self, attr):
+        for (key1, key2) in self.COLLISIONS:
+            val1 = attr.get(key1)
+            val2 = attr.get(key2)
+            if val1 and val2 and val1 != val2:
+                msg = ('Cannot have conflicting values for %s and %s' %
+                       (key1, key2))
+                raise exceptions.InvalidCredentials(msg)
         for key in attr.keys():
             if key in self.ATTRIBUTES:
                 setattr(self, key, attr[key])
@@ -600,7 +681,33 @@
 class KeystoneV2Credentials(Credentials):
 
     ATTRIBUTES = ['username', 'password', 'tenant_name', 'user_id',
-                  'tenant_id']
+                  'tenant_id', 'project_id', 'project_name']
+    COLLISIONS = [('project_name', 'tenant_name'), ('project_id', 'tenant_id')]
+
+    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 __setattr__(self, key, value):
+        # NOTE(andreaf) In order to ease the migration towards 'project' we
+        # support v2 credentials configured with 'project' and translate it
+        # to tenant on the fly. The original kwargs are stored for clients
+        # that may rely on them. We also set project when tenant is defined
+        # so clients can rely on project being part of credentials.
+        parent = super(KeystoneV2Credentials, self)
+        # for project_* set tenant only
+        if key == 'project_id':
+            parent.__setattr__('tenant_id', value)
+        elif key == 'project_name':
+            parent.__setattr__('tenant_name', value)
+        if key == 'tenant_id':
+            parent.__setattr__('project_id', value)
+        elif key == 'tenant_name':
+            parent.__setattr__('project_name', value)
+        # trigger default behaviour for all attributes
+        parent.__setattr__(key, value)
 
     def is_valid(self):
         """Check of credentials (no API call)
@@ -611,9 +718,6 @@
         return None not in (self.username, self.password)
 
 
-COLLISIONS = [('project_name', 'tenant_name'), ('project_id', 'tenant_id')]
-
-
 class KeystoneV3Credentials(Credentials):
     """Credentials suitable for the Keystone Identity V3 API"""
 
@@ -621,16 +725,7 @@
                   'project_domain_id', 'project_domain_name', 'project_id',
                   'project_name', 'tenant_id', 'tenant_name', 'user_domain_id',
                   'user_domain_name', 'user_id']
-
-    def _apply_credentials(self, attr):
-        for (key1, key2) in COLLISIONS:
-            val1 = attr.get(key1)
-            val2 = attr.get(key2)
-            if val1 and val2 and val1 != val2:
-                msg = ('Cannot have conflicting values for %s and %s' %
-                       (key1, key2))
-                raise exceptions.InvalidCredentials(msg)
-        super(KeystoneV3Credentials, self)._apply_credentials(attr)
+    COLLISIONS = [('project_name', 'tenant_name'), ('project_id', 'tenant_id')]
 
     def __setattr__(self, key, value):
         parent = super(KeystoneV3Credentials, self)
@@ -669,7 +764,7 @@
     def is_valid(self):
         """Check of credentials (no API call)
 
-        Valid combinations of v3 credentials (excluding token, scope)
+        Valid combinations of v3 credentials (excluding token)
         - User id, password (optional domain)
         - User name, password and its domain id/name
         For the scope, valid combinations are:
diff --git a/tempest/lib/cli/base.py b/tempest/lib/cli/base.py
index 54f35f4..20b2a3d 100644
--- a/tempest/lib/cli/base.py
+++ b/tempest/lib/cli/base.py
@@ -119,7 +119,7 @@
         :param merge_stderr: if True the stderr buffer is merged into stdout
         :type merge_stderr: boolean
         """
-        flags += ' --endpoint-type %s' % endpoint_type
+        flags += ' --os-endpoint-type %s' % endpoint_type
         return self.cmd_with_auth(
             'nova', action, flags, params, fail_ok, merge_stderr)
 
@@ -247,7 +247,7 @@
         :param merge_stderr: if True the stderr buffer is merged into stdout
         :type merge_stderr: boolean
         """
-        flags += ' --endpoint-type %s' % endpoint_type
+        flags += ' --os-endpoint-type %s' % endpoint_type
         return self.cmd_with_auth(
             'cinder', action, flags, params, fail_ok, merge_stderr)
 
diff --git a/tempest/lib/cmd/skip_tracker.py b/tempest/lib/cmd/skip_tracker.py
index b7d6a24..f35b14c 100755
--- a/tempest/lib/cmd/skip_tracker.py
+++ b/tempest/lib/cmd/skip_tracker.py
@@ -48,7 +48,7 @@
 
 
 def find_skips(start):
-    """Find the entire list of skiped tests.
+    """Find the entire list of skipped tests.
 
     Returns a list of tuples (method, bug) that represent
     test methods that have been decorated to skip because of
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index d001d27..179db17 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -15,6 +15,7 @@
 #    under the License.
 
 import collections
+import email.utils
 import logging as real_logging
 import re
 import time
@@ -242,7 +243,8 @@
                 details = pattern.format(read_code, expected_code)
                 raise exceptions.InvalidHttpSuccessCode(details)
 
-    def post(self, url, body, headers=None, extra_headers=False):
+    def post(self, url, body, headers=None, extra_headers=False,
+             chunked=False):
         """Send a HTTP POST request using keystone auth
 
         :param str url: the relative url to send the post request to
@@ -252,11 +254,12 @@
                                    returned by the get_headers() method are to
                                    be used but additional headers are needed in
                                    the request pass them in as a dict.
+        :param bool chunked: sends the body with chunked encoding
         :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)
+        return self.request('POST', url, extra_headers, headers, body, chunked)
 
     def get(self, url, headers=None, extra_headers=False):
         """Send a HTTP GET request using keystone service catalog and auth
@@ -305,7 +308,7 @@
         """
         return self.request('PATCH', url, extra_headers, headers, body)
 
-    def put(self, url, body, headers=None, extra_headers=False):
+    def put(self, url, body, headers=None, extra_headers=False, chunked=False):
         """Send a HTTP PUT request using keystone service catalog and auth
 
         :param str url: the relative url to send the post request to
@@ -315,11 +318,12 @@
                                    returned by the get_headers() method are to
                                    be used but additional headers are needed in
                                    the request pass them in as a dict.
+        :param bool chunked: sends the body with chunked encoding
         :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)
+        return self.request('PUT', url, extra_headers, headers, body, chunked)
 
     def head(self, url, headers=None, extra_headers=False):
         """Send a HTTP HEAD request using keystone service catalog and auth
@@ -400,6 +404,10 @@
                           caller_name=None, extra=None):
         if 'X-Auth-Token' in req_headers:
             req_headers['X-Auth-Token'] = '<omitted>'
+        # A shallow copy is sufficient
+        resp_log = resp.copy()
+        if 'x-subject-token' in resp_log:
+            resp_log['x-subject-token'] = '<omitted>'
         log_fmt = """Request - Headers: %s
         Body: %s
     Response - Headers: %s
@@ -409,7 +417,7 @@
             log_fmt % (
                 str(req_headers),
                 self._safe_body(req_body),
-                str(resp),
+                str(resp_log),
                 self._safe_body(resp_body)),
             extra=extra)
 
@@ -515,7 +523,7 @@
         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):
+    def _request(self, method, url, headers=None, body=None, chunked=False):
         """A simple HTTP request interface."""
         # Authenticate the request with the auth provider
         req_url, req_headers, req_body = self.auth_provider.auth_request(
@@ -525,7 +533,9 @@
         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)
+            req_url, method, headers=req_headers, body=req_body,
+            chunked=chunked
+        )
         end = time.time()
         self._log_request(method, req_url, resp, secs=(end - start),
                           req_headers=req_headers, req_body=req_body,
@@ -536,7 +546,7 @@
 
         return resp, resp_body
 
-    def raw_request(self, url, method, headers=None, body=None):
+    def raw_request(self, url, method, headers=None, body=None, chunked=False):
         """Send a raw HTTP request without the keystone catalog or auth
 
         This method sends a HTTP request in the same manner as the request()
@@ -549,17 +559,18 @@
         :param str headers: Headers to use for the request if none are specifed
                             the headers
         :param str body: Body to send with the request
+        :param bool chunked: sends the body with chunked encoding
         :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)
+        return self.http_obj.request(url, method, headers=headers,
+                                     body=body, chunked=chunked)
 
     def request(self, method, url, extra_headers=False, headers=None,
-                body=None):
+                body=None, chunked=False):
         """Send a HTTP request with keystone auth and using the catalog
 
         This method will send an HTTP request using keystone auth in the
@@ -585,6 +596,7 @@
                              get_headers() method are used. If the request
                              explicitly requires no headers use an empty dict.
         :param str body: Body to send with the request
+        :param bool chunked: sends the body with chunked encoding
         :rtype: tuple
         :return: a tuple with the first entry containing the response headers
                  and the second the response body
@@ -624,8 +636,8 @@
             except (ValueError, TypeError):
                 headers = self.get_headers()
 
-        resp, resp_body = self._request(method, url,
-                                        headers=headers, body=body)
+        resp, resp_body = self._request(method, url, headers=headers,
+                                        body=body, chunked=chunked)
 
         while (resp.status == 413 and
                'retry-after' in resp and
@@ -633,7 +645,10 @@
                     resp, self._parse_resp(resp_body)) and
                 retry < MAX_RECURSION_DEPTH):
             retry += 1
-            delay = int(resp['retry-after'])
+            delay = self._get_retry_after_delay(resp)
+            self.LOG.debug(
+                "Sleeping %s seconds based on retry-after header", delay
+            )
             time.sleep(delay)
             resp, resp_body = self._request(method, url,
                                             headers=headers, body=body)
@@ -641,6 +656,51 @@
                             resp, resp_body)
         return resp, resp_body
 
+    def _get_retry_after_delay(self, resp):
+        """Extract the delay from the retry-after header.
+
+        This supports both integer and HTTP date formatted retry-after headers
+        per RFC 2616.
+
+        :param resp: The response containing the retry-after headers
+        :rtype: int
+        :return: The delay in seconds, clamped to be at least 1 second
+        :raises ValueError: On failing to parse the delay
+        """
+        delay = None
+        try:
+            delay = int(resp['retry-after'])
+        except (ValueError, KeyError):
+            pass
+
+        try:
+            retry_timestamp = self._parse_http_date(resp['retry-after'])
+            date_timestamp = self._parse_http_date(resp['date'])
+            delay = int(retry_timestamp - date_timestamp)
+        except (ValueError, OverflowError, KeyError):
+            pass
+
+        if delay is None:
+            raise ValueError(
+                "Failed to parse retry-after header %r as either int or "
+                "HTTP-date." % resp.get('retry-after')
+            )
+
+        # Retry-after headers do not have sub-second precision. Clients may
+        # receive a delay of 0. After sleeping 0 seconds, we would (likely) hit
+        # another 413. To avoid this, always sleep at least 1 second.
+        return max(1, delay)
+
+    def _parse_http_date(self, val):
+        """Parse an HTTP date, like 'Fri, 31 Dec 1999 23:59:59 GMT'.
+
+        Return an epoch timestamp (float), as returned by time.mktime().
+        """
+        parts = email.utils.parsedate(val)
+        if not parts:
+            raise ValueError("Failed to parse date %s" % val)
+        return time.mktime(parts)
+
     def _error_checker(self, method, url,
                        headers, body, resp, resp_body):
 
@@ -767,10 +827,7 @@
         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')
+        return 'exceed' in resp_body.get('message', 'blabla')
 
     def wait_for_resource_deletion(self, id):
         """Waits for a resource to be deleted
diff --git a/tempest/lib/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py
index 01b6477..45e5067 100644
--- a/tempest/lib/common/utils/data_utils.py
+++ b/tempest/lib/common/utils/data_utils.py
@@ -19,6 +19,8 @@
 import string
 import uuid
 
+import six.moves
+
 
 def rand_uuid():
     """Generate a random UUID string
@@ -39,7 +41,7 @@
 
 
 def rand_name(name='', prefix=None):
-    """Generate a random name that inclues a random number
+    """Generate a random name that includes a random number
 
     :param str name: The name that you want to include
     :param str prefix: The prefix that you want to include
@@ -81,7 +83,7 @@
 
 
 def rand_url():
-    """Generate a random url that inclues a random number
+    """Generate a random url that includes a random number
 
     :return: a random url. The format is 'https://url-<random number>.com'.
              (e.g. 'https://url-154876201.com')
@@ -121,6 +123,18 @@
     return ':'.join(["%02x" % x for x in mac])
 
 
+def rand_infiniband_guid_address():
+    """Generate an Infiniband GUID address
+
+    :return: an random Infiniband GUID address
+    :rtype: string
+    """
+    guid = []
+    for i in range(8):
+        guid.append("%02x" % random.randint(0x00, 0xff))
+    return ':'.join(guid)
+
+
 def parse_image_id(image_ref):
     """Return the image id from a given image ref
 
@@ -184,3 +198,10 @@
     except TypeError:
         raise TypeError('Bad prefix type for generate IPv6 address by '
                         'EUI-64: %s' % cidr)
+
+
+# Courtesy of http://stackoverflow.com/a/312464
+def chunkify(sequence, chunksize):
+    """Yield successive chunks from `sequence`."""
+    for i in six.moves.xrange(0, len(sequence), chunksize):
+        yield sequence[i:i + chunksize]
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
index b9b2ae9..259bbbb 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -207,6 +207,10 @@
     message = "Invalid Credentials"
 
 
+class InvalidScope(TempestException):
+    message = "Invalid Scope %(scope)s for %(auth_provider)s"
+
+
 class SSHTimeout(TempestException):
     message = ("Connection to the %(host)s via SSH timed out.\n"
                "User: %(user)s, Password: %(password)s")
diff --git a/tempest/lib/services/compute/base_compute_client.py b/tempest/lib/services/compute/base_compute_client.py
index 9161abb..433c94c 100644
--- a/tempest/lib/services/compute/base_compute_client.py
+++ b/tempest/lib/services/compute/base_compute_client.py
@@ -48,9 +48,9 @@
         return headers
 
     def request(self, method, url, extra_headers=False, headers=None,
-                body=None):
+                body=None, chunked=False):
         resp, resp_body = super(BaseComputeClient, self).request(
-            method, url, extra_headers, headers, body)
+            method, url, extra_headers, headers, body, chunked)
         if (COMPUTE_MICROVERSION and
             COMPUTE_MICROVERSION != api_version_utils.LATEST_MICROVERSION):
             api_version_utils.assert_version_header_matches_request(
@@ -67,11 +67,13 @@
 
         :param schema_versions_info: List of dict which provides schema
                                      information with range of valid versions.
-        Example -
-        schema_versions_info = [
-            {'min': None, 'max': '2.1', 'schema': schemav21},
-            {'min': '2.2', 'max': '2.9', 'schema': schemav22},
-            {'min': '2.10', 'max': None, 'schema': schemav210}]
+
+        Example::
+
+         schema_versions_info = [
+             {'min': None, 'max': '2.1', 'schema': schemav21},
+             {'min': '2.2', 'max': '2.9', 'schema': schemav22},
+             {'min': '2.10', 'max': None, 'schema': schemav210}]
         """
         schema = None
         version = api_version_request.APIVersionRequest(COMPUTE_MICROVERSION)
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index a37f167..8e4eca1 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -20,11 +20,17 @@
 from six.moves.urllib import parse as urllib
 
 from tempest.lib.api_schema.response.compute.v2_1 import servers as schema
+from tempest.lib.api_schema.response.compute.v2_19 import servers as schemav219
+from tempest.lib.api_schema.response.compute.v2_9 import servers as schemav29
 from tempest.lib.common import rest_client
 from tempest.lib.services.compute import base_compute_client
 
 
 class ServersClient(base_compute_client.BaseComputeClient):
+    schema_versions_info = [
+        {'min': None, 'max': '2.8', 'schema': schema},
+        {'min': '2.9', 'max': '2.18', 'schema': schemav29},
+        {'min': '2.19', 'max': None, 'schema': schemav219}]
 
     def __init__(self, auth_provider, service, region,
                  enable_instance_password=True, **kwargs):
@@ -55,7 +61,7 @@
         post_body = {'server': body}
 
         if hints:
-            post_body = dict(post_body.items() + hints.items())
+            post_body.update(hints)
 
         post_body = json.dumps(post_body)
         resp, body = self.post('servers', post_body)
@@ -88,6 +94,7 @@
         post_body = json.dumps({'server': kwargs})
         resp, body = self.put("servers/%s" % server_id, post_body)
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.update_server, resp, body)
         return rest_client.ResponseBody(resp, body)
 
@@ -95,6 +102,7 @@
         """Get server details."""
         resp, body = self.get("servers/%s" % server_id)
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.get_server, resp, body)
         return rest_client.ResponseBody(resp, body)
 
@@ -114,6 +122,7 @@
         """
 
         url = 'servers'
+        schema = self.get_schema(self.schema_versions_info)
         _schema = schema.list_servers
 
         if detail:
@@ -209,6 +218,7 @@
         kwargs['imageRef'] = image_ref
         if 'disk_config' in kwargs:
             kwargs['OS-DCF:diskConfig'] = kwargs.pop('disk_config')
+        schema = self.get_schema(self.schema_versions_info)
         if self.enable_instance_password:
             rebuild_schema = schema.rebuild_server_with_admin_pass
         else:
diff --git a/tempest/lib/services/identity/v2/token_client.py b/tempest/lib/services/identity/v2/token_client.py
index 0350175..5716027 100644
--- a/tempest/lib/services/identity/v2/token_client.py
+++ b/tempest/lib/services/identity/v2/token_client.py
@@ -75,8 +75,12 @@
         return rest_client.ResponseBody(resp, body['access'])
 
     def request(self, method, url, extra_headers=False, headers=None,
-                body=None):
-        """A simple HTTP request interface."""
+                body=None, chunked=False):
+        """A simple HTTP request interface.
+
+        Note: this overloads the `request` method from the parent class and
+        thus must implement the same method signature.
+        """
         if headers is None:
             headers = self.get_headers(accept_type="json")
         elif extra_headers:
diff --git a/tempest/lib/services/identity/v3/token_client.py b/tempest/lib/services/identity/v3/token_client.py
index f342a49..964d43f 100644
--- a/tempest/lib/services/identity/v3/token_client.py
+++ b/tempest/lib/services/identity/v3/token_client.py
@@ -122,8 +122,12 @@
         return rest_client.ResponseBody(resp, body)
 
     def request(self, method, url, extra_headers=False, headers=None,
-                body=None):
-        """A simple HTTP request interface."""
+                body=None, chunked=False):
+        """A simple HTTP request interface.
+
+        Note: this overloads the `request` method from the parent class and
+        thus must implement the same method signature.
+        """
         if headers is None:
             # Always accept 'json', for xml token client too.
             # Because XML response is not easily
diff --git a/tempest/manager.py b/tempest/manager.py
index c97e0d1..cafa5b9 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -28,13 +28,14 @@
     and a client object for a test case to use in performing actions.
     """
 
-    def __init__(self, credentials):
+    def __init__(self, credentials, scope='project'):
         """Initialization of base manager class
 
         Credentials to be used within the various client classes managed by the
         Manager object must be defined.
 
         :param credentials: type Credentials or TestResources
+        :param scope: default scope for tokens produced by the auth provider
         """
         self.credentials = credentials
         # Check if passed or default credentials are valid
@@ -48,7 +49,8 @@
         else:
             creds = self.credentials
         # Creates an auth provider for the credentials
-        self.auth_provider = get_auth_provider(creds, pre_auth=True)
+        self.auth_provider = get_auth_provider(creds, pre_auth=True,
+                                               scope=scope)
 
 
 def get_auth_provider_class(credentials):
@@ -58,7 +60,7 @@
         return auth.KeystoneV2AuthProvider, CONF.identity.uri
 
 
-def get_auth_provider(credentials, pre_auth=False):
+def get_auth_provider(credentials, pre_auth=False, scope='project'):
     default_params = {
         'disable_ssl_certificate_validation':
             CONF.identity.disable_ssl_certificate_validation,
@@ -71,6 +73,7 @@
     auth_provider_class, auth_url = get_auth_provider_class(
         credentials)
     _auth_provider = auth_provider_class(credentials, auth_url,
+                                         scope=scope,
                                          **default_params)
     if pre_auth:
         _auth_provider.set_auth()
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 988ee1a..7389722 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -29,7 +29,7 @@
 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
+from tempest.scenario import network_resources
 import tempest.test
 
 CONF = config.CONF
@@ -459,13 +459,13 @@
         LOG.debug("Creating a snapshot image for server: %s", server['name'])
         image = _images_client.create_image(server['id'], name=name)
         image_id = image.response['location'].split('images/')[1]
-        _image_client.wait_for_image_status(image_id, 'active')
+        waiters.wait_for_image_status(_image_client, image_id, 'active')
         self.addCleanup_with_wait(
             waiter_callable=_image_client.wait_for_resource_deletion,
             thing_id=image_id, thing_id_param='id',
             cleanup_callable=self.delete_wrapper,
             cleanup_args=[_image_client.delete_image, image_id])
-        snapshot_image = _image_client.get_image_meta(image_id)
+        snapshot_image = _image_client.check_image(image_id)
 
         bdm = snapshot_image.get('properties', {}).get('block_device_mapping')
         if bdm:
@@ -648,7 +648,7 @@
         """
         if CONF.validation.connect_method == 'floating':
             # The tests calling this method don't have a floating IP
-            # and can't make use of the validattion resources. So the
+            # and can't make use of the validation resources. So the
             # method is creating the floating IP there.
             return self.create_floating_ip(server)['ip']
         elif CONF.validation.connect_method == 'fixed':
@@ -697,7 +697,7 @@
             tenant_id = networks_client.tenant_id
         name = data_utils.rand_name(namestart)
         result = networks_client.create_network(name=name, tenant_id=tenant_id)
-        network = net_resources.DeletableNetwork(
+        network = network_resources.DeletableNetwork(
             networks_client=networks_client, routers_client=routers_client,
             **result['network'])
         self.assertEqual(network.name, name)
@@ -790,7 +790,7 @@
                 if not is_overlapping_cidr:
                     raise
         self.assertIsNotNone(result, 'Unable to allocate tenant network')
-        subnet = net_resources.DeletableSubnet(
+        subnet = network_resources.DeletableSubnet(
             subnets_client=subnets_client,
             routers_client=routers_client, **result['subnet'])
         self.assertEqual(subnet.cidr, str_cidr)
@@ -807,8 +807,8 @@
             network_id=network_id,
             **kwargs)
         self.assertIsNotNone(result, 'Unable to allocate port')
-        port = net_resources.DeletablePort(ports_client=client,
-                                           **result['port'])
+        port = network_resources.DeletablePort(ports_client=client,
+                                               **result['port'])
         self.addCleanup(self.delete_wrapper, port.delete)
         return port
 
@@ -838,7 +838,7 @@
         net = self._list_networks(name=network_name)
         self.assertNotEqual(len(net), 0,
                             "Unable to get network by name: %s" % network_name)
-        return net_resources.AttributeDict(net[0])
+        return network_resources.AttributeDict(net[0])
 
     def create_floating_ip(self, thing, external_network_id=None,
                            port_id=None, client=None):
@@ -857,7 +857,7 @@
             tenant_id=thing['tenant_id'],
             fixed_ip_address=ip4
         )
-        floating_ip = net_resources.DeletableFloatingIp(
+        floating_ip = network_resources.DeletableFloatingIp(
             client=client,
             **result['floatingip'])
         self.addCleanup(self.delete_wrapper, floating_ip.delete)
@@ -878,8 +878,8 @@
     def check_floating_ip_status(self, floating_ip, status):
         """Verifies floatingip reaches the given status
 
-        :param floating_ip: net_resources.DeletableFloatingIp floating IP to
-        to check status
+        :param floating_ip: network_resources.DeletableFloatingIp floating
+        IP to check status
         :param status: target status
         :raises: AssertionError if status doesn't match
         """
@@ -991,7 +991,7 @@
                        description=sg_desc)
         sg_dict['tenant_id'] = tenant_id
         result = client.create_security_group(**sg_dict)
-        secgroup = net_resources.DeletableSecurityGroup(
+        secgroup = network_resources.DeletableSecurityGroup(
             client=client, routers_client=self.routers_client,
             **result['security_group']
         )
@@ -1016,8 +1016,8 @@
         ]
         msg = "No default security group for tenant %s." % (tenant_id)
         self.assertTrue(len(sgs) > 0, msg)
-        return net_resources.DeletableSecurityGroup(client=client,
-                                                    **sgs[0])
+        return network_resources.DeletableSecurityGroup(client=client,
+                                                        **sgs[0])
 
     def _create_security_group_rule(self, secgroup=None,
                                     sec_group_rules_client=None,
@@ -1055,7 +1055,7 @@
         ruleset.update(kwargs)
 
         sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
-        sg_rule = net_resources.DeletableSecurityGroupRule(
+        sg_rule = network_resources.DeletableSecurityGroupRule(
             client=sec_group_rules_client,
             **sg_rule['security_group_rule']
         )
@@ -1069,10 +1069,11 @@
                                         security_groups_client=None):
         """Create loginable security group rule
 
-        These rules are intended to permit inbound ssh and icmp
-        traffic from all sources, so no group_id is provided.
-        Setting a group_id would only permit traffic from ports
-        belonging to the same security group.
+        This function will create:
+        1. egress and ingress tcp port 22 allow rule in order to allow ssh
+        access for ipv4.
+        2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
+        3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
         """
 
         if security_group_rules_client is None:
@@ -1135,7 +1136,7 @@
         network_id = CONF.network.public_network_id
         if router_id:
             body = client.show_router(router_id)
-            return net_resources.AttributeDict(**body['router'])
+            return network_resources.AttributeDict(**body['router'])
         elif network_id:
             router = self._create_router(client, tenant_id)
             router.set_gateway(network_id)
@@ -1154,8 +1155,8 @@
         result = client.create_router(name=name,
                                       admin_state_up=True,
                                       tenant_id=tenant_id)
-        router = net_resources.DeletableRouter(routers_client=client,
-                                               **result['router'])
+        router = network_resources.DeletableRouter(routers_client=client,
+                                                   **result['router'])
         self.assertEqual(router.name, name)
         self.addCleanup(self.delete_wrapper, router.delete)
         return router
diff --git a/tempest/services/network/resources.py b/tempest/scenario/network_resources.py
similarity index 98%
rename from tempest/services/network/resources.py
rename to tempest/scenario/network_resources.py
index 329c54d..667476f 100644
--- a/tempest/services/network/resources.py
+++ b/tempest/scenario/network_resources.py
@@ -76,7 +76,7 @@
         """Waits for a network resource to reach a status
 
         @param fetch: the callable to be used to query the resource status
-        @type fecth: callable that takes no parameters and returns the resource
+        @type fetch: callable that takes no parameters and returns the resource
         @param status: the status that the resource has to reach
         @type status: String
         """
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index dfa4815..f0ae223 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -24,7 +24,7 @@
 from tempest import config
 from tempest import exceptions
 from tempest.scenario import manager
-from tempest.services.network import resources as net_resources
+from tempest.scenario import network_resources
 from tempest import test
 
 CONF = config.CONF
@@ -269,8 +269,9 @@
                 "Old port: %s. Number of new ports: %d" % (
                     CONF.network.build_timeout, old_port,
                     len(self.new_port_list)))
-        new_port = net_resources.DeletablePort(ports_client=self.ports_client,
-                                               **self.new_port_list[0])
+        new_port = network_resources.DeletablePort(
+            ports_client=self.ports_client,
+            **self.new_port_list[0])
 
         def check_new_nic():
             new_nic_list = self._get_server_nics(ssh_client)
@@ -686,8 +687,9 @@
         unschedule_router = (self.admin_manager.network_agents_client.
                              delete_router_from_l3_agent)
 
-        agent_list = set(a["id"] for a in
-                         self._list_agents(agent_type="L3 agent"))
+        agent_list_alive = set(a["id"] for a in
+                               self._list_agents(agent_type="L3 agent") if
+                               a["alive"] is True)
         self._setup_network_and_servers()
 
         # NOTE(kevinbenton): we have to use the admin credentials to check
@@ -702,7 +704,7 @@
         # remove resource from agents
         hosting_agents = set(a["id"] for a in
                              list_hosts(self.router.id)['agents'])
-        no_migration = agent_list == hosting_agents
+        no_migration = agent_list_alive == hosting_agents
         LOG.info("Router will be assigned to {mig} hosting agent".
                  format(mig="the same" if no_migration else "a new"))
 
@@ -722,7 +724,7 @@
 
         # schedule resource to new agent
         target_agent = list(hosting_agents if no_migration else
-                            agent_list - hosting_agents)[0]
+                            agent_list_alive - hosting_agents)[0]
         schedule_router(target_agent,
                         router_id=self.router['id'])
         self.assertEqual(
@@ -752,10 +754,10 @@
         The test steps are :
         1. Create a new network.
         2. Connect (hotplug) the VM to a new network.
-        3. Check the VM can ping the DHCP interface of this network.
+        3. Check the VM can ping a server on the new network ("peer")
         4. Spoof the mac address of the new VM interface.
         5. Check the Security Group enforces mac spoofing and blocks pings via
-           spoofed interface (VM cannot ping the DHCP interface).
+           spoofed interface (VM cannot ping the peer).
         6. Disable port-security of the spoofed port- set the flag to false.
         7. Retest 3rd step and check that the Security Group allows pings via
         the spoofed interface.
@@ -776,18 +778,18 @@
         ssh_client = self.get_remote_client(fip.floating_ip_address,
                                             private_key=private_key)
         spoof_nic = ssh_client.get_nic_name_by_mac(spoof_port["mac_address"])
-        dhcp_ports = self._list_ports(device_owner="network:dhcp",
-                                      network_id=self.new_net["id"])
-        new_net_dhcp = dhcp_ports[0]["fixed_ips"][0]["ip_address"]
-        self._check_remote_connectivity(ssh_client, dest=new_net_dhcp,
+        name = data_utils.rand_name('peer')
+        peer = self._create_server(name, self.new_net)
+        peer_address = peer['addresses'][self.new_net.name][0]['addr']
+        self._check_remote_connectivity(ssh_client, dest=peer_address,
                                         nic=spoof_nic, should_succeed=True)
         ssh_client.set_mac_address(spoof_nic, spoof_mac)
         new_mac = ssh_client.get_mac_address(nic=spoof_nic)
         self.assertEqual(spoof_mac, new_mac)
-        self._check_remote_connectivity(ssh_client, dest=new_net_dhcp,
+        self._check_remote_connectivity(ssh_client, dest=peer_address,
                                         nic=spoof_nic, should_succeed=False)
         self.ports_client.update_port(spoof_port["id"],
                                       port_security_enabled=False,
                                       security_groups=[])
-        self._check_remote_connectivity(ssh_client, dest=new_net_dhcp,
+        self._check_remote_connectivity(ssh_client, dest=peer_address,
                                         nic=spoof_nic, should_succeed=True)
diff --git a/tempest/scenario/test_object_storage_telemetry_middleware.py b/tempest/scenario/test_object_storage_telemetry_middleware.py
deleted file mode 100644
index eee4d3d..0000000
--- a/tempest/scenario/test_object_storage_telemetry_middleware.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# Copyright 2014 Red Hat
-#
-# 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 tempest import config
-from tempest.scenario import manager
-from tempest import test
-
-CONF = config.CONF
-
-LOG = logging.getLogger(__name__)
-
-# Loop for up to 120 seconds waiting on notifications
-# NOTE(chdent): The choice of 120 seconds is fairly
-# arbitrary: Long enough to give the notifications the
-# chance to travel across a highly latent bus but not
-# so long as to allow excessive latency to never be visible.
-# TODO(chdent): Ideally this value would come from configuration.
-NOTIFICATIONS_WAIT = 120
-NOTIFICATIONS_SLEEP = 1
-
-
-class TestObjectStorageTelemetry(manager.ObjectStorageScenarioTest):
-    """Test that swift uses the ceilometer middleware.
-
-     * create container.
-     * upload a file to the created container.
-     * retrieve the file from the created container.
-     * wait for notifications from ceilometer.
-    """
-
-    @classmethod
-    def skip_checks(cls):
-        super(TestObjectStorageTelemetry, cls).skip_checks()
-        if not CONF.service_available.ceilometer:
-            skip_msg = ("%s skipped as ceilometer is not available" %
-                        cls.__name__)
-            raise cls.skipException(skip_msg)
-
-    @classmethod
-    def setup_clients(cls):
-        super(TestObjectStorageTelemetry, cls).setup_clients()
-        cls.telemetry_client = cls.os_operator.telemetry_client
-
-    def _confirm_notifications(self, container_name, obj_name):
-        # NOTE: Loop seeking for appropriate notifications about the containers
-        # and objects sent to swift.
-
-        def _check_samples():
-            # NOTE: Return True only if we have notifications about some
-            # containers and some objects and the notifications are about
-            # the expected containers and objects.
-            # Otherwise returning False will case _check_samples to be
-            # called again.
-            results = self.telemetry_client.list_samples(
-                'storage.objects.incoming.bytes')
-            LOG.debug('got samples %s', results)
-
-            # Extract container info from samples.
-            containers, objects = [], []
-            for sample in results:
-                meta = sample['resource_metadata']
-                if meta.get('container') and meta['container'] != 'None':
-                    containers.append(meta['container'])
-                elif (meta.get('target.metadata:container') and
-                      meta['target.metadata:container'] != 'None'):
-                    containers.append(meta['target.metadata:container'])
-
-                if meta.get('object') and meta['object'] != 'None':
-                    objects.append(meta['object'])
-                elif (meta.get('target.metadata:object') and
-                      meta['target.metadata:object'] != 'None'):
-                    objects.append(meta['target.metadata:object'])
-
-            return (container_name in containers and obj_name in objects)
-
-        self.assertTrue(test.call_until_true(_check_samples,
-                                             NOTIFICATIONS_WAIT,
-                                             NOTIFICATIONS_SLEEP),
-                        'Correct notifications were not received after '
-                        '%s seconds.' % NOTIFICATIONS_WAIT)
-
-    @test.idempotent_id('6d6b88e5-3e38-41bc-b34a-79f713a6cb84')
-    @test.services('object_storage', 'telemetry')
-    def test_swift_middleware_notifies(self):
-        container_name = self.create_container()
-        obj_name, _ = self.upload_object_to_container(container_name)
-        self._confirm_notifications(container_name, obj_name)
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index 4b932ce..504d72b 100644
--- a/tempest/scenario/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -31,7 +31,7 @@
     """The test suite for server advanced operations
 
     This test case stresses some advanced server instance operations:
-     * Resizing an instance
+     * Resizing a volume-backed instance
      * Sequence suspend resume
     """
 
@@ -50,10 +50,10 @@
     @test.idempotent_id('e6c28180-7454-4b59-b188-0257af08a63b')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize is not available.')
-    @test.services('compute')
-    def test_resize_server_confirm(self):
+    @test.services('compute', 'volume')
+    def test_resize_volume_backed_server_confirm(self):
         # We create an instance for use in this test
-        instance = self.create_server(wait_until='ACTIVE')
+        instance = self.create_server(wait_until='ACTIVE', volume_backed=True)
         instance_id = instance['id']
         resize_flavor = CONF.compute.flavor_ref_alt
         LOG.debug("Resizing instance %s from flavor %s to flavor %s",
diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py
index 77de47e..6d3ecd4 100644
--- a/tempest/scenario/test_shelve_instance.py
+++ b/tempest/scenario/test_shelve_instance.py
@@ -15,6 +15,7 @@
 
 import testtools
 
+from tempest.common import compute
 from tempest.common import waiters
 from tempest import config
 from tempest.scenario import manager
@@ -35,18 +36,9 @@
     """
 
     def _shelve_then_unshelve_server(self, server):
-        self.servers_client.shelve_server(server['id'])
-        offload_time = CONF.compute.shelved_offload_time
-        if offload_time >= 0:
-            waiters.wait_for_server_status(self.servers_client, server['id'],
-                                           'SHELVED_OFFLOADED',
-                                           extra_timeout=offload_time)
-        else:
-            waiters.wait_for_server_status(self.servers_client,
-                                           server['id'], 'SHELVED')
-            self.servers_client.shelve_offload_server(server['id'])
-            waiters.wait_for_server_status(self.servers_client, server['id'],
-                                           'SHELVED_OFFLOADED')
+        compute.shelve_server(self.servers_client, server['id'],
+                              force_shelve_offload=True)
+
         self.servers_client.unshelve_server(server['id'])
         waiters.wait_for_server_status(self.servers_client, server['id'],
                                        'ACTIVE')
diff --git a/tempest/services/identity/v3/json/projects_client.py b/tempest/services/identity/v3/json/projects_client.py
index dc553d0..97e43df 100644
--- a/tempest/services/identity/v3/json/projects_client.py
+++ b/tempest/services/identity/v3/json/projects_client.py
@@ -23,17 +23,15 @@
     api_version = "v3"
 
     def create_project(self, name, **kwargs):
-        """Creates a project."""
-        description = kwargs.get('description', None)
-        en = kwargs.get('enabled', True)
-        domain_id = kwargs.get('domain_id', 'default')
-        post_body = {
-            'description': description,
-            'domain_id': domain_id,
-            'enabled': en,
-            'name': name
-        }
-        post_body = json.dumps({'project': post_body})
+        """Create a Project.
+
+        Available params: see http://developer.openstack.org/
+                          api-ref-identity-v3.html#createProject
+
+        """
+        # Include the project name to the kwargs parameters
+        kwargs['name'] = name
+        post_body = json.dumps({'project': kwargs})
         resp, body = self.post('projects', post_body)
         self.expected_success(201, resp.status)
         body = json.loads(body)
@@ -49,19 +47,13 @@
         return rest_client.ResponseBody(resp, body)
 
     def update_project(self, project_id, **kwargs):
-        body = self.show_project(project_id)['project']
-        name = kwargs.get('name', body['name'])
-        desc = kwargs.get('description', body['description'])
-        en = kwargs.get('enabled', body['enabled'])
-        domain_id = kwargs.get('domain_id', body['domain_id'])
-        post_body = {
-            'id': project_id,
-            'name': name,
-            'description': desc,
-            'enabled': en,
-            'domain_id': domain_id,
-        }
-        post_body = json.dumps({'project': post_body})
+        """Update a Project.
+
+        Available params: see http://developer.openstack.org/
+                          api-ref-identity-v3.html#updateProject
+
+        """
+        post_body = json.dumps({'project': kwargs})
         resp, body = self.patch('projects/%s' % project_id, post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
diff --git a/tempest/services/image/v1/json/images_client.py b/tempest/services/image/v1/json/images_client.py
index e29ff89..a36075f 100644
--- a/tempest/services/image/v1/json/images_client.py
+++ b/tempest/services/image/v1/json/images_client.py
@@ -16,7 +16,6 @@
 import copy
 import errno
 import os
-import time
 
 from oslo_log import log as logging
 from oslo_serialization import jsonutils as json
@@ -24,9 +23,7 @@
 from six.moves.urllib import parse as urllib
 
 from tempest.common import glance_http
-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__)
@@ -198,7 +195,8 @@
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
-    def get_image_meta(self, image_id):
+    def check_image(self, image_id):
+        """Check image metadata."""
         url = 'v1/images/%s' % image_id
         resp, __ = self.head(url)
         self.expected_success(200, resp.status)
@@ -206,6 +204,7 @@
         return rest_client.ResponseBody(resp, body)
 
     def show_image(self, image_id):
+        """Get image details plus the image itself."""
         url = 'v1/images/%s' % image_id
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
@@ -213,7 +212,7 @@
 
     def is_resource_deleted(self, id):
         try:
-            if self.get_image_meta(id)['status'] == 'deleted':
+            if self.check_image(id)['status'] == 'deleted':
                 return True
         except lib_exc.NotFound:
             return True
@@ -256,40 +255,3 @@
         resp, __ = self.delete(url)
         self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp)
-
-    # NOTE(afazekas): just for the wait function
-    def _get_image_status(self, image_id):
-        meta = self.get_image_meta(image_id)
-        status = meta['status']
-        return status
-
-    # NOTE(afazkas): Wait reinvented again. It is not in the correct layer
-    def wait_for_image_status(self, image_id, status):
-        """Waits for a Image to reach a given status."""
-        start_time = time.time()
-        old_value = value = self._get_image_status(image_id)
-        while True:
-            dtime = time.time() - start_time
-            time.sleep(self.build_interval)
-            if value != old_value:
-                LOG.info('Value transition from "%s" to "%s"'
-                         'in %d second(s).', old_value,
-                         value, dtime)
-            if value == status:
-                return value
-
-            if value == 'killed':
-                raise exceptions.ImageKilledException(image_id=image_id,
-                                                      status=status)
-            if dtime > self.build_timeout:
-                message = ('Time Limit Exceeded! (%ds)'
-                           'while waiting for %s, '
-                           'but we got %s.' %
-                           (self.build_timeout, status, value))
-                caller = misc_utils.find_test_caller()
-                if caller:
-                    message = '(%s) %s' % (caller, message)
-                raise exceptions.TimeoutException(message)
-            time.sleep(self.build_interval)
-            old_value = value
-            value = self._get_image_status(image_id)
diff --git a/tempest/services/image/v2/json/images_client.py b/tempest/services/image/v2/json/images_client.py
index 4e037af..a61f31d 100644
--- a/tempest/services/image/v2/json/images_client.py
+++ b/tempest/services/image/v2/json/images_client.py
@@ -21,10 +21,10 @@
 from tempest.lib import exceptions as lib_exc
 
 
-class ImagesClientV2(rest_client.RestClient):
+class ImagesClient(rest_client.RestClient):
 
     def __init__(self, auth_provider, catalog_type, region, **kwargs):
-        super(ImagesClientV2, self).__init__(
+        super(ImagesClient, self).__init__(
             auth_provider, catalog_type, region, **kwargs)
         self._http = None
         self.dscv = kwargs.get("disable_ssl_certificate_validation")
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 78bda5d..33dba6e 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -18,6 +18,7 @@
 from six.moves.urllib import parse as urlparse
 
 from tempest.lib.common import rest_client
+from tempest.lib import exceptions
 
 
 class ObjectClient(rest_client.RestClient):
@@ -148,56 +149,94 @@
         self.expected_success(201, resp.status)
         return resp, body
 
-    def put_object_with_chunk(self, container, name, contents, chunk_size):
-        """Put an object with Transfer-Encoding header"""
-        if self.base_url is None:
-            self._set_auth()
+    def put_object_with_chunk(self, container, name, contents):
+        """Put an object with Transfer-Encoding header
 
+        :param container: name of the container
+        :type container: string
+        :param name: name of the object
+        :type name: string
+        :param contents: object data
+        :type contents: iterable
+        """
         headers = {'Transfer-Encoding': 'chunked'}
         if self.token:
             headers['X-Auth-Token'] = self.token
 
-        conn = put_object_connection(self.base_url, container, name, contents,
-                                     chunk_size, headers)
-
-        resp = conn.getresponse()
-        body = resp.read()
-
-        resp_headers = {}
-        for header, value in resp.getheaders():
-            resp_headers[header.lower()] = value
+        url = "%s/%s" % (container, name)
+        resp, body = self.put(
+            url, headers=headers,
+            body=contents,
+            chunked=True
+        )
 
         self._error_checker('PUT', None, headers, contents, resp, body)
         self.expected_success(201, resp.status)
-        return resp.status, resp.reason, resp_headers
+        return resp.status, resp.reason, resp
 
     def create_object_continue(self, container, object_name,
                                data, metadata=None):
-        """Create storage object."""
+        """Put an object using Expect:100-continue"""
         headers = {}
         if metadata:
             for key in metadata:
                 headers[str(key)] = metadata[key]
 
-        if not data:
-            headers['content-length'] = '0'
-
-        if self.base_url is None:
-            self._set_auth()
         headers['X-Auth-Token'] = self.token
+        headers['content-length'] = 0 if data is None else len(data)
+        headers['Expect'] = '100-continue'
 
-        conn = put_object_connection(self.base_url, str(container),
-                                     str(object_name), data, None, headers)
+        parsed = urlparse.urlparse(self.base_url)
+        path = str(parsed.path) + "/"
+        path += "%s/%s" % (str(container), str(object_name))
 
+        conn = create_connection(parsed)
+
+        # Send the PUT request and the headers including the "Expect" header
+        conn.putrequest('PUT', path)
+
+        for header, value in six.iteritems(headers):
+            conn.putheader(header, value)
+        conn.endheaders()
+
+        # Read the 100 status prior to sending the data
         response = conn.response_class(conn.sock,
                                        strict=conn.strict,
                                        method=conn._method)
-        version, status, reason = response._read_status()
-        resp = {'version': version,
-                'status': str(status),
-                'reason': reason}
+        _, status, _ = response._read_status()
 
-        return resp
+        # toss the CRLF at the end of the response
+        response._safe_read(2)
+
+        # Expecting a 100 here, if not close and throw an exception
+        if status != 100:
+            conn.close()
+            pattern = "%s %s" % (
+                """Unexpected http success status code {0}.""",
+                """The expected status code is {1}""")
+            details = pattern.format(status, 100)
+            raise exceptions.UnexpectedResponseCode(details)
+
+        # If a continue was received go ahead and send the data
+        # and get the final response
+        conn.send(data)
+
+        resp = conn.getresponse()
+
+        return resp.status, resp.reason
+
+
+def create_connection(parsed_url):
+    """Helper function to create connection with httplib
+
+    :param parsed_url: parsed url of the remote location
+    """
+    if parsed_url.scheme == 'https':
+        conn = httplib.HTTPSConnection(parsed_url.netloc)
+    else:
+        conn = httplib.HTTPConnection(parsed_url.netloc)
+
+    return conn
 
 
 def put_object_connection(base_url, container, name, contents=None,
@@ -216,43 +255,19 @@
     :param query_string: if set will be appended with '?' to generated path
     """
     parsed = urlparse.urlparse(base_url)
-    if parsed.scheme == 'https':
-        conn = httplib.HTTPSConnection(parsed.netloc)
-    else:
-        conn = httplib.HTTPConnection(parsed.netloc)
+
     path = str(parsed.path) + "/"
     path += "%s/%s" % (str(container), str(name))
 
+    conn = create_connection(parsed)
+
     if query_string:
         path += '?' + query_string
     if headers:
         headers = dict(headers)
     else:
         headers = {}
-    if hasattr(contents, 'read'):
-        conn.putrequest('PUT', path)
-        for header, value in six.iteritems(headers):
-            conn.putheader(header, value)
-        if 'Content-Length' not in headers:
-            if 'Transfer-Encoding' not in headers:
-                conn.putheader('Transfer-Encoding', 'chunked')
-            conn.endheaders()
-            chunk = contents.read(chunk_size)
-            while chunk:
-                conn.send('%x\r\n%s\r\n' % (len(chunk), chunk))
-                chunk = contents.read(chunk_size)
-            conn.send('0\r\n\r\n')
-        else:
-            conn.endheaders()
-            left = headers['Content-Length']
-            while left > 0:
-                size = chunk_size
-                if size > left:
-                    size = left
-                chunk = contents.read(size)
-                conn.send(chunk)
-                left -= len(chunk)
-    else:
-        conn.request('PUT', path, contents, headers)
+
+    conn.request('PUT', path, contents, headers)
 
     return conn
diff --git a/tempest/services/telemetry/__init__.py b/tempest/services/telemetry/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/telemetry/__init__.py
+++ /dev/null
diff --git a/tempest/services/telemetry/json/__init__.py b/tempest/services/telemetry/json/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/telemetry/json/__init__.py
+++ /dev/null
diff --git a/tempest/services/telemetry/json/alarming_client.py b/tempest/services/telemetry/json/alarming_client.py
deleted file mode 100644
index 703efdf..0000000
--- a/tempest/services/telemetry/json/alarming_client.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# Copyright 2014 OpenStack Foundation
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from oslo_serialization import jsonutils as json
-from six.moves.urllib import parse as urllib
-
-from tempest.lib.common import rest_client
-
-
-class AlarmingClient(rest_client.RestClient):
-
-    version = '2'
-    uri_prefix = "v2"
-
-    def deserialize(self, body):
-        return json.loads(body.replace("\n", ""))
-
-    def serialize(self, body):
-        return json.dumps(body)
-
-    def list_alarms(self, query=None):
-        uri = '%s/alarms' % self.uri_prefix
-        uri_dict = {}
-        if query:
-            uri_dict = {'q.field': query[0],
-                        'q.op': query[1],
-                        'q.value': query[2]}
-        if uri_dict:
-            uri += "?%s" % urllib.urlencode(uri_dict)
-        resp, body = self.get(uri)
-        self.expected_success(200, resp.status)
-        body = self.deserialize(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 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 rest_client.ResponseBodyList(resp, body)
-
-    def delete_alarm(self, alarm_id):
-        uri = "%s/alarms/%s" % (self.uri_prefix, alarm_id)
-        resp, body = self.delete(uri)
-        self.expected_success(204, resp.status)
-        if body:
-            body = self.deserialize(body)
-        return rest_client.ResponseBody(resp, body)
-
-    def create_alarm(self, **kwargs):
-        uri = "%s/alarms" % self.uri_prefix
-        body = self.serialize(kwargs)
-        resp, body = self.post(uri, body)
-        self.expected_success(201, resp.status)
-        body = self.deserialize(body)
-        return rest_client.ResponseBody(resp, body)
-
-    def update_alarm(self, alarm_id, **kwargs):
-        uri = "%s/alarms/%s" % (self.uri_prefix, alarm_id)
-        body = self.serialize(kwargs)
-        resp, body = self.put(uri, body)
-        self.expected_success(200, resp.status)
-        body = self.deserialize(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 rest_client.ResponseBodyData(resp, body)
-
-    def alarm_set_state(self, alarm_id, state):
-        uri = "%s/alarms/%s/state" % (self.uri_prefix, alarm_id)
-        body = self.serialize(state)
-        resp, body = self.put(uri, body)
-        self.expected_success(200, resp.status)
-        body = self.deserialize(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
deleted file mode 100644
index df7d916..0000000
--- a/tempest/services/telemetry/json/telemetry_client.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# Copyright 2014 OpenStack Foundation
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from oslo_serialization import jsonutils as json
-from six.moves.urllib import parse as urllib
-
-from tempest.lib.common import rest_client
-
-
-class TelemetryClient(rest_client.RestClient):
-
-    version = '2'
-    uri_prefix = "v2"
-
-    def deserialize(self, body):
-        return json.loads(body.replace("\n", ""))
-
-    def serialize(self, body):
-        return json.dumps(body)
-
-    def create_sample(self, meter_name, sample_list):
-        uri = "%s/meters/%s" % (self.uri_prefix, meter_name)
-        body = self.serialize(sample_list)
-        resp, body = self.post(uri, body)
-        self.expected_success(200, resp.status)
-        body = self.deserialize(body)
-        return rest_client.ResponseBody(resp, body)
-
-    def _helper_list(self, uri, query=None, period=None):
-        uri_dict = {}
-        if query:
-            uri_dict = {'q.field': query[0],
-                        'q.op': query[1],
-                        'q.value': query[2]}
-        if period:
-            uri_dict['period'] = period
-        if uri_dict:
-            uri += "?%s" % urllib.urlencode(uri_dict)
-        resp, body = self.get(uri)
-        self.expected_success(200, resp.status)
-        body = self.deserialize(body)
-        return rest_client.ResponseBodyList(resp, body)
-
-    def list_resources(self, query=None):
-        uri = '%s/resources' % self.uri_prefix
-        return self._helper_list(uri, query)
-
-    def list_meters(self, query=None):
-        uri = '%s/meters' % self.uri_prefix
-        return self._helper_list(uri, query)
-
-    def list_statistics(self, meter, period=None, query=None):
-        uri = "%s/meters/%s/statistics" % (self.uri_prefix, meter)
-        return self._helper_list(uri, query, period)
-
-    def list_samples(self, meter_id, query=None):
-        uri = '%s/meters/%s' % (self.uri_prefix, meter_id)
-        return self._helper_list(uri, query)
-
-    def list_events(self, query=None):
-        uri = '%s/events' % self.uri_prefix
-        return self._helper_list(uri, query)
-
-    def show_resource(self, resource_id):
-        uri = '%s/resources/%s' % (self.uri_prefix, resource_id)
-        resp, body = self.get(uri)
-        self.expected_success(200, resp.status)
-        body = self.deserialize(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 4344802..6237745 100644
--- a/tempest/services/volume/base/base_volumes_client.py
+++ b/tempest/services/volume/base/base_volumes_client.py
@@ -62,6 +62,17 @@
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
+    def show_pools(self, detail=False):
+        # List all the volumes pools (hosts)
+        url = 'scheduler-stats/get_pools'
+        if detail:
+            url += '?detail=True'
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
     def show_volume(self, volume_id):
         """Returns the details of a single volume."""
         url = "volumes/%s" % str(volume_id)
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index 382b851..2beaaa9 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -135,10 +135,13 @@
                 break
         if skip:
             break
+        # TODO(andreaf) This has to be reworked to use the credential
+        # provider interface. For now only tests marked as 'use_admin' will
+        # work.
         if test.get('use_admin', False):
             manager = admin_manager
         else:
-            manager = credentials.ConfiguredUserManager()
+            raise NotImplemented('Non admin tests are not supported')
         for p_number in moves.xrange(test.get('threads', default_thread_num)):
             if test.get('use_isolated_tenants', False):
                 username = data_utils.rand_name("stress_user")
diff --git a/tempest/test.py b/tempest/test.py
index b32beaa..aefe1a9 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -78,7 +78,6 @@
         'identity': True,
         'object_storage': CONF.service_available.swift,
         'dashboard': CONF.service_available.horizon,
-        'telemetry': CONF.service_available.ceilometer,
         'data_processing': CONF.service_available.sahara,
         'database': CONF.service_available.trove
     }
@@ -94,7 +93,7 @@
     def decorator(f):
         services = ['compute', 'image', 'baremetal', 'volume', 'orchestration',
                     'network', 'identity', 'object_storage', 'dashboard',
-                    'telemetry', 'data_processing', 'database']
+                    'data_processing', 'database']
         for service in args:
             if service not in services:
                 raise exceptions.InvalidServiceTag('%s is not a valid '
@@ -350,11 +349,14 @@
 
     @classmethod
     def setup_credentials(cls):
-        """Allocate credentials and the client managers from them.
+        """Allocate credentials and create the client managers from them.
 
-        A test class that requires network resources must override
-        setup_credentials and defined the required resources before super
-        is invoked.
+        For every element of credentials param function creates tenant/user,
+        Then it creates client manager for that credential.
+
+        Network related tests must override this function with
+        set_network_resources() method, otherwise it will create
+        network resources(network resources are created in a later step).
         """
         for credentials_type in cls.credentials:
             # This may raise an exception in case credentials are not available
diff --git a/tempest/tests/lib/base.py b/tempest/tests/base.py
similarity index 79%
rename from tempest/tests/lib/base.py
rename to tempest/tests/base.py
index fe9268e..ca81d4d 100644
--- a/tempest/tests/lib/base.py
+++ b/tempest/tests/base.py
@@ -14,17 +14,10 @@
 
 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.
 
@@ -42,3 +35,15 @@
         m = p.start()
         self.addCleanup(p.stop)
         return m
+
+    def patchobject(self, target, attribute, new=mock.DEFAULT):
+        """Convenient wrapper around `mock.patch.object`
+
+        Returns a started mock that will be automatically stopped after the
+        test ran.
+        """
+
+        p = mock.patch.object(target, attribute, new)
+        m = p.start()
+        self.addCleanup(p.stop)
+        return m
diff --git a/tempest/tests/cmd/test_javelin.py b/tempest/tests/cmd/test_javelin.py
index b8c9969..2d0256a 100644
--- a/tempest/tests/cmd/test_javelin.py
+++ b/tempest/tests/cmd/test_javelin.py
@@ -17,7 +17,7 @@
 
 from tempest.cmd import javelin
 from tempest.lib import exceptions as lib_exc
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class JavelinUnitTest(base.TestCase):
diff --git a/tempest/tests/cmd/test_list_plugins.py b/tempest/tests/cmd/test_list_plugins.py
index 782dde7..17ddb18 100644
--- a/tempest/tests/cmd/test_list_plugins.py
+++ b/tempest/tests/cmd/test_list_plugins.py
@@ -14,7 +14,7 @@
 
 import subprocess
 
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class TestTempestListPlugins(base.TestCase):
diff --git a/tempest/tests/cmd/test_tempest_init.py b/tempest/tests/cmd/test_tempest_init.py
index 6c5326a..685a0b3 100644
--- a/tempest/tests/cmd/test_tempest_init.py
+++ b/tempest/tests/cmd/test_tempest_init.py
@@ -18,7 +18,7 @@
 import fixtures
 
 from tempest.cmd import init
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class TestTempestInit(base.TestCase):
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 9df07a1..70cbf87 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -12,28 +12,56 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-
 import mock
 from oslo_serialization import jsonutils as json
 from oslotest import mockpatch
 
 from tempest.cmd import verify_tempest_config
 from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.tests import base
 from tempest.tests import fake_config
-from tempest.tests.lib import base
 
 
 class TestGetAPIVersions(base.TestCase):
 
+    def test_remove_version_project(self):
+        f = verify_tempest_config._remove_version_project
+        self.assertEqual('/', f('/v2.1/%s/' % data_utils.rand_uuid_hex()))
+        self.assertEqual('', f('/v2.1/tenant_id'))
+        self.assertEqual('', f('/v3'))
+        self.assertEqual('/', f('/v3/'))
+        self.assertEqual('/something/', f('/something/v2.1/tenant_id/'))
+        self.assertEqual('/something', f('/something/v2.1/tenant_id'))
+        self.assertEqual('/something', f('/something/v3'))
+        self.assertEqual('/something/', f('/something/v3/'))
+        self.assertEqual('/', f('/'))  # http://localhost/
+        self.assertEqual('', f(''))  # http://localhost
+
     def test_url_grab_versioned_nova_nossl(self):
         base_url = 'http://127.0.0.1:8774/v2/'
         endpoint = verify_tempest_config._get_unversioned_endpoint(base_url)
-        self.assertEqual('http://127.0.0.1:8774', endpoint)
+        self.assertEqual('http://127.0.0.1:8774/', endpoint)
 
     def test_url_grab_versioned_nova_ssl(self):
         base_url = 'https://127.0.0.1:8774/v3/'
         endpoint = verify_tempest_config._get_unversioned_endpoint(base_url)
-        self.assertEqual('https://127.0.0.1:8774', endpoint)
+        self.assertEqual('https://127.0.0.1:8774/', endpoint)
+
+    def test_get_unversioned_endpoint_base(self):
+        base_url = 'https://127.0.0.1:5000/'
+        endpoint = verify_tempest_config._get_unversioned_endpoint(base_url)
+        self.assertEqual('https://127.0.0.1:5000/', endpoint)
+
+    def test_get_unversioned_endpoint_subpath(self):
+        base_url = 'https://127.0.0.1/identity/v3'
+        endpoint = verify_tempest_config._get_unversioned_endpoint(base_url)
+        self.assertEqual('https://127.0.0.1/identity', endpoint)
+
+    def test_get_unversioned_endpoint_subpath_trailing_solidus(self):
+        base_url = 'https://127.0.0.1/identity/v3/'
+        endpoint = verify_tempest_config._get_unversioned_endpoint(base_url)
+        self.assertEqual('https://127.0.0.1/identity/', endpoint)
 
 
 class TestDiscovery(base.TestCase):
@@ -41,7 +69,8 @@
     def setUp(self):
         super(TestDiscovery, self).setUp()
         self.useFixture(fake_config.ConfigFixture())
-        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+        self.patchobject(config, 'TempestConfigPrivate',
+                         fake_config.FakePrivate)
 
     def test_get_keystone_api_versions(self):
         self.useFixture(mockpatch.PatchObject(
diff --git a/tempest/tests/common/test_admin_available.py b/tempest/tests/common/test_admin_available.py
index c803541..01a9cd0 100644
--- a/tempest/tests/common/test_admin_available.py
+++ b/tempest/tests/common/test_admin_available.py
@@ -17,8 +17,8 @@
 
 from tempest.common import credentials_factory as credentials
 from tempest import config
+from tempest.tests import base
 from tempest.tests import fake_config
-from tempest.tests.lib import base
 
 
 class TestAdminAvailable(base.TestCase):
@@ -28,7 +28,8 @@
     def setUp(self):
         super(TestAdminAvailable, self).setUp()
         self.useFixture(fake_config.ConfigFixture())
-        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+        self.patchobject(config, 'TempestConfigPrivate',
+                         fake_config.FakePrivate)
 
     def run_test(self, dynamic_creds, use_accounts_file, admin_creds):
 
diff --git a/tempest/tests/common/test_alt_available.py b/tempest/tests/common/test_alt_available.py
index cb1de16..27db95c 100644
--- a/tempest/tests/common/test_alt_available.py
+++ b/tempest/tests/common/test_alt_available.py
@@ -17,8 +17,8 @@
 
 from tempest.common import credentials_factory as credentials
 from tempest import config
+from tempest.tests import base
 from tempest.tests import fake_config
-from tempest.tests.lib import base
 
 
 class TestAltAvailable(base.TestCase):
@@ -28,7 +28,8 @@
     def setUp(self):
         super(TestAltAvailable, self).setUp()
         self.useFixture(fake_config.ConfigFixture())
-        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+        self.patchobject(config, 'TempestConfigPrivate',
+                         fake_config.FakePrivate)
 
     def run_test(self, dynamic_creds, use_accounts_file, creds):
 
@@ -48,28 +49,6 @@
         else:
             self.useFixture(mockpatch.Patch('os.path.isfile',
                                             return_value=False))
-            cred_prefix = ['', 'alt_']
-            for ii in range(0, 2):
-                if len(creds) > ii:
-                    username = 'u%s' % creds[ii]
-                    project = 't%s' % creds[ii]
-                    password = 'p'
-                    domain = 'd'
-                else:
-                    username = None
-                    project = None
-                    password = None
-                    domain = None
-
-                cfg.CONF.set_default('%susername' % cred_prefix[ii], username,
-                                     group='identity')
-                cfg.CONF.set_default('%sproject_name' % cred_prefix[ii],
-                                     project, group='identity')
-                cfg.CONF.set_default('%spassword' % cred_prefix[ii], password,
-                                     group='identity')
-                cfg.CONF.set_default('%sdomain_name' % cred_prefix[ii], domain,
-                                     group='identity')
-
         expected = len(set(creds)) > 1 or dynamic_creds
         observed = credentials.is_alt_available(
             identity_version=self.identity_version)
@@ -96,21 +75,6 @@
                       use_accounts_file=True,
                       creds=['1', '1'])
 
-    def test__no_dynamic_creds__no_accounts_file__one_user(self):
-        self.run_test(dynamic_creds=False,
-                      use_accounts_file=False,
-                      creds=['1'])
-
-    def test__no_dynamic_creds__no_accounts_file__two_users(self):
-        self.run_test(dynamic_creds=False,
-                      use_accounts_file=False,
-                      creds=['1', '2'])
-
-    def test__no_dynamic_creds__no_accounts_file__two_users_identical(self):
-        self.run_test(dynamic_creds=False,
-                      use_accounts_file=False,
-                      creds=['1', '1'])
-
 
 class TestAltAvailableV3(TestAltAvailable):
 
diff --git a/tempest/tests/common/test_configured_creds.py b/tempest/tests/common/test_configured_creds.py
deleted file mode 100644
index 3c104b2..0000000
--- a/tempest/tests/common/test_configured_creds.py
+++ /dev/null
@@ -1,130 +0,0 @@
-# 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.
-
-from oslo_config import cfg
-
-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 fake_config
-from tempest.tests.lib import base
-from tempest.tests.lib import fake_identity
-
-
-class ConfiguredV2CredentialsTests(base.TestCase):
-    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(ConfiguredV2CredentialsTests, self).setUp()
-        self.useFixture(fake_config.ConfigFixture())
-        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
-        self.stubs.Set(self.tokenclient_class, 'raw_request',
-                       self.identity_response)
-
-    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 _verify_credentials(self, credentials_class, filled=True,
-                            identity_version=None):
-        for ctype in common_creds.CREDENTIAL_TYPES:
-            if identity_version is None:
-                creds = common_creds.get_configured_credentials(
-                    credential_type=ctype, fill_in=filled)
-            else:
-                creds = common_creds.get_configured_credentials(
-                    credential_type=ctype, fill_in=filled,
-                    identity_version=identity_version)
-            self._check(creds, credentials_class, filled)
-
-    def test_create(self):
-        creds = self._get_credentials()
-        self.assertEqual(self.attributes, creds._initial)
-
-    def test_create_invalid_attr(self):
-        self.assertRaises(lib_exc.InvalidCredentials,
-                          self._get_credentials,
-                          attributes=dict(invalid='fake'))
-
-    def test_get_configured_credentials(self):
-        self.useFixture(fixtures.LockFixture('auth_version'))
-        self._verify_credentials(credentials_class=self.credentials_class)
-
-    def test_get_configured_credentials_unfilled(self):
-        self.useFixture(fixtures.LockFixture('auth_version'))
-        self._verify_credentials(credentials_class=self.credentials_class,
-                                 filled=False)
-
-    def test_get_configured_credentials_version(self):
-        # version specified and not loaded from config
-        self.useFixture(fixtures.LockFixture('auth_version'))
-        self._verify_credentials(credentials_class=self.credentials_class,
-                                 identity_version=self.identity_version)
-
-    def test_is_valid(self):
-        creds = self._get_credentials()
-        self.assertTrue(creds.is_valid())
-
-
-class ConfiguredV3CredentialsTests(ConfiguredV2CredentialsTests):
-    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 setUp(self):
-        super(ConfiguredV3CredentialsTests, self).setUp()
-        # Additional config items reset by cfg fixture after each test
-        cfg.CONF.set_default('auth_version', 'v3', group='identity')
-        # Identity group items
-        for prefix in ['', 'alt_', 'admin_']:
-            if prefix == 'admin_':
-                group = 'auth'
-            else:
-                group = 'identity'
-            cfg.CONF.set_default(prefix + 'domain_name', 'fake_domain_name',
-                                 group=group)
diff --git a/tempest/tests/common/test_credentials.py b/tempest/tests/common/test_credentials.py
deleted file mode 100644
index 6fc490e..0000000
--- a/tempest/tests/common/test_credentials.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# 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.
-
-from tempest.common import credentials_factory as credentials
-from tempest import config
-from tempest import exceptions
-from tempest.tests import fake_config
-from tempest.tests.lib import base
-
-
-class TestLegacyCredentialsProvider(base.TestCase):
-
-    fixed_params = {'identity_version': 'v2'}
-
-    def setUp(self):
-        super(TestLegacyCredentialsProvider, self).setUp()
-        self.useFixture(fake_config.ConfigFixture())
-        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
-
-    def test_get_creds_roles_legacy_invalid(self):
-        test_accounts_class = credentials.LegacyCredentialProvider(
-            **self.fixed_params)
-        self.assertRaises(exceptions.InvalidConfiguration,
-                          test_accounts_class.get_creds_by_roles,
-                          ['fake_role'])
diff --git a/tempest/tests/common/test_custom_matchers.py b/tempest/tests/common/test_custom_matchers.py
index d664961..2656a47 100644
--- a/tempest/tests/common/test_custom_matchers.py
+++ b/tempest/tests/common/test_custom_matchers.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.common import custom_matchers
-from tempest.tests.lib import base
+from tempest.tests import base
 
 from testtools.tests.matchers import helpers
 
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index e1d9023..8d4f33b 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -31,8 +31,8 @@
 from tempest.services.identity.v2.json import users_client as \
     json_users_client
 from tempest.services.network.json import routers_client
+from tempest.tests import base
 from tempest.tests import fake_config
-from tempest.tests.lib import base
 from tempest.tests.lib import fake_http
 from tempest.tests.lib import fake_identity
 
@@ -46,9 +46,10 @@
     def setUp(self):
         super(TestDynamicCredentialProvider, self).setUp()
         self.useFixture(fake_config.ConfigFixture())
-        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
-        self.stubs.Set(json_token_client.TokenClient, 'raw_request',
-                       fake_identity._fake_v2_response)
+        self.patchobject(config, 'TempestConfigPrivate',
+                         fake_config.FakePrivate)
+        self.patchobject(json_token_client.TokenClient, 'raw_request',
+                         fake_identity._fake_v2_response)
         cfg.CONF.set_default('operator_role', 'FakeRole',
                              group='object-storage')
         self._mock_list_ec2_credentials('fake_user_id', 'fake_tenant_id')
diff --git a/tempest/tests/common/test_preprov_creds.py b/tempest/tests/common/test_preprov_creds.py
index 36d6c3d..873c4c4 100644
--- a/tempest/tests/common/test_preprov_creds.py
+++ b/tempest/tests/common/test_preprov_creds.py
@@ -27,9 +27,8 @@
 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.lib import base
 from tempest.tests.lib import fake_identity
 
 
@@ -43,39 +42,46 @@
                     'object_storage_operator_role': 'operator',
                     'object_storage_reseller_admin_role': 'reseller'}
 
-    def setUp(self):
-        super(TestPreProvisionedCredentials, self).setUp()
-        self.useFixture(fake_config.ConfigFixture())
-        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
-        self.stubs.Set(token_client.TokenClient, 'raw_request',
-                       fake_identity._fake_v2_response)
-        self.useFixture(lockutils_fixtures.ExternalLockFixture())
-        self.test_accounts = [
+    identity_response = fake_identity._fake_v2_response
+    token_client = ('tempest.lib.services.identity.v2.token_client'
+                    '.TokenClient.raw_request')
+
+    @classmethod
+    def _fake_accounts(cls, admin_role):
+        return [
             {'username': 'test_user1', 'tenant_name': 'test_tenant1',
              'password': 'p'},
-            {'username': 'test_user2', 'tenant_name': 'test_tenant2',
+            {'username': 'test_user2', 'project_name': 'test_tenant2',
              'password': 'p'},
             {'username': 'test_user3', 'tenant_name': 'test_tenant3',
              'password': 'p'},
-            {'username': 'test_user4', 'tenant_name': 'test_tenant4',
+            {'username': 'test_user4', 'project_name': 'test_tenant4',
              'password': 'p'},
             {'username': 'test_user5', 'tenant_name': 'test_tenant5',
              'password': 'p'},
-            {'username': 'test_user6', 'tenant_name': 'test_tenant6',
+            {'username': 'test_user6', 'project_name': 'test_tenant6',
              'password': 'p', 'roles': ['role1', 'role2']},
             {'username': 'test_user7', 'tenant_name': 'test_tenant7',
              'password': 'p', 'roles': ['role2', 'role3']},
-            {'username': 'test_user8', 'tenant_name': 'test_tenant8',
+            {'username': 'test_user8', 'project_name': 'test_tenant8',
              'password': 'p', 'roles': ['role4', 'role1']},
             {'username': 'test_user9', 'tenant_name': 'test_tenant9',
              'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']},
-            {'username': 'test_user10', 'tenant_name': 'test_tenant10',
+            {'username': 'test_user10', 'project_name': 'test_tenant10',
              'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']},
             {'username': 'test_user11', 'tenant_name': 'test_tenant11',
-             'password': 'p', 'roles': [cfg.CONF.identity.admin_role]},
-            {'username': 'test_user12', 'tenant_name': 'test_tenant12',
-             'password': 'p', 'roles': [cfg.CONF.identity.admin_role]},
-        ]
+             'password': 'p', 'roles': [admin_role]},
+            {'username': 'test_user12', 'project_name': 'test_tenant12',
+             'password': 'p', 'roles': [admin_role]}]
+
+    def setUp(self):
+        super(TestPreProvisionedCredentials, self).setUp()
+        self.useFixture(fake_config.ConfigFixture())
+        self.patchobject(config, 'TempestConfigPrivate',
+                         fake_config.FakePrivate)
+        self.patch(self.token_client, side_effect=self.identity_response)
+        self.useFixture(lockutils_fixtures.ExternalLockFixture())
+        self.test_accounts = self._fake_accounts(cfg.CONF.identity.admin_role)
         self.accounts_mock = self.useFixture(mockpatch.Patch(
             'tempest.common.preprov_creds.read_accounts_yaml',
             return_value=self.test_accounts))
@@ -88,24 +94,33 @@
 
     def _get_hash_list(self, accounts_list):
         hash_list = []
+        hash_fields = (
+            preprov_creds.PreProvisionedCredentialProvider.HASH_CRED_FIELDS)
         for account in accounts_list:
             hash = hashlib.md5()
-            hash.update(six.text_type(account).encode('utf-8'))
+            account_for_hash = dict((k, v) for (k, v) in six.iteritems(account)
+                                    if k in hash_fields)
+            hash.update(six.text_type(account_for_hash).encode('utf-8'))
             temp_hash = hash.hexdigest()
             hash_list.append(temp_hash)
         return hash_list
 
     def test_get_hash(self):
-        self.stubs.Set(token_client.TokenClient, 'raw_request',
-                       fake_identity._fake_v2_response)
-        test_account_class = preprov_creds.PreProvisionedCredentialProvider(
-            **self.fixed_params)
-        hash_list = self._get_hash_list(self.test_accounts)
-        test_cred_dict = self.test_accounts[3]
-        test_creds = auth.get_credentials(fake_identity.FAKE_AUTH_URL,
-                                          **test_cred_dict)
-        results = test_account_class.get_hash(test_creds)
-        self.assertEqual(hash_list[3], results)
+        # Test with all accounts to make sure we try all combinations
+        # and hide no race conditions
+        hash_index = 0
+        for test_cred_dict in self.test_accounts:
+            test_account_class = (
+                preprov_creds.PreProvisionedCredentialProvider(
+                    **self.fixed_params))
+            hash_list = self._get_hash_list(self.test_accounts)
+            test_creds = auth.get_credentials(
+                fake_identity.FAKE_AUTH_URL,
+                identity_version=self.fixed_params['identity_version'],
+                **test_cred_dict)
+            results = test_account_class.get_hash(test_creds)
+            self.assertEqual(hash_list[hash_index], results)
+            hash_index += 1
 
     def test_get_hash_dict(self):
         test_account_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -188,7 +203,7 @@
                 return False
             return True
 
-        self.stubs.Set(os.path, 'isfile', _fake_is_file)
+        self.patchobject(os.path, 'isfile', _fake_is_file)
         with mock.patch('six.moves.builtins.open', mock.mock_open(),
                         create=True) as open_mock:
             test_account_class._get_free_hash(hash_list)
@@ -330,3 +345,53 @@
         self.assertIn('id', network)
         self.assertEqual('fake-id', network['id'])
         self.assertEqual('network-2', network['name'])
+
+
+class TestPreProvisionedCredentialsV3(TestPreProvisionedCredentials):
+
+    fixed_params = {'name': 'test class',
+                    'identity_version': 'v3',
+                    'test_accounts_file': 'fake_accounts_file',
+                    'accounts_lock_dir': 'fake_locks_dir_v3',
+                    'admin_role': 'admin',
+                    'object_storage_operator_role': 'operator',
+                    'object_storage_reseller_admin_role': 'reseller'}
+
+    identity_response = fake_identity._fake_v3_response
+    token_client = ('tempest.lib.services.identity.v3.token_client'
+                    '.V3TokenClient.raw_request')
+
+    @classmethod
+    def _fake_accounts(cls, admin_role):
+        return [
+            {'username': 'test_user1', 'project_name': 'test_project1',
+             'domain_name': 'domain', 'password': 'p'},
+            {'username': 'test_user2', 'project_name': 'test_project2',
+             'domain_name': 'domain', 'password': 'p'},
+            {'username': 'test_user3', 'project_name': 'test_project3',
+             'domain_name': 'domain', 'password': 'p'},
+            {'username': 'test_user4', 'project_name': 'test_project4',
+             'domain_name': 'domain', 'password': 'p'},
+            {'username': 'test_user5', 'project_name': 'test_project5',
+             'domain_name': 'domain', 'password': 'p'},
+            {'username': 'test_user6', 'project_name': 'test_project6',
+             'domain_name': 'domain', 'password': 'p',
+             'roles': ['role1', 'role2']},
+            {'username': 'test_user7', 'project_name': 'test_project7',
+             'domain_name': 'domain', 'password': 'p',
+             'roles': ['role2', 'role3']},
+            {'username': 'test_user8', 'project_name': 'test_project8',
+             'domain_name': 'domain', 'password': 'p',
+             'roles': ['role4', 'role1']},
+            {'username': 'test_user9', 'project_name': 'test_project9',
+             'domain_name': 'domain', 'password': 'p',
+             'roles': ['role1', 'role2', 'role3', 'role4']},
+            {'username': 'test_user10', 'project_name': 'test_project10',
+             'domain_name': 'domain', 'password': 'p',
+             'roles': ['role1', 'role2', 'role3', 'role4']},
+            {'username': 'test_user11', 'project_name': 'test_project11',
+             'domain_name': 'domain', 'password': 'p',
+             'roles': [admin_role]},
+            {'username': 'test_user12', 'project_name': 'test_project12',
+             'domain_name': 'domain', 'password': 'p',
+             'roles': [admin_role]}]
diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py
index e0cef62..a56f837 100644
--- a/tempest/tests/common/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -19,7 +19,7 @@
 from tempest.common import waiters
 from tempest import exceptions
 from tempest.services.volume.base import base_volumes_client
-from tempest.tests.lib import base
+from tempest.tests import base
 import tempest.tests.utils as utils
 
 
@@ -38,8 +38,7 @@
         # Ensure waiter returns before build_timeout
         self.assertTrue((end_time - start_time) < 10)
 
-    @mock.patch('time.sleep')
-    def test_wait_for_image_status_timeout(self, mock_sleep):
+    def test_wait_for_image_status_timeout(self):
         time_mock = self.patch('time.time')
         time_mock.side_effect = utils.generate_timeout_series(1)
 
@@ -47,15 +46,12 @@
         self.assertRaises(exceptions.TimeoutException,
                           waiters.wait_for_image_status,
                           self.client, 'fake_image_id', 'active')
-        mock_sleep.assert_called_once_with(1)
 
-    @mock.patch('time.sleep')
-    def test_wait_for_image_status_error_on_image_create(self, mock_sleep):
+    def test_wait_for_image_status_error_on_image_create(self):
         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/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
index 22cf47a..7d625cf 100644
--- a/tempest/tests/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -12,6 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import fixtures
 import time
 
 from oslo_config import cfg
@@ -19,15 +20,45 @@
 
 from tempest.common.utils.linux import remote_client
 from tempest import config
+from tempest.lib import exceptions as lib_exc
+from tempest.tests import base
 from tempest.tests import fake_config
-from tempest.tests.lib import base
+
+
+SERVER = {
+    'id': 'server_uuid',
+    'name': 'fake_server',
+    'status': 'ACTIVE'
+}
+
+BROKEN_SERVER = {
+    'id': 'broken_server_uuid',
+    'name': 'broken_server',
+    'status': 'ERROR'
+}
+
+
+class FakeServersClient(object):
+
+    CONSOLE_OUTPUT = "Console output for %s"
+
+    def get_console_output(self, server_id):
+        status = 'ERROR'
+        for s in SERVER, BROKEN_SERVER:
+            if s['id'] == server_id:
+                status = s['status']
+        if status == 'ERROR':
+            raise lib_exc.BadRequest('Server in ERROR state')
+        else:
+            return dict(output=self.CONSOLE_OUTPUT % server_id)
 
 
 class TestRemoteClient(base.TestCase):
     def setUp(self):
         super(TestRemoteClient, self).setUp()
         self.useFixture(fake_config.ConfigFixture())
-        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+        self.patchobject(config, 'TempestConfigPrivate',
+                         fake_config.FakePrivate)
         cfg.CONF.set_default('ip_version_for_ssh', 4, group='validation')
         cfg.CONF.set_default('network_for_ssh', 'public', group='validation')
         cfg.CONF.set_default('connect_timeout', 1, group='validation')
@@ -154,3 +185,78 @@
         self.conn.set_nic_state(nic, "down")
         self._assert_exec_called_with(
             'sudo ip link set %s down' % nic)
+
+
+class TestRemoteClientWithServer(base.TestCase):
+
+    server = SERVER
+
+    def setUp(self):
+        super(TestRemoteClientWithServer, self).setUp()
+        self.useFixture(fake_config.ConfigFixture())
+        self.patchobject(config, 'TempestConfigPrivate',
+                         fake_config.FakePrivate)
+        cfg.CONF.set_default('ip_version_for_ssh', 4, group='validation')
+        cfg.CONF.set_default('network_for_ssh', 'public',
+                             group='validation')
+        cfg.CONF.set_default('connect_timeout', 1, group='validation')
+        cfg.CONF.set_default('console_output', True,
+                             group='compute-feature-enabled')
+
+        self.conn = remote_client.RemoteClient(
+            '127.0.0.1', 'user', 'pass',
+            server=self.server, servers_client=FakeServersClient())
+        self.useFixture(fixtures.MockPatch(
+            'tempest.lib.common.ssh.Client._get_ssh_connection',
+            side_effect=lib_exc.SSHTimeout(host='127.0.0.1',
+                                           user='user',
+                                           password='pass')))
+        self.log = self.useFixture(fixtures.FakeLogger(
+            name='tempest.common.utils.linux.remote_client',
+            level='DEBUG'))
+
+    def test_validate_debug_ssh_console(self):
+        self.assertRaises(lib_exc.SSHTimeout,
+                          self.conn.validate_authentication)
+        msg = 'Caller: %s. Timeout trying to ssh to server %s' % (
+            'TestRemoteClientWithServer:test_validate_debug_ssh_console',
+            self.server)
+        self.assertIn(msg, self.log.output)
+        self.assertIn('Console output for', self.log.output)
+
+    def test_exec_command_debug_ssh_console(self):
+        self.assertRaises(lib_exc.SSHTimeout,
+                          self.conn.exec_command, 'fake command')
+        self.assertIn('fake command', self.log.output)
+        msg = 'Caller: %s. Timeout trying to ssh to server %s' % (
+            'TestRemoteClientWithServer:test_exec_command_debug_ssh_console',
+            self.server)
+        self.assertIn(msg, self.log.output)
+        self.assertIn('Console output for', self.log.output)
+
+
+class TestRemoteClientWithBrokenServer(TestRemoteClientWithServer):
+
+    server = BROKEN_SERVER
+
+    def test_validate_debug_ssh_console(self):
+        self.assertRaises(lib_exc.SSHTimeout,
+                          self.conn.validate_authentication)
+        msg = 'Caller: %s. Timeout trying to ssh to server %s' % (
+            'TestRemoteClientWithBrokenServer:test_validate_debug_ssh_console',
+            self.server)
+        self.assertIn(msg, self.log.output)
+        msg = 'Could not get console_log for server %s' % self.server['id']
+        self.assertIn(msg, self.log.output)
+
+    def test_exec_command_debug_ssh_console(self):
+        self.assertRaises(lib_exc.SSHTimeout,
+                          self.conn.exec_command, 'fake command')
+        self.assertIn('fake command', self.log.output)
+        caller = ":".join(['TestRemoteClientWithBrokenServer',
+                           'test_exec_command_debug_ssh_console'])
+        msg = 'Caller: %s. Timeout trying to ssh to server %s' % (
+            caller, self.server)
+        self.assertIn(msg, self.log.output)
+        msg = 'Could not get console_log for server %s' % self.server['id']
+        self.assertIn(msg, self.log.output)
diff --git a/tempest/tests/common/utils/test_file_utils.py b/tempest/tests/common/utils/test_file_utils.py
deleted file mode 100644
index 1a14592..0000000
--- a/tempest/tests/common/utils/test_file_utils.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# 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 mock
-
-from tempest.common.utils import file_utils
-from tempest.tests.lib import base
-
-
-class TestFileUtils(base.TestCase):
-
-    def test_have_effective_read_path(self):
-        with mock.patch('six.moves.builtins.open', mock.mock_open(),
-                        create=True):
-            result = file_utils.have_effective_read_access('fake_path')
-        self.assertTrue(result)
-
-    def test_not_effective_read_path(self):
-        result = file_utils.have_effective_read_access('fake_path')
-        self.assertFalse(result)
diff --git a/tempest/tests/fake_auth_provider.py b/tempest/tests/fake_auth_provider.py
index bc68d26..769f6a6 100644
--- a/tempest/tests/fake_auth_provider.py
+++ b/tempest/tests/fake_auth_provider.py
@@ -18,3 +18,9 @@
 
     def auth_request(self, method, url, headers=None, body=None, filters=None):
         return url, headers, body
+
+    def get_token(self):
+        return "faketoken"
+
+    def base_url(self, filters, auth_data=None):
+        return "https://example.com"
diff --git a/tempest/tests/fake_config.py b/tempest/tests/fake_config.py
index edd7186..65164a0 100644
--- a/tempest/tests/fake_config.py
+++ b/tempest/tests/fake_config.py
@@ -48,14 +48,9 @@
         self.conf.set_default('auth_version', 'v2', group='identity')
         for config_option in ['username', 'password', 'project_name']:
             # Identity group items
-            for prefix in ['', 'alt_', 'admin_']:
-                if prefix == 'admin_':
-                    group = 'auth'
-                else:
-                    group = 'identity'
-                self.conf.set_default(prefix + config_option,
-                                      'fake_' + config_option,
-                                      group=group)
+            self.conf.set_default('admin_' + config_option,
+                                  'fake_' + config_option,
+                                  group='auth')
 
 
 class FakePrivate(config.TempestConfigPrivate):
diff --git a/tempest/tests/lib/cli/test_command_failed.py b/tempest/tests/lib/cli/test_command_failed.py
index 8ce34c2..388028a 100644
--- a/tempest/tests/lib/cli/test_command_failed.py
+++ b/tempest/tests/lib/cli/test_command_failed.py
@@ -11,7 +11,7 @@
 #    under the License.
 
 from tempest.lib import exceptions
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class TestOutputParser(base.TestCase):
diff --git a/tempest/tests/lib/cli/test_execute.py b/tempest/tests/lib/cli/test_execute.py
index b5f7145..cc9c94c 100644
--- a/tempest/tests/lib/cli/test_execute.py
+++ b/tempest/tests/lib/cli/test_execute.py
@@ -12,26 +12,65 @@
 #    under the License.
 
 
+import mock
+import subprocess
+
 from tempest.lib.cli import base as cli_base
 from tempest.lib import exceptions
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class TestExecute(base.TestCase):
-    def test_execute_success(self):
+
+    @mock.patch('subprocess.Popen', autospec=True)
+    def test_execute_success(self, mock_popen):
+        mock_popen.return_value.returncode = 0
+        mock_popen.return_value.communicate.return_value = (
+            "__init__.py", "")
         result = cli_base.execute("/bin/ls", action="tempest",
                                   flags="-l -a")
+        args, kwargs = mock_popen.call_args
+        # Check merge_stderr == False
+        self.assertEqual(subprocess.PIPE, kwargs['stderr'])
+        # Check action and flags are passed
+        args = args[0]
+        # We just tests that all pieces are passed through, we cannot make
+        # assumptions about the order
+        self.assertIn("/bin/ls", args)
+        self.assertIn("-l", args)
+        self.assertIn("-a", args)
+        self.assertIn("tempest", args)
+        # The result is mocked - checking that the mock was invoked correctly
         self.assertIsInstance(result, str)
         self.assertIn("__init__.py", result)
 
-    def test_execute_failure(self):
+    @mock.patch('subprocess.Popen', autospec=True)
+    def test_execute_failure(self, mock_popen):
+        mock_popen.return_value.returncode = 1
+        mock_popen.return_value.communicate.return_value = (
+            "No such option --foobar", "")
         result = cli_base.execute("/bin/ls", action="tempest.lib",
                                   flags="--foobar", merge_stderr=True,
                                   fail_ok=True)
+        args, kwargs = mock_popen.call_args
+        # Check the merge_stderr
+        self.assertEqual(subprocess.STDOUT, kwargs['stderr'])
+        # Check action and flags are passed
+        args = args[0]
+        # We just tests that all pieces are passed through, we cannot make
+        # assumptions about the order
+        self.assertIn("/bin/ls", args)
+        self.assertIn("--foobar", args)
+        self.assertIn("tempest.lib", args)
+        # The result is mocked - checking that the mock was invoked correctly
         self.assertIsInstance(result, str)
         self.assertIn("--foobar", result)
 
-    def test_execute_failure_raise_exception(self):
+    @mock.patch('subprocess.Popen', autospec=True)
+    def test_execute_failure_raise_exception(self, mock_popen):
+        mock_popen.return_value.returncode = 1
+        mock_popen.return_value.communicate.return_value = (
+            "No such option --foobar", "")
         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
index a2c1b2d..d88dfc3 100644
--- a/tempest/tests/lib/cli/test_output_parser.py
+++ b/tempest/tests/lib/cli/test_output_parser.py
@@ -16,7 +16,7 @@
 
 from tempest.lib.cli import output_parser
 from tempest.lib import exceptions
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class TestOutputParser(base.TestCase):
diff --git a/tempest/tests/lib/common/test_api_version_request.py b/tempest/tests/lib/common/test_api_version_request.py
index bdaa936..58e7040 100644
--- a/tempest/tests/lib/common/test_api_version_request.py
+++ b/tempest/tests/lib/common/test_api_version_request.py
@@ -14,7 +14,7 @@
 
 from tempest.lib.common import api_version_request
 from tempest.lib import exceptions
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class APIVersionRequestTests(base.TestCase):
diff --git a/tempest/tests/lib/common/test_api_version_utils.py b/tempest/tests/lib/common/test_api_version_utils.py
index 591b87e..6206379 100644
--- a/tempest/tests/lib/common/test_api_version_utils.py
+++ b/tempest/tests/lib/common/test_api_version_utils.py
@@ -16,7 +16,7 @@
 
 from tempest.lib.common import api_version_utils
 from tempest.lib import exceptions
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class TestVersionSkipLogic(base.TestCase):
diff --git a/tempest/tests/lib/common/utils/test_data_utils.py b/tempest/tests/lib/common/utils/test_data_utils.py
index 493df89..399c4af 100644
--- a/tempest/tests/lib/common/utils/test_data_utils.py
+++ b/tempest/tests/lib/common/utils/test_data_utils.py
@@ -16,7 +16,7 @@
 import netaddr
 
 from tempest.lib.common.utils import data_utils
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class TestDataUtils(base.TestCase):
@@ -93,6 +93,15 @@
         actual2 = data_utils.rand_int_id()
         self.assertNotEqual(actual, actual2)
 
+    def test_rand_infiniband_guid_address(self):
+        actual = data_utils.rand_infiniband_guid_address()
+        self.assertIsInstance(actual, str)
+        self.assertRegex(actual, "^([0-9a-f][0-9a-f]:){7}"
+                         "[0-9a-f][0-9a-f]$")
+
+        actual2 = data_utils.rand_infiniband_guid_address()
+        self.assertNotEqual(actual, actual2)
+
     def test_rand_mac_address(self):
         actual = data_utils.rand_mac_address()
         self.assertIsInstance(actual, str)
@@ -160,3 +169,10 @@
         bad_mac = 99999999999999999999
         self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64,
                           cidr, bad_mac)
+
+    def test_chunkify(self):
+        data = "aaa"
+        chunks = data_utils.chunkify(data, 2)
+        self.assertEqual("aa", next(chunks))
+        self.assertEqual("a", next(chunks))
+        self.assertRaises(StopIteration, next, chunks)
diff --git a/tempest/tests/lib/common/utils/test_misc.py b/tempest/tests/lib/common/utils/test_misc.py
index e23d7fb..9597f5b 100644
--- a/tempest/tests/lib/common/utils/test_misc.py
+++ b/tempest/tests/lib/common/utils/test_misc.py
@@ -15,7 +15,7 @@
 
 
 from tempest.lib.common.utils import misc
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 @misc.singleton
diff --git a/tempest/tests/lib/fake_credentials.py b/tempest/tests/lib/fake_credentials.py
index fb81bd6..eac4ada 100644
--- a/tempest/tests/lib/fake_credentials.py
+++ b/tempest/tests/lib/fake_credentials.py
@@ -57,3 +57,18 @@
             user_domain_name='fake_domain_name'
         )
         super(FakeKeystoneV3DomainCredentials, self).__init__(**creds)
+
+
+class FakeKeystoneV3AllCredentials(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',
+            project_name='fake_tenant_name',
+            project_domain_name='fake_domain_name',
+            domain_name='fake_domain_name'
+        )
+        super(FakeKeystoneV3AllCredentials, self).__init__(**creds)
diff --git a/tempest/tests/lib/fake_http.py b/tempest/tests/lib/fake_http.py
index 397c856..cfa4b93 100644
--- a/tempest/tests/lib/fake_http.py
+++ b/tempest/tests/lib/fake_http.py
@@ -21,7 +21,7 @@
         self.return_type = return_type
 
     def request(self, uri, method="GET", body=None, headers=None,
-                redirections=5, connection_type=None):
+                redirections=5, connection_type=None, chunked=False):
         if not self.return_type:
             fake_headers = fake_http_response(headers)
             return_obj = {
diff --git a/tempest/tests/lib/fake_identity.py b/tempest/tests/lib/fake_identity.py
index 5732065..c903e47 100644
--- a/tempest/tests/lib/fake_identity.py
+++ b/tempest/tests/lib/fake_identity.py
@@ -133,6 +133,49 @@
     }
 }
 
+IDENTITY_V3_RESPONSE_DOMAIN_SCOPE = {
+    "token": {
+        "methods": [
+            "token",
+            "password"
+        ],
+        "expires_at": "2020-01-01T00:00:10.000123Z",
+        "domain": {
+            "id": "fake_domain_id",
+            "name": "domain_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
+    }
+}
+
+IDENTITY_V3_RESPONSE_NO_SCOPE = {
+    "token": {
+        "methods": [
+            "token",
+            "password"
+        ],
+        "expires_at": "2020-01-01T00:00:10.000123Z",
+        "user": {
+            "domain": {
+                "id": "fake_domain_id",
+                "name": "domain_name"
+            },
+            "id": "fake_user_id",
+            "name": "username"
+        },
+        "issued_at": "2013-05-29T16:55:21.468960Z",
+    }
+}
+
 ALT_IDENTITY_V3 = IDENTITY_V3_RESPONSE
 
 
@@ -145,6 +188,28 @@
             json.dumps(IDENTITY_V3_RESPONSE))
 
 
+def _fake_v3_response_domain_scope(self, uri, method="GET", body=None,
+                                   headers=None, redirections=5,
+                                   connection_type=None):
+    fake_headers = {
+        "status": "201",
+        "x-subject-token": TOKEN
+    }
+    return (fake_http.fake_http_response(fake_headers, status=201),
+            json.dumps(IDENTITY_V3_RESPONSE_DOMAIN_SCOPE))
+
+
+def _fake_v3_response_no_scope(self, uri, method="GET", body=None,
+                               headers=None, redirections=5,
+                               connection_type=None):
+    fake_headers = {
+        "status": "201",
+        "x-subject-token": TOKEN
+    }
+    return (fake_http.fake_http_response(fake_headers, status=201),
+            json.dumps(IDENTITY_V3_RESPONSE_NO_SCOPE))
+
+
 def _fake_v2_response(self, uri, method="GET", body=None, headers=None,
                       redirections=5, connection_type=None):
     return (fake_http.fake_http_response({}, status=200),
diff --git a/tempest/tests/lib/services/compute/base.py b/tempest/tests/lib/services/compute/base.py
index c805de2..e77b436 100644
--- a/tempest/tests/lib/services/compute/base.py
+++ b/tempest/tests/lib/services/compute/base.py
@@ -15,7 +15,7 @@
 from oslo_serialization import jsonutils as json
 from oslotest import mockpatch
 
-from tempest.tests.lib import base
+from tempest.tests import base
 from tempest.tests.lib import fake_http
 
 
diff --git a/tempest/tests/lib/services/identity/v2/test_token_client.py b/tempest/tests/lib/services/identity/v2/test_token_client.py
index d91ecdc..7925152 100644
--- a/tempest/tests/lib/services/identity/v2/test_token_client.py
+++ b/tempest/tests/lib/services/identity/v2/test_token_client.py
@@ -19,7 +19,7 @@
 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 import base
 from tempest.tests.lib import fake_http
 
 
diff --git a/tempest/tests/lib/services/identity/v3/test_token_client.py b/tempest/tests/lib/services/identity/v3/test_token_client.py
index 52b8e01..e9ef740 100644
--- a/tempest/tests/lib/services/identity/v3/test_token_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_token_client.py
@@ -19,7 +19,7 @@
 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 import base
 from tempest.tests.lib import fake_http
 
 
diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py
index 5502c01..c253187 100644
--- a/tempest/tests/lib/test_auth.py
+++ b/tempest/tests/lib/test_auth.py
@@ -15,6 +15,7 @@
 
 import copy
 import datetime
+import testtools
 
 from oslotest import mockpatch
 
@@ -22,7 +23,7 @@
 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 import base
 from tempest.tests.lib import fake_credentials
 from tempest.tests.lib import fake_identity
 
@@ -41,7 +42,7 @@
 
     def setUp(self):
         super(BaseAuthTestsSetUp, self).setUp()
-        self.stubs.Set(auth, 'get_credentials', fake_get_credentials)
+        self.patchobject(auth, 'get_credentials', fake_get_credentials)
         self.auth_provider = self._auth(self.credentials,
                                         fake_identity.FAKE_AUTH_URL)
 
@@ -118,8 +119,8 @@
 
     def setUp(self):
         super(TestKeystoneV2AuthProvider, self).setUp()
-        self.stubs.Set(v2_client.TokenClient, 'raw_request',
-                       fake_identity._fake_v2_response)
+        self.patchobject(v2_client.TokenClient, 'raw_request',
+                         fake_identity._fake_v2_response)
         self.target_url = 'test_api'
 
     def _get_fake_identity(self):
@@ -425,6 +426,16 @@
             self.assertEqual(self.auth_provider.is_expired(auth_data),
                              should_be_expired)
 
+    def test_set_scope_all_valid(self):
+        for scope in self.auth_provider.SCOPES:
+            self.auth_provider.scope = scope
+            self.assertEqual(scope, self.auth_provider.scope)
+
+    def test_set_scope_invalid(self):
+        with testtools.ExpectedException(exceptions.InvalidScope,
+                                         '.* invalid_scope .*'):
+            self.auth_provider.scope = 'invalid_scope'
+
 
 class TestKeystoneV3AuthProvider(TestKeystoneV2AuthProvider):
     _endpoints = fake_identity.IDENTITY_V3_RESPONSE['token']['catalog']
@@ -433,8 +444,8 @@
 
     def setUp(self):
         super(TestKeystoneV3AuthProvider, self).setUp()
-        self.stubs.Set(v3_client.V3TokenClient, 'raw_request',
-                       fake_identity._fake_v3_response)
+        self.patchobject(v3_client.V3TokenClient, 'raw_request',
+                         fake_identity._fake_v3_response)
 
     def _get_fake_identity(self):
         return fake_identity.IDENTITY_V3_RESPONSE['token']
@@ -529,6 +540,98 @@
         expected = 'http://fake_url/v3'
         self._test_base_url_helper(expected, filters, ('token', auth_data))
 
+    # Base URL test with scope only for V3
+    def test_base_url_scope_project(self):
+        self.auth_provider.scope = 'project'
+        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)
+
+    # Base URL test with scope only for V3
+    def test_base_url_unscoped_identity(self):
+        self.auth_provider.scope = 'unscoped'
+        self.patchobject(v3_client.V3TokenClient, 'raw_request',
+                         fake_identity._fake_v3_response_no_scope)
+        self.filters = {
+            'service': 'identity',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion'
+        }
+        expected = fake_identity.FAKE_AUTH_URL
+        self._test_base_url_helper(expected, self.filters)
+
+    # Base URL test with scope only for V3
+    def test_base_url_unscoped_other(self):
+        self.auth_provider.scope = 'unscoped'
+        self.patchobject(v3_client.V3TokenClient, 'raw_request',
+                         fake_identity._fake_v3_response_no_scope)
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion'
+        }
+        self.assertRaises(exceptions.EndpointNotFound,
+                          self.auth_provider.base_url,
+                          auth_data=self.auth_provider.auth_data,
+                          filters=self.filters)
+
+    def test_auth_parameters_with_scope_unset(self):
+        # No scope defaults to 'project'
+        all_creds = fake_credentials.FakeKeystoneV3AllCredentials()
+        self.auth_provider.credentials = all_creds
+        auth_params = self.auth_provider._auth_params()
+        self.assertNotIn('scope', auth_params.keys())
+        for attr in all_creds.get_init_attributes():
+            if attr.startswith('domain_'):
+                self.assertNotIn(attr, auth_params.keys())
+            else:
+                self.assertIn(attr, auth_params.keys())
+                self.assertEqual(getattr(all_creds, attr), auth_params[attr])
+
+    def test_auth_parameters_with_project_scope(self):
+        all_creds = fake_credentials.FakeKeystoneV3AllCredentials()
+        self.auth_provider.credentials = all_creds
+        self.auth_provider.scope = 'project'
+        auth_params = self.auth_provider._auth_params()
+        self.assertNotIn('scope', auth_params.keys())
+        for attr in all_creds.get_init_attributes():
+            if attr.startswith('domain_'):
+                self.assertNotIn(attr, auth_params.keys())
+            else:
+                self.assertIn(attr, auth_params.keys())
+                self.assertEqual(getattr(all_creds, attr), auth_params[attr])
+
+    def test_auth_parameters_with_domain_scope(self):
+        all_creds = fake_credentials.FakeKeystoneV3AllCredentials()
+        self.auth_provider.credentials = all_creds
+        self.auth_provider.scope = 'domain'
+        auth_params = self.auth_provider._auth_params()
+        self.assertNotIn('scope', auth_params.keys())
+        for attr in all_creds.get_init_attributes():
+            if attr.startswith('project_'):
+                self.assertNotIn(attr, auth_params.keys())
+            else:
+                self.assertIn(attr, auth_params.keys())
+                self.assertEqual(getattr(all_creds, attr), auth_params[attr])
+
+    def test_auth_parameters_unscoped(self):
+        all_creds = fake_credentials.FakeKeystoneV3AllCredentials()
+        self.auth_provider.credentials = all_creds
+        self.auth_provider.scope = 'unscoped'
+        auth_params = self.auth_provider._auth_params()
+        self.assertNotIn('scope', auth_params.keys())
+        for attr in all_creds.get_init_attributes():
+            if attr.startswith('project_') or attr.startswith('domain_'):
+                self.assertNotIn(attr, auth_params.keys())
+            else:
+                self.assertIn(attr, auth_params.keys())
+                self.assertEqual(getattr(all_creds, attr), auth_params[attr])
+
 
 class TestKeystoneV3Credentials(base.TestCase):
     def testSetAttrUserDomain(self):
@@ -630,3 +733,20 @@
         self.assertEqual(
             'http://localhost/identity/v2.0/uuid/',
             auth.replace_version('http://localhost/identity/v3/uuid/', 'v2.0'))
+
+
+class TestKeystoneV3AuthProvider_DomainScope(BaseAuthTestsSetUp):
+    _endpoints = fake_identity.IDENTITY_V3_RESPONSE['token']['catalog']
+    _auth_provider_class = auth.KeystoneV3AuthProvider
+    credentials = fake_credentials.FakeKeystoneV3Credentials()
+
+    def setUp(self):
+        super(TestKeystoneV3AuthProvider_DomainScope, self).setUp()
+        self.patchobject(v3_client.V3TokenClient, 'raw_request',
+                         fake_identity._fake_v3_response_domain_scope)
+
+    def test_get_auth_with_domain_scope(self):
+        self.auth_provider.scope = 'domain'
+        _, auth_data = self.auth_provider.get_auth()
+        self.assertIn('domain', auth_data)
+        self.assertNotIn('project', auth_data)
diff --git a/tempest/tests/lib/test_credentials.py b/tempest/tests/lib/test_credentials.py
index 791fbb5..b6f2cf6 100644
--- a/tempest/tests/lib/test_credentials.py
+++ b/tempest/tests/lib/test_credentials.py
@@ -19,7 +19,7 @@
 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 import base
 from tempest.tests.lib import fake_identity
 
 
@@ -36,8 +36,10 @@
         # Check the right version of credentials has been returned
         self.assertIsInstance(credentials, credentials_class)
         # Check the id attributes are filled in
+        # NOTE(andreaf) project_* attributes are accepted as input but
+        # never set on the credentials object
         attributes = [x for x in credentials.ATTRIBUTES if (
-            '_id' in x and x != 'domain_id')]
+            '_id' in x and x != 'domain_id' and x != 'project_id')]
         for attr in attributes:
             if filled:
                 self.assertIsNotNone(getattr(credentials, attr))
@@ -72,8 +74,8 @@
 
     def setUp(self):
         super(KeystoneV2CredentialsTests, self).setUp()
-        self.stubs.Set(self.tokenclient_class, 'raw_request',
-                       self.identity_response)
+        self.patchobject(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,
diff --git a/tempest/tests/lib/test_decorators.py b/tempest/tests/lib/test_decorators.py
index f83bcbb..f3a4e9c 100644
--- a/tempest/tests/lib/test_decorators.py
+++ b/tempest/tests/lib/test_decorators.py
@@ -18,7 +18,7 @@
 from tempest.lib import base as test
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class TestSkipBecauseDecorator(base.TestCase):
diff --git a/tempest/tests/lib/test_rest_client.py b/tempest/tests/lib/test_rest_client.py
index 90651b0..2a6fad5 100644
--- a/tempest/tests/lib/test_rest_client.py
+++ b/tempest/tests/lib/test_rest_client.py
@@ -22,7 +22,7 @@
 from tempest.lib.common import http
 from tempest.lib.common import rest_client
 from tempest.lib import exceptions
-from tempest.tests.lib import base
+from tempest.tests import base
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib import fake_http
 import tempest.tests.utils as utils
@@ -37,9 +37,7 @@
         self.fake_auth_provider = fake_auth_provider.FakeAuthProvider()
         self.rest_client = rest_client.RestClient(
             self.fake_auth_provider, None, None)
-        self.stubs.Set(http.ClosingHttp, 'request',
-                       self.fake_http.request)
-
+        self.patchobject(http.ClosingHttp, 'request', self.fake_http.request)
         self.useFixture(mockpatch.PatchObject(self.rest_client,
                                               '_log_request'))
 
@@ -549,6 +547,65 @@
         self.assertIsNotNone(str(self.rest_client))
 
 
+class TestRateLimiting(BaseRestClientTestClass):
+
+    def setUp(self):
+        self.fake_http = fake_http.fake_httplib2()
+        super(TestRateLimiting, self).setUp()
+
+    def test__get_retry_after_delay_with_integer(self):
+        resp = {'retry-after': '123'}
+        self.assertEqual(123, self.rest_client._get_retry_after_delay(resp))
+
+    def test__get_retry_after_delay_with_http_date(self):
+        resp = {
+            'date': 'Mon, 4 Apr 2016 21:56:23 GMT',
+            'retry-after': 'Mon, 4 Apr 2016 21:58:26 GMT',
+        }
+        self.assertEqual(123, self.rest_client._get_retry_after_delay(resp))
+
+    def test__get_retry_after_delay_of_zero_with_integer(self):
+        resp = {'retry-after': '0'}
+        self.assertEqual(1, self.rest_client._get_retry_after_delay(resp))
+
+    def test__get_retry_after_delay_of_zero_with_http_date(self):
+        resp = {
+            'date': 'Mon, 4 Apr 2016 21:56:23 GMT',
+            'retry-after': 'Mon, 4 Apr 2016 21:56:23 GMT',
+        }
+        self.assertEqual(1, self.rest_client._get_retry_after_delay(resp))
+
+    def test__get_retry_after_delay_with_missing_date_header(self):
+        resp = {
+            'retry-after': 'Mon, 4 Apr 2016 21:58:26 GMT',
+        }
+        self.assertRaises(ValueError, self.rest_client._get_retry_after_delay,
+                          resp)
+
+    def test__get_retry_after_delay_with_invalid_http_date(self):
+        resp = {
+            'retry-after': 'Mon, 4 AAA 2016 21:58:26 GMT',
+            'date': 'Mon, 4 Apr 2016 21:56:23 GMT',
+        }
+        self.assertRaises(ValueError, self.rest_client._get_retry_after_delay,
+                          resp)
+
+    def test__get_retry_after_delay_with_missing_retry_after_header(self):
+        self.assertRaises(ValueError, self.rest_client._get_retry_after_delay,
+                          {})
+
+    def test_is_absolute_limit_gives_false_with_retry_after(self):
+        resp = {'retry-after': 123}
+
+        # is_absolute_limit() requires the overLimit body to be unwrapped
+        resp_body = self.rest_client._parse_resp("""{
+            "overLimit": {
+                "message": ""
+            }
+        }""")
+        self.assertFalse(self.rest_client.is_absolute_limit(resp, resp_body))
+
+
 class TestProperties(BaseRestClientTestClass):
 
     def setUp(self):
diff --git a/tempest/tests/lib/test_ssh.py b/tempest/tests/lib/test_ssh.py
index d001c51..b07f6bc 100644
--- a/tempest/tests/lib/test_ssh.py
+++ b/tempest/tests/lib/test_ssh.py
@@ -21,7 +21,7 @@
 
 from tempest.lib.common import ssh
 from tempest.lib import exceptions
-from tempest.tests.lib import base
+from tempest.tests import base
 import tempest.tests.utils as utils
 
 
diff --git a/tempest/tests/lib/test_tempest_lib.py b/tempest/tests/lib/test_tempest_lib.py
index 9731e96..d70e53d 100644
--- a/tempest/tests/lib/test_tempest_lib.py
+++ b/tempest/tests/lib/test_tempest_lib.py
@@ -19,7 +19,7 @@
 Tests for `tempest.lib` module.
 """
 
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class TestTempest_lib(base.TestCase):
diff --git a/tempest/tests/negative/test_negative_auto_test.py b/tempest/tests/negative/test_negative_auto_test.py
index c666bd3..44ce567 100644
--- a/tempest/tests/negative/test_negative_auto_test.py
+++ b/tempest/tests/negative/test_negative_auto_test.py
@@ -15,8 +15,8 @@
 
 from tempest import config
 import tempest.test as test
+from tempest.tests import base
 from tempest.tests import fake_config
-from tempest.tests.lib import base
 
 
 class TestNegativeAutoTest(base.TestCase):
@@ -37,7 +37,8 @@
     def setUp(self):
         super(TestNegativeAutoTest, self).setUp()
         self.useFixture(fake_config.ConfigFixture())
-        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+        self.patchobject(config, 'TempestConfigPrivate',
+                         fake_config.FakePrivate)
 
     def _check_prop_entries(self, result, entry):
         entries = [a for a in result if entry in a[0]]
diff --git a/tempest/tests/negative/test_negative_generators.py b/tempest/tests/negative/test_negative_generators.py
index e0d7f42..78fd80d 100644
--- a/tempest/tests/negative/test_negative_generators.py
+++ b/tempest/tests/negative/test_negative_generators.py
@@ -22,7 +22,7 @@
 from tempest.common.generator import base_generator
 from tempest.common.generator import negative_generator
 from tempest.common.generator import valid_generator
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class TestNegativeBasicGenerator(base.TestCase):
diff --git a/tempest/api/telemetry/__init__.py b/tempest/tests/services/object_storage/__init__.py
similarity index 100%
rename from tempest/api/telemetry/__init__.py
rename to tempest/tests/services/object_storage/__init__.py
diff --git a/tempest/tests/services/object_storage/test_object_client.py b/tempest/tests/services/object_storage/test_object_client.py
new file mode 100644
index 0000000..cd8c8f1
--- /dev/null
+++ b/tempest/tests/services/object_storage/test_object_client.py
@@ -0,0 +1,109 @@
+# Copyright 2016 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 mock
+import six
+
+from tempest.lib import exceptions
+from tempest.services.object_storage import object_client
+from tempest.tests import base
+from tempest.tests import fake_auth_provider
+
+
+class TestObjectClient(base.TestCase):
+
+    def setUp(self):
+        super(TestObjectClient, self).setUp()
+        self.fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.url = self.fake_auth.base_url(None)
+        self.object_client = object_client.ObjectClient(self.fake_auth,
+                                                        'swift', 'region1')
+
+    @mock.patch.object(object_client, 'create_connection')
+    def test_create_object_continue_no_data(self, mock_poc):
+        self._validate_create_object_continue(None, mock_poc)
+
+    @mock.patch.object(object_client, 'create_connection')
+    def test_create_object_continue_with_data(self, mock_poc):
+        self._validate_create_object_continue('hello', mock_poc)
+
+    @mock.patch.object(object_client, 'create_connection')
+    def test_create_continue_with_no_continue_received(self, mock_poc):
+        self._validate_create_object_continue('hello', mock_poc,
+                                              initial_status=201)
+
+    def _validate_create_object_continue(self, req_data,
+                                         mock_poc, initial_status=100):
+
+        expected_hdrs = {
+            'X-Auth-Token': self.fake_auth.get_token(),
+            'content-length': 0 if req_data is None else len(req_data),
+            'Expect': '100-continue'}
+
+        # Setup the Mocks prior to invoking the object creation
+        mock_resp_cls = mock.Mock()
+        mock_resp_cls._read_status.return_value = ("1", initial_status, "OK")
+
+        mock_poc.return_value.response_class.return_value = mock_resp_cls
+
+        # This is the final expected return value
+        mock_poc.return_value.getresponse.return_value.status = 201
+        mock_poc.return_value.getresponse.return_value.reason = 'OK'
+
+        # Call method to PUT object using expect:100-continue
+        cnt = "container1"
+        obj = "object1"
+        path = "/%s/%s" % (cnt, obj)
+
+        # If the expected initial status is not 100, then an exception
+        # should be thrown and the connection closed
+        if initial_status is 100:
+            status, reason = \
+                self.object_client.create_object_continue(cnt, obj, req_data)
+        else:
+            self.assertRaises(exceptions.UnexpectedResponseCode,
+                              self.object_client.create_object_continue, cnt,
+                              obj, req_data)
+            mock_poc.return_value.close.assert_called_once_with()
+
+        # Verify that putrequest is called 1 time with the appropriate values
+        mock_poc.return_value.putrequest.assert_called_once_with('PUT', path)
+
+        # Verify that headers were written, including "Expect:100-continue"
+        calls = []
+
+        for header, value in six.iteritems(expected_hdrs):
+            calls.append(mock.call(header, value))
+
+        mock_poc.return_value.putheader.assert_has_calls(calls, False)
+        mock_poc.return_value.endheaders.assert_called_once_with()
+
+        # The following steps are only taken if the initial status is 100
+        if initial_status is 100:
+            # Verify that the method returned what it was supposed to
+            self.assertEqual(status, 201)
+
+            # Verify that _safe_read was called once to remove the CRLF
+            # after the 100 response
+            mock_rc = mock_poc.return_value.response_class.return_value
+            mock_rc._safe_read.assert_called_once_with(2)
+
+            # Verify the actual data was written via send
+            mock_poc.return_value.send.assert_called_once_with(req_data)
+
+            # Verify that the getresponse method was called to receive
+            # the final
+            mock_poc.return_value.getresponse.assert_called_once_with()
diff --git a/tempest/tests/stress/test_stress.py b/tempest/tests/stress/test_stress.py
index a35b4d7..dfe0291 100644
--- a/tempest/tests/stress/test_stress.py
+++ b/tempest/tests/stress/test_stress.py
@@ -18,7 +18,7 @@
 
 from oslo_log import log as logging
 from tempest.lib import exceptions
-from tempest.tests.lib import base
+from tempest.tests import base
 
 LOG = logging.getLogger(__name__)
 
diff --git a/tempest/tests/test_base_test.py b/tempest/tests/test_base_test.py
index 9ffb7a1..dc355b4 100644
--- a/tempest/tests/test_base_test.py
+++ b/tempest/tests/test_base_test.py
@@ -19,8 +19,8 @@
 from tempest.common import fixed_network
 from tempest import config
 from tempest import test
+from tempest.tests import base
 from tempest.tests import fake_config
-from tempest.tests.lib import base
 
 
 class TestBaseTestCase(base.TestCase):
diff --git a/tempest/tests/test_decorators.py b/tempest/tests/test_decorators.py
index 0174160..8c5d861 100644
--- a/tempest/tests/test_decorators.py
+++ b/tempest/tests/test_decorators.py
@@ -21,15 +21,16 @@
 from tempest import exceptions
 from tempest.lib.common.utils import data_utils
 from tempest import test
+from tempest.tests import base
 from tempest.tests import fake_config
-from tempest.tests.lib import base
 
 
 class BaseDecoratorsTest(base.TestCase):
     def setUp(self):
         super(BaseDecoratorsTest, self).setUp()
         self.config_fixture = self.useFixture(fake_config.ConfigFixture())
-        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+        self.patchobject(config, 'TempestConfigPrivate',
+                         fake_config.FakePrivate)
 
 
 class TestAttrDecorator(BaseDecoratorsTest):
@@ -245,3 +246,96 @@
         self.assertIn("test_fake_negative", dir(obj))
         obj.test_fake_negative()
         mock.assert_called_once_with(self.FakeNegativeJSONTest._schema)
+
+
+class TestConfigDecorators(BaseDecoratorsTest):
+    def setUp(self):
+        super(TestConfigDecorators, self).setUp()
+        cfg.CONF.set_default('nova', True, 'service_available')
+        cfg.CONF.set_default('glance', False, 'service_available')
+
+    def _assert_skip_message(self, func, skip_msg):
+        try:
+            func()
+            self.fail()
+        except testtools.TestCase.skipException as skip_exc:
+            self.assertEqual(skip_exc.args[0], skip_msg)
+
+    def _test_skip_unless_config(self, expected_to_skip=True, *decorator_args):
+
+        class TestFoo(test.BaseTestCase):
+            @config.skip_unless_config(*decorator_args)
+            def test_bar(self):
+                return 0
+
+        t = TestFoo('test_bar')
+        if expected_to_skip:
+            self.assertRaises(testtools.TestCase.skipException, t.test_bar)
+            if (len(decorator_args) >= 3):
+                # decorator_args[2]: skip message specified
+                self._assert_skip_message(t.test_bar, decorator_args[2])
+        else:
+            try:
+                self.assertEqual(t.test_bar(), 0)
+            except testtools.TestCase.skipException:
+                # We caught a skipException but we didn't expect to skip
+                # this test so raise a hard test failure instead.
+                raise testtools.TestCase.failureException(
+                    "Not supposed to skip")
+
+    def _test_skip_if_config(self, expected_to_skip=True,
+                             *decorator_args):
+
+        class TestFoo(test.BaseTestCase):
+            @config.skip_if_config(*decorator_args)
+            def test_bar(self):
+                return 0
+
+        t = TestFoo('test_bar')
+        if expected_to_skip:
+            self.assertRaises(testtools.TestCase.skipException, t.test_bar)
+            if (len(decorator_args) >= 3):
+                # decorator_args[2]: skip message specified
+                self._assert_skip_message(t.test_bar, decorator_args[2])
+        else:
+            try:
+                self.assertEqual(t.test_bar(), 0)
+            except testtools.TestCase.skipException:
+                # We caught a skipException but we didn't expect to skip
+                # this test so raise a hard test failure instead.
+                raise testtools.TestCase.failureException(
+                    "Not supposed to skip")
+
+    def test_skip_unless_no_group(self):
+        self._test_skip_unless_config(True, 'fake_group', 'an_option')
+
+    def test_skip_unless_no_option(self):
+        self._test_skip_unless_config(True, 'service_available',
+                                      'not_an_option')
+
+    def test_skip_unless_false_option(self):
+        self._test_skip_unless_config(True, 'service_available', 'glance')
+
+    def test_skip_unless_false_option_msg(self):
+        self._test_skip_unless_config(True, 'service_available', 'glance',
+                                      'skip message')
+
+    def test_skip_unless_true_option(self):
+        self._test_skip_unless_config(False,
+                                      'service_available', 'nova')
+
+    def test_skip_if_no_group(self):
+        self._test_skip_if_config(False, 'fake_group', 'an_option')
+
+    def test_skip_if_no_option(self):
+        self._test_skip_if_config(False, 'service_available', 'not_an_option')
+
+    def test_skip_if_false_option(self):
+        self._test_skip_if_config(False, 'service_available', 'glance')
+
+    def test_skip_if_true_option(self):
+        self._test_skip_if_config(True, 'service_available', 'nova')
+
+    def test_skip_if_true_option_msg(self):
+        self._test_skip_if_config(True, 'service_available', 'nova',
+                                  'skip message')
diff --git a/tempest/tests/test_glance_http.py b/tempest/tests/test_glance_http.py
index fdbc2d2..768cd05 100644
--- a/tempest/tests/test_glance_http.py
+++ b/tempest/tests/test_glance_http.py
@@ -22,8 +22,8 @@
 
 from tempest.common import glance_http
 from tempest import exceptions
+from tempest.tests import base
 from tempest.tests import fake_auth_provider
-from tempest.tests.lib import base
 from tempest.tests.lib import fake_http
 
 
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index 6b3aa0d..aba2aab 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -13,7 +13,7 @@
 #    under the License.
 
 from tempest.hacking import checks
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class HackingTestCase(base.TestCase):
diff --git a/tempest/tests/test_list_tests.py b/tempest/tests/test_list_tests.py
index 69527b1..38d4c5c 100644
--- a/tempest/tests/test_list_tests.py
+++ b/tempest/tests/test_list_tests.py
@@ -17,7 +17,7 @@
 import six
 import subprocess
 
-from tempest.tests.lib import base
+from tempest.tests import base
 
 
 class TestTestList(base.TestCase):
diff --git a/tempest/tests/test_microversions.py b/tempest/tests/test_microversions.py
index 1ac1232..173accb 100644
--- a/tempest/tests/test_microversions.py
+++ b/tempest/tests/test_microversions.py
@@ -18,8 +18,8 @@
 from tempest.api.compute import base as compute_base
 from tempest import config
 from tempest.lib import exceptions
+from tempest.tests import base
 from tempest.tests import fake_config
-from tempest.tests.lib import base
 
 
 class VersionTestNoneTolatest(compute_base.BaseV2ComputeTest):
@@ -57,8 +57,8 @@
     def setUp(self):
         super(TestMicroversionsTestsClass, self).setUp()
         self.useFixture(fake_config.ConfigFixture())
-        self.stubs.Set(config, 'TempestConfigPrivate',
-                       fake_config.FakePrivate)
+        self.patchobject(config, 'TempestConfigPrivate',
+                         fake_config.FakePrivate)
 
     def _test_version(self, cfg_min, cfg_max,
                       expected_pass_tests,
diff --git a/tempest/tests/test_negative_rest_client.py b/tempest/tests/test_negative_rest_client.py
index a1b5f0e..9d9c20f 100644
--- a/tempest/tests/test_negative_rest_client.py
+++ b/tempest/tests/test_negative_rest_client.py
@@ -20,9 +20,9 @@
 
 from tempest.common import negative_rest_client
 from tempest import config
+from tempest.tests import base
 from tempest.tests import fake_auth_provider
 from tempest.tests import fake_config
-from tempest.tests.lib import base
 
 
 class TestNegativeRestClient(base.TestCase):
@@ -32,7 +32,8 @@
     def setUp(self):
         super(TestNegativeRestClient, self).setUp()
         self.useFixture(fake_config.ConfigFixture())
-        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+        self.patchobject(config, 'TempestConfigPrivate',
+                         fake_config.FakePrivate)
         self.negative_rest_client = negative_rest_client.NegativeRestClient(
             fake_auth_provider.FakeAuthProvider(), None)
         self.useFixture(mockpatch.PatchObject(self.negative_rest_client,
diff --git a/tempest/tests/test_tempest_plugin.py b/tempest/tests/test_tempest_plugin.py
index f66dfc8..c07e98c 100644
--- a/tempest/tests/test_tempest_plugin.py
+++ b/tempest/tests/test_tempest_plugin.py
@@ -14,8 +14,8 @@
 #    under the License.
 
 from tempest.test_discover import plugins
+from tempest.tests import base
 from tempest.tests import fake_tempest_plugin as fake_plugin
-from tempest.tests.lib import base
 
 
 class TestPluginDiscovery(base.TestCase):
diff --git a/tempest/tests/test_wrappers.py b/tempest/tests/test_wrappers.py
index edb9061..a4ef699 100644
--- a/tempest/tests/test_wrappers.py
+++ b/tempest/tests/test_wrappers.py
@@ -19,7 +19,7 @@
 
 import six
 
-from tempest.tests.lib import base
+from tempest.tests import base
 
 DEVNULL = open(os.devnull, 'wb')
 
diff --git a/test-requirements.txt b/test-requirements.txt
index bb4b27f..9ef956a 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -7,7 +7,6 @@
 python-subunit>=0.0.18 # Apache-2.0/BSD
 oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
 reno>=1.6.2 # Apache2
-mox>=0.5.3 # Apache-2.0
 mock>=1.2 # BSD
 coverage>=3.6 # Apache-2.0
 oslotest>=1.10.0 # Apache-2.0
diff --git a/tools/check_logs.py b/tools/check_logs.py
index fa7129d..e34dec3 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -54,7 +54,6 @@
     'q-meta',
     'q-metering',
     'q-svc',
-    'q-vpn',
     's-proxy'])
 
 
diff --git a/tox.ini b/tox.ini
index e9b9741..44162fd 100644
--- a/tox.ini
+++ b/tox.ini
@@ -35,6 +35,7 @@
 commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}'
 
 [testenv:all]
+envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
 # 'all' includes slow tests
 setenv =
@@ -45,6 +46,17 @@
     find . -type f -name "*.pyc" -delete
     bash tools/pretty_tox.sh '{posargs}'
 
+[testenv:ostestr]
+sitepackages = {[tempestenv]sitepackages}
+# 'all' includes slow tests
+setenv =
+    {[tempestenv]setenv}
+    OS_TEST_TIMEOUT={env:OS_TEST_TIMEOUT:1200}
+deps = {[tempestenv]deps}
+commands =
+    find . -type f -name "*.pyc" -delete
+    ostestr {posargs}
+
 [testenv:all-plugin]
 sitepackages = True
 # 'all' includes slow tests
@@ -57,6 +69,7 @@
     bash tools/pretty_tox.sh '{posargs}'
 
 [testenv:full]
+envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
@@ -67,6 +80,7 @@
     bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}'
 
 [testenv:full-serial]
+envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
@@ -77,6 +91,7 @@
     bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}'
 
 [testenv:smoke]
+envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
@@ -85,6 +100,7 @@
     bash tools/pretty_tox.sh '\[.*\bsmoke\b.*\] {posargs}'
 
 [testenv:smoke-serial]
+envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
@@ -96,6 +112,7 @@
     bash tools/pretty_tox_serial.sh '\[.*\bsmoke\b.*\] {posargs}'
 
 [testenv:stress]
+envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
@@ -105,6 +122,13 @@
 [testenv:venv]
 commands = {posargs}
 
+[testenv:venv-tempest]
+envdir = .tox/tempest
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+deps = {[tempestenv]deps}
+commands = {posargs}
+
 [testenv:docs]
 commands =
     python setup.py build_sphinx {posargs}