Merge "Add missing test for the object storage v1 API"
diff --git a/HACKING.rst b/HACKING.rst
index b66fa24..480650c 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -21,6 +21,7 @@
 - [T111] Check that service client names of DELETE should be consistent
 - [T112] Check that tempest.lib should not import local tempest code
 - [T113] Check that tests use data_utils.rand_uuid() instead of uuid.uuid4()
+- [T114] Check that tempest.lib does not use tempest config
 - [N322] Method's default argument shouldn't be mutable
 
 Test Data/Configuration
@@ -132,6 +133,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 +142,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`
 
diff --git a/README.rst b/README.rst
index 650a1ed..725a890 100644
--- a/README.rst
+++ b/README.rst
@@ -25,8 +25,7 @@
   discover features of a cloud incorrectly, and give people an
   incorrect assessment of their cloud. Explicit is always better.
 - Tempest uses OpenStack public interfaces. Tests in Tempest should
-  only touch public interfaces, API calls (native or 3rd party),
-  or libraries.
+  only touch public OpenStack APIs.
 - Tempest should not touch private or implementation specific
   interfaces. This means not directly going to the database, not
   directly hitting the hypervisors, not testing extensions not
@@ -163,7 +162,7 @@
 Tempest also has a set of unit tests which test the Tempest code itself. These
 tests can be run by specifying the test discovery path::
 
-    $> OS_TEST_PATH=./tempest/tests testr run --parallel
+    $ OS_TEST_PATH=./tempest/tests testr run --parallel
 
 By setting OS_TEST_PATH to ./tempest/tests it specifies that test discover
 should only be run on the unit test directory. The default value of OS_TEST_PATH
@@ -214,8 +213,8 @@
 To start you need to create a configuration file. The easiest way to create a
 configuration file is to generate a sample in the ``etc/`` directory ::
 
-    $> cd $TEMPEST_ROOT_DIR
-    $> oslo-config-generator --config-file \
+    $ cd $TEMPEST_ROOT_DIR
+    $ oslo-config-generator --config-file \
         etc/config-generator.tempest.conf \
         --output-file etc/tempest.conf
 
@@ -237,21 +236,21 @@
 After setting up your configuration file, you can execute the set of Tempest
 tests by using ``testr`` ::
 
-    $> testr run --parallel
+    $ testr run --parallel
 
 To run one single test serially ::
 
-    $> testr run tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_reboot_non_existent_server
+    $ testr run tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_reboot_non_existent_server
 
 Alternatively, you can use the run_tempest.sh script which will create a venv
 and run the tests or use tox to do the same. Tox also contains several existing
 job configurations. For example::
 
-   $> tox -efull
+   $ tox -efull
 
 which will run the same set of tests as the OpenStack gate. (it's exactly how
 the gate invokes Tempest) Or::
 
-  $> tox -esmoke
+  $ tox -esmoke
 
 to run the tests tagged as smoke.
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index bcb1e3e..9a7ce15 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -27,21 +27,13 @@
 - Generate test credentials on the fly (see `Dynamic Credentials`_)
 
 Tempest allows for configuring pre-provisioned test credentials as well.
-This can be done in two different ways.
-
-One is to provide credentials is using the accounts.yaml file (see
+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.
 
-A second way - now deprecated - is a set of configuration options in the
-tempest.conf file (see `Legacy Credentials`_). These options are clearly
-labelled in the ``identity`` section and let you specify a set of credentials
-for a regular user and an alternate user, consisting of a username, password,
-project and domain name.
-
 Keystone Connection Info
 ^^^^^^^^^^^^^^^^^^^^^^^^
 In order for Tempest to be able to talk to your OpenStack deployment you need
@@ -134,44 +126,6 @@
 
 Pre-Provisioned Credentials are also know as accounts.yaml or accounts file.
 
-Legacy Credentials
-""""""""""""""""""
-**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``
- #. ``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.
-
 Compute
 -------
 
@@ -394,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/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 ad26741..9640469 100644
--- a/doc/source/plugin.rst
+++ b/doc/source/plugin.rst
@@ -15,10 +15,22 @@
 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
 -------------------
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/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-integrated-horizon-bb57551c1e5f5be3.yaml b/releasenotes/notes/remove-integrated-horizon-bb57551c1e5f5be3.yaml
new file mode 100644
index 0000000..294f6d9
--- /dev/null
+++ b/releasenotes/notes/remove-integrated-horizon-bb57551c1e5f5be3.yaml
@@ -0,0 +1,7 @@
+---
+upgrade:
+  - The integrated dashboard scenario test has been
+    removed and is now in a separate tempest plugin
+    tempest-horizon. The removed test coverage can be
+    used by installing tempest-horizon on the server
+    where you run tempest.
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/requirements.txt b/requirements.txt
index dd73257..f41d2a7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,21 +5,21 @@
 cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
 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
-oslo.concurrency>=3.5.0 # Apache-2.0
+oslo.concurrency>=3.8.0 # Apache-2.0
 oslo.config>=3.9.0 # Apache-2.0
 oslo.i18n>=2.1.0 # Apache-2.0
 oslo.log>=1.14.0 # Apache-2.0
 oslo.serialization>=1.10.0 # Apache-2.0
 oslo.utils>=3.5.0 # Apache-2.0
 six>=1.9.0 # MIT
-fixtures<2.0,>=1.3.1 # Apache-2.0/BSD
+fixtures>=3.0.0 # 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
+os-testr>=0.7.0 # Apache-2.0
+urllib3>=1.15.1 # MIT
diff --git a/setup.cfg b/setup.cfg
index 0ddb898..24e0214 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -5,7 +5,7 @@
     README.rst
 author = OpenStack
 author-email = openstack-dev@lists.openstack.org
-home-page = http://www.openstack.org/
+home-page = http://docs.openstack.org/developer/tempest/
 classifier =
     Intended Audience :: Information Technology
     Intended Audience :: System Administrators
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py
index 8986db8..a4ed8dc 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage.py
@@ -59,7 +59,9 @@
                 return True
             except e.InvalidHTTPResponseBody:
                 return False
-        test.call_until_true(is_valid, duration, 1)
+        self.assertEqual(test.call_until_true(is_valid, duration, 1), True,
+                         "%s not return valid response in %s secs" % (
+                             func.__name__, duration))
         return self.resp
 
     @test.idempotent_id('062c8ae9-9912-4249-8b51-e38d664e926e')
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 8201363..fdf55e5 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -13,10 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import netaddr
 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
@@ -125,18 +125,21 @@
 
     def _test_create_interface_by_fixed_ips(self, server, ifs):
         network_id = ifs[0]['net_id']
-        ip_list = [
-            ifs[n]['fixed_ips'][0]['ip_address'] for n in range(0, len(ifs))]
-        ip = str(netaddr.IPAddress(sorted(ip_list)[-1]) + 1)
+        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}]
+        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)
+        self._check_interface(iface, fixed_ip=ip_list[0])
         return iface
 
     def _test_show_interface(self, server, ifs):
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index c05045e..07423ff 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -204,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.
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index f01657b..66aec84 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -226,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
@@ -312,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')
@@ -322,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 = {
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_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 cad22f3..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
@@ -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_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/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_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index b2e52bb..cf05f5f 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -30,6 +30,11 @@
         super(BaseVolumeQuotasAdminV2TestJSON, cls).setup_credentials()
         cls.demo_tenant_id = cls.os.credentials.tenant_id
 
+    def _delete_volume(self, volume_id):
+        # Delete the specified volume using admin credentials
+        self.admin_volume_client.delete_volume(volume_id)
+        self.admin_volume_client.wait_for_resource_deletion(volume_id)
+
     @test.idempotent_id('59eada70-403c-4cef-a2a3-a8ce2f1b07a0')
     def test_list_quotas(self):
         quotas = (self.quotas_client.show_quota_set(self.demo_tenant_id)
@@ -83,8 +88,7 @@
             self.demo_tenant_id)['quota_set']
 
         volume = self.create_volume()
-        self.addCleanup(self.admin_volume_client.delete_volume,
-                        volume['id'])
+        self.addCleanup(self._delete_volume, volume['id'])
 
         new_quota_usage = self.quotas_client.show_quota_usage(
             self.demo_tenant_id)['quota_set']
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index b09cd2c..1289297 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -13,11 +13,15 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import base64
+import six
+
+from oslo_serialization import jsonutils as json
+
 from tempest.api.volume import base
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
-from tempest.lib import decorators
 from tempest import test
 
 CONF = config.CONF
@@ -41,6 +45,20 @@
         self.backups_adm_client.delete_backup(backup_id)
         self.backups_adm_client.wait_for_backup_deletion(backup_id)
 
+    def _decode_url(self, backup_url):
+        return json.loads(base64.decodestring(backup_url))
+
+    def _encode_backup(self, backup):
+        retval = json.dumps(backup)
+        if six.PY3:
+            retval = retval.encode('utf-8')
+        return base64.encodestring(retval)
+
+    def _modify_backup_url(self, backup_url, changes):
+        backup = self._decode_url(backup_url)
+        backup.update(changes)
+        return self._encode_backup(backup)
+
     @test.idempotent_id('a66eb488-8ee1-47d4-8e9f-575a095728c6')
     def test_volume_backup_create_get_detailed_list_restore_delete(self):
         # Create backup
@@ -78,9 +96,13 @@
         waiters.wait_for_volume_status(self.admin_volume_client,
                                        restore['volume_id'], 'available')
 
-    @decorators.skip_because(bug='1455043')
     @test.idempotent_id('a99c54a1-dd80-4724-8a13-13bf58d4068d')
     def test_volume_backup_export_import(self):
+        """Test backup export import functionality.
+
+        Cinder allows exporting DB backup information through its API so it can
+        be imported back in case of a DB loss.
+        """
         # Create backup
         backup_name = data_utils.rand_name('Backup')
         backup = (self.backups_adm_client.create_backup(
@@ -99,25 +121,40 @@
                         'cinder.backup.drivers'))
         self.assertIsNotNone(export_backup['backup_url'])
 
+        # NOTE(geguileo): Backups are imported with the same backup id
+        # (important for incremental backups among other things), so we cannot
+        # import the exported backup information as it is, because that Backup
+        # ID already exists.  So we'll fake the data by changing the backup id
+        # in the exported backup DB info we have retrieved before importing it
+        # back.
+        new_id = data_utils.rand_uuid()
+        new_url = self._modify_backup_url(
+            export_backup['backup_url'], {'id': new_id})
+
         # Import Backup
         import_backup = self.backups_adm_client.import_backup(
             backup_service=export_backup['backup_service'],
-            backup_url=export_backup['backup_url'])['backup']
-        self.addCleanup(self._delete_backup, import_backup['id'])
+            backup_url=new_url)['backup']
+
+        # NOTE(geguileo): We delete both backups, but only one of those
+        # deletions will delete data from the backup back-end because they
+        # were both pointing to the same backend data.
+        self.addCleanup(self._delete_backup, new_id)
         self.assertIn("id", import_backup)
+        self.assertEqual(new_id, import_backup['id'])
         self.backups_adm_client.wait_for_backup_status(import_backup['id'],
                                                        'available')
 
         # Verify Import Backup
         backups = self.backups_adm_client.list_backups(detail=True)['backups']
-        self.assertIn(import_backup['id'], [b['id'] for b in backups])
+        self.assertIn(new_id, [b['id'] for b in backups])
 
         # Restore backup
-        restore = (self.backups_adm_client.restore_backup(import_backup['id'])
-                   ['restore'])
+        restore = self.backups_adm_client.restore_backup(
+            backup['id'])['restore']
         self.addCleanup(self.admin_volume_client.delete_volume,
                         restore['volume_id'])
-        self.assertEqual(import_backup['id'], restore['backup_id'])
+        self.assertEqual(backup['id'], restore['backup_id'])
         waiters.wait_for_volume_status(self.admin_volume_client,
                                        restore['volume_id'], 'available')
 
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/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/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/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 39fed63..72ea894 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -282,8 +282,6 @@
         'object_storage': 'swift',
         'compute': 'nova',
         'orchestration': 'heat',
-        'metering': 'ceilometer',
-        'telemetry': 'ceilometer',
         'data_processing': 'sahara',
         'baremetal': 'ironic',
         'identity': 'keystone',
diff --git a/tempest/common/cred_client.py b/tempest/common/cred_client.py
index 37c9727..b23bc6f 100644
--- a/tempest/common/cred_client.py
+++ b/tempest/common/cred_client.py
@@ -170,6 +170,29 @@
                                                       user['id'],
                                                       role['id'])
 
+    def assign_user_role_on_domain(self, user, role_name, domain=None):
+        """Assign the specified role on a domain
+
+        :param user: a user dict
+        :param role_name: name of the role to be assigned
+        :param domain: (optional) The domain to assign the role on. If not
+                                  specified the default domain of cred_client
+        """
+        # NOTE(andreaf) This method is very specific to the v3 case, and
+        # because of that it's not defined in the parent class.
+        if domain is None:
+            domain = self.creds_domain
+        role = self._check_role_exists(role_name)
+        if not role:
+            msg = 'No "%s" role found' % role_name
+            raise lib_exc.NotFound(msg)
+        try:
+            self.roles_client.assign_user_role_on_domain(
+                domain['id'], user['id'], role['id'])
+        except lib_exc.Conflict:
+            LOG.debug("Role %s already assigned on domain %s for user %s",
+                      role['id'], domain['id'], user['id'])
+
 
 def get_creds_client(identity_client,
                      projects_client,
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 6cb43f3..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
@@ -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 a "\
-              "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..3a3e3c2 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -122,7 +122,9 @@
         project = self.creds_client.create_project(
             name=project_name, description=project_desc)
 
-        username = data_utils.rand_name(root) + suffix
+        # NOTE(andreaf) User and project can be distinguished from the context,
+        # having the same ID in both makes it easier to match them and debug.
+        username = project_name
         user_password = data_utils.rand_password()
         email = data_utils.rand_name(root) + suffix + "@example.com"
         user = self.creds_client.create_user(
@@ -134,6 +136,9 @@
             self.creds_client.assign_user_role(user, project,
                                                self.admin_role)
             role_assigned = True
+            if self.identity_version == 'v3':
+                self.creds_client.assign_user_role_on_domain(
+                    user, CONF.identity.admin_role)
         # Add roles specified in config file
         for conf_role in CONF.auth.tempest_roles:
             self.creds_client.assign_user_role(user, project, conf_role)
@@ -154,6 +159,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/glance_http.py b/tempest/common/glance_http.py
deleted file mode 100644
index 00062de..0000000
--- a/tempest/common/glance_http.py
+++ /dev/null
@@ -1,361 +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.
-
-# Originally copied from python-glanceclient
-
-import copy
-import hashlib
-import posixpath
-import re
-import socket
-import struct
-
-import OpenSSL
-from oslo_log import log as logging
-import six
-from six import moves
-from six.moves import http_client as httplib
-from six.moves.urllib import parse as urlparse
-
-from tempest import exceptions as exc
-
-LOG = logging.getLogger(__name__)
-USER_AGENT = 'tempest'
-CHUNKSIZE = 1024 * 64  # 64kB
-TOKEN_CHARS_RE = re.compile('^[-A-Za-z0-9+/=]*$')
-
-
-class HTTPClient(object):
-
-    def __init__(self, auth_provider, filters, **kwargs):
-        self.auth_provider = auth_provider
-        self.filters = filters
-        self.endpoint = auth_provider.base_url(filters)
-        endpoint_parts = urlparse.urlparse(self.endpoint)
-        self.endpoint_scheme = endpoint_parts.scheme
-        self.endpoint_hostname = endpoint_parts.hostname
-        self.endpoint_port = endpoint_parts.port
-
-        self.connection_class = self._get_connection_class(
-            self.endpoint_scheme)
-        self.connection_kwargs = self._get_connection_kwargs(
-            self.endpoint_scheme, **kwargs)
-
-    @staticmethod
-    def _get_connection_class(scheme):
-        if scheme == 'https':
-            return VerifiedHTTPSConnection
-        else:
-            return httplib.HTTPConnection
-
-    @staticmethod
-    def _get_connection_kwargs(scheme, **kwargs):
-        _kwargs = {'timeout': float(kwargs.get('timeout', 600))}
-
-        if scheme == 'https':
-            _kwargs['ca_certs'] = kwargs.get('ca_certs', None)
-            _kwargs['cert_file'] = kwargs.get('cert_file', None)
-            _kwargs['key_file'] = kwargs.get('key_file', None)
-            _kwargs['insecure'] = kwargs.get('insecure', False)
-            _kwargs['ssl_compression'] = kwargs.get('ssl_compression', True)
-
-        return _kwargs
-
-    def _get_connection(self):
-        _class = self.connection_class
-        try:
-            return _class(self.endpoint_hostname, self.endpoint_port,
-                          **self.connection_kwargs)
-        except httplib.InvalidURL:
-            raise exc.EndpointNotFound
-
-    def _http_request(self, url, method, **kwargs):
-        """Send an http request with the specified characteristics.
-
-        Wrapper around httplib.HTTP(S)Connection.request to handle tasks such
-        as setting headers and error handling.
-        """
-        # Copy the kwargs so we can reuse the original in case of redirects
-        kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
-        kwargs['headers'].setdefault('User-Agent', USER_AGENT)
-
-        self._log_request(method, url, kwargs['headers'])
-
-        conn = self._get_connection()
-
-        try:
-            url_parts = urlparse.urlparse(url)
-            conn_url = posixpath.normpath(url_parts.path)
-            LOG.debug('Actual Path: {path}'.format(path=conn_url))
-            if kwargs['headers'].get('Transfer-Encoding') == 'chunked':
-                conn.putrequest(method, conn_url)
-                for header, value in kwargs['headers'].items():
-                    conn.putheader(header, value)
-                conn.endheaders()
-                chunk = kwargs['body'].read(CHUNKSIZE)
-                # Chunk it, baby...
-                while chunk:
-                    conn.send('%x\r\n%s\r\n' % (len(chunk), chunk))
-                    chunk = kwargs['body'].read(CHUNKSIZE)
-                conn.send('0\r\n\r\n')
-            else:
-                conn.request(method, conn_url, **kwargs)
-            resp = conn.getresponse()
-        except socket.gaierror as e:
-            message = ("Error finding address for %(url)s: %(e)s" %
-                       {'url': url, 'e': e})
-            raise exc.EndpointNotFound(message)
-        except (socket.error, socket.timeout) as e:
-            message = ("Error communicating with %(endpoint)s %(e)s" %
-                       {'endpoint': self.endpoint, 'e': e})
-            raise exc.TimeoutException(message)
-
-        body_iter = ResponseBodyIterator(resp)
-        # Read body into string if it isn't obviously image data
-        if resp.getheader('content-type', None) != 'application/octet-stream':
-            body_str = ''.join([body_chunk for body_chunk in body_iter])
-            body_iter = six.StringIO(body_str)
-            self._log_response(resp, None)
-        else:
-            self._log_response(resp, body_iter)
-
-        return resp, body_iter
-
-    def _log_request(self, method, url, headers):
-        LOG.info('Request: ' + method + ' ' + url)
-        if headers:
-            headers_out = headers
-            if 'X-Auth-Token' in headers and headers['X-Auth-Token']:
-                token = headers['X-Auth-Token']
-                if len(token) > 64 and TOKEN_CHARS_RE.match(token):
-                    headers_out = headers.copy()
-                    headers_out['X-Auth-Token'] = "<Token omitted>"
-                LOG.info('Request Headers: ' + str(headers_out))
-
-    def _log_response(self, resp, body):
-        status = str(resp.status)
-        LOG.info("Response Status: " + status)
-        if resp.getheaders():
-            LOG.info('Response Headers: ' + str(resp.getheaders()))
-        if body:
-            str_body = str(body)
-            length = len(body)
-            LOG.info('Response Body: ' + str_body[:2048])
-            if length >= 2048:
-                self.LOG.debug("Large body (%d) md5 summary: %s", length,
-                               hashlib.md5(str_body).hexdigest())
-
-    def raw_request(self, method, url, **kwargs):
-        kwargs.setdefault('headers', {})
-        kwargs['headers'].setdefault('Content-Type',
-                                     'application/octet-stream')
-        if 'body' in kwargs:
-            if (hasattr(kwargs['body'], 'read')
-                    and method.lower() in ('post', 'put')):
-                # We use 'Transfer-Encoding: chunked' because
-                # body size may not always be known in advance.
-                kwargs['headers']['Transfer-Encoding'] = 'chunked'
-
-        # Decorate the request with auth
-        req_url, kwargs['headers'], kwargs['body'] = \
-            self.auth_provider.auth_request(
-                method=method, url=url, headers=kwargs['headers'],
-                body=kwargs.get('body', None), filters=self.filters)
-        return self._http_request(req_url, method, **kwargs)
-
-
-class OpenSSLConnectionDelegator(object):
-    """An OpenSSL.SSL.Connection delegator.
-
-    Supplies an additional 'makefile' method which httplib requires
-    and is not present in OpenSSL.SSL.Connection.
-
-    Note: Since it is not possible to inherit from OpenSSL.SSL.Connection
-    a delegator must be used.
-    """
-    def __init__(self, *args, **kwargs):
-        self.connection = OpenSSL.SSL.Connection(*args, **kwargs)
-
-    def __getattr__(self, name):
-        return getattr(self.connection, name)
-
-    def makefile(self, *args, **kwargs):
-        # Ensure the socket is closed when this file is closed
-        kwargs['close'] = True
-        return socket._fileobject(self.connection, *args, **kwargs)
-
-
-class VerifiedHTTPSConnection(httplib.HTTPSConnection):
-    """Extended HTTPSConnection which uses OpenSSL library for enhanced SSL
-
-    Note: Much of this functionality can eventually be replaced
-          with native Python 3.3 code.
-    """
-    def __init__(self, host, port=None, key_file=None, cert_file=None,
-                 ca_certs=None, timeout=None, insecure=False,
-                 ssl_compression=True):
-        httplib.HTTPSConnection.__init__(self, host, port,
-                                         key_file=key_file,
-                                         cert_file=cert_file)
-        self.key_file = key_file
-        self.cert_file = cert_file
-        self.timeout = timeout
-        self.insecure = insecure
-        self.ssl_compression = ssl_compression
-        self.ca_certs = ca_certs
-        self.setcontext()
-
-    @staticmethod
-    def host_matches_cert(host, x509):
-        """Verify that the x509 certificate we have received from 'host'
-
-        Identifies the server we are connecting to, ie that the certificate's
-        Common Name or a Subject Alternative Name matches 'host'.
-        """
-        # First see if we can match the CN
-        if x509.get_subject().commonName == host:
-            return True
-
-        # Also try Subject Alternative Names for a match
-        san_list = None
-        for i in moves.xrange(x509.get_extension_count()):
-            ext = x509.get_extension(i)
-            if ext.get_short_name() == 'subjectAltName':
-                san_list = str(ext)
-                for san in ''.join(san_list.split()).split(','):
-                    if san == "DNS:%s" % host:
-                        return True
-
-        # Server certificate does not match host
-        msg = ('Host "%s" does not match x509 certificate contents: '
-               'CommonName "%s"' % (host, x509.get_subject().commonName))
-        if san_list is not None:
-            msg = msg + ', subjectAltName "%s"' % san_list
-        raise exc.SSLCertificateError(msg)
-
-    def verify_callback(self, connection, x509, errnum,
-                        depth, preverify_ok):
-        if x509.has_expired():
-            msg = "SSL Certificate expired on '%s'" % x509.get_notAfter()
-            raise exc.SSLCertificateError(msg)
-
-        if depth == 0 and preverify_ok is True:
-            # We verify that the host matches against the last
-            # certificate in the chain
-            return self.host_matches_cert(self.host, x509)
-        else:
-            # Pass through OpenSSL's default result
-            return preverify_ok
-
-    def setcontext(self):
-        """Set up the OpenSSL context."""
-        self.context = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
-
-        if self.ssl_compression is False:
-            self.context.set_options(0x20000)  # SSL_OP_NO_COMPRESSION
-
-        if self.insecure is not True:
-            self.context.set_verify(OpenSSL.SSL.VERIFY_PEER,
-                                    self.verify_callback)
-        else:
-            self.context.set_verify(OpenSSL.SSL.VERIFY_NONE,
-                                    self.verify_callback)
-
-        if self.cert_file:
-            try:
-                self.context.use_certificate_file(self.cert_file)
-            except Exception as e:
-                msg = 'Unable to load cert from "%s" %s' % (self.cert_file, e)
-                raise exc.SSLConfigurationError(msg)
-            if self.key_file is None:
-                # We support having key and cert in same file
-                try:
-                    self.context.use_privatekey_file(self.cert_file)
-                except Exception as e:
-                    msg = ('No key file specified and unable to load key '
-                           'from "%s" %s' % (self.cert_file, e))
-                    raise exc.SSLConfigurationError(msg)
-
-        if self.key_file:
-            try:
-                self.context.use_privatekey_file(self.key_file)
-            except Exception as e:
-                msg = 'Unable to load key from "%s" %s' % (self.key_file, e)
-                raise exc.SSLConfigurationError(msg)
-
-        if self.ca_certs:
-            try:
-                self.context.load_verify_locations(self.ca_certs)
-            except Exception as e:
-                msg = 'Unable to load CA from "%s" %s' % (self.ca_certs, e)
-                raise exc.SSLConfigurationError(msg)
-        else:
-            self.context.set_default_verify_paths()
-
-    def connect(self):
-        """Connect to SSL port and apply per-connection parameters."""
-        try:
-            addresses = socket.getaddrinfo(self.host,
-                                           self.port,
-                                           socket.AF_UNSPEC,
-                                           socket.SOCK_STREAM)
-        except OSError as msg:
-            raise exc.RestClientException(msg)
-        for res in addresses:
-            af, socktype, proto, canonname, sa = res
-            sock = socket.socket(af, socket.SOCK_STREAM)
-
-            if self.timeout is not None:
-                # '0' microseconds
-                sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO,
-                                struct.pack('LL', self.timeout, 0))
-            self.sock = OpenSSLConnectionDelegator(self.context, sock)
-            try:
-                self.sock.connect(sa)
-            except OSError as msg:
-                if self.sock:
-                    self.sock = None
-                    continue
-            break
-        if self.sock is None:
-            # Happen only when all results have failed.
-            raise exc.RestClientException('Cannot connect to %s' % self.host)
-
-    def close(self):
-        if self.sock:
-            # Remove the reference to the socket but don't close it yet.
-            # Response close will close both socket and associated
-            # file. Closing socket too soon will cause response
-            # reads to fail with socket IO error 'Bad file descriptor'.
-            self.sock = None
-        httplib.HTTPSConnection.close(self)
-
-
-class ResponseBodyIterator(object):
-    """A class that acts as an iterator over an HTTP response."""
-
-    def __init__(self, resp):
-        self.resp = resp
-
-    def __iter__(self):
-        while True:
-            yield self.next()
-
-    def next(self):
-        chunk = self.resp.read(CHUNKSIZE)
-        if chunk:
-            return chunk
-        else:
-            raise StopIteration()
diff --git a/tempest/common/preprov_creds.py b/tempest/common/preprov_creds.py
index 51f723b..42c69d5 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:
@@ -241,6 +249,9 @@
             raise lib_exc.InvalidCredentials(
                 "Account file %s doesn't exist" % self.test_accounts_file)
         useable_hashes = self._get_match_hash_list(roles)
+        if len(useable_hashes) == 0:
+            msg = 'No users configured for type/roles %s' % roles
+            raise lib_exc.InvalidCredentials(msg)
         free_hash = self._get_free_hash(useable_hashes)
         clean_creds = self._sanitize_creds(
             self.hash_dict['creds'][free_hash])
@@ -262,13 +273,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 +362,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/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 3e0f28f..3810ceb 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -160,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"),
@@ -402,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.'),
@@ -672,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')]),
 ]
@@ -881,65 +841,6 @@
                help="Value must match heat configuration of the same name."),
 ]
 
-
-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")
-
-DashboardGroup = [
-    cfg.StrOpt('dashboard_url',
-               default='http://localhost/',
-               help="Where the dashboard can be found"),
-    cfg.StrOpt('login_url',
-               default='http://localhost/auth/login/',
-               help="Login page for the dashboard",
-               deprecated_for_removal=True),
-]
-
-
 data_processing_group = cfg.OptGroup(name="data-processing",
                                      title="Data Processing options")
 
@@ -1070,15 +971,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"),
     cfg.BoolOpt('sahara',
                 default=False,
                 help="Whether or not Sahara is expected to be available"),
@@ -1221,10 +1113,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),
     (stress_group, StressGroup),
@@ -1292,9 +1180,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[
             'data-processing-feature-enabled']
@@ -1305,12 +1190,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):
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 5943adf..09106d1 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.*')
@@ -257,6 +256,23 @@
     yield (0, msg)
 
 
+def dont_use_config_in_tempest_lib(logical_line, filename):
+    """Check that tempest.lib doesn't use tempest config
+
+    T114
+    """
+
+    if 'tempest/lib/' not in filename:
+        return
+
+    if ('tempest.config' in logical_line
+        or 'from tempest import config' in logical_line
+        or 'oslo_config' in logical_line):
+        msg = ('T114: tempest.lib can not have any dependency on tempest '
+               'config.')
+        yield(0, msg)
+
+
 def factory(register):
     register(import_no_clients_in_api_and_scenario_tests)
     register(scenario_tests_need_service_tags)
@@ -269,4 +285,5 @@
     register(get_resources_on_service_clients)
     register(delete_resources_on_service_clients)
     register(dont_import_local_tempest_into_lib)
+    register(dont_use_config_in_tempest_lib)
     register(use_rand_uuid_instead_of_uuid4)
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/lib/api_schema/response/compute/v2_1/images.py b/tempest/lib/api_schema/response/compute/v2_1/images.py
index daab898..b0f1934 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/images.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/images.py
@@ -77,7 +77,7 @@
                     'properties': {
                         'id': {'type': 'string'},
                         'links': image_links,
-                        'name': {'type': 'string'}
+                        'name': {'type': ['string', 'null']}
                     },
                     'additionalProperties': False,
                     'required': ['id', 'links', 'name']
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..a43d002 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)
 
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index d001d27..627143d 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
@@ -220,6 +221,10 @@
         :raises exceptions.InvalidHttpSuccessCode: if the read code isn't an
                                                    expected http success code
         """
+        if not isinstance(read_code, int):
+            raise TypeError("'read_code' must be an int instead of (%s)"
+                            % type(read_code))
+
         assert_msg = ("This function only allowed to use for HTTP status"
                       "codes which explicitly defined in the RFC 7231 & 4918."
                       "{0} is not a defined Success Code!"
@@ -242,7 +247,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 +258,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 +312,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 +322,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 +408,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 +421,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 +527,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 +537,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 +550,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 +563,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 +600,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 +640,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 +649,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 +660,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 +831,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 9605479..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
@@ -196,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/decorators.py b/tempest/lib/decorators.py
index e78e624..6ed99b4 100644
--- a/tempest/lib/decorators.py
+++ b/tempest/lib/decorators.py
@@ -69,12 +69,11 @@
                                "or False") % attr
 
     def __call__(self, func):
+        @functools.wraps(func)
         def _skipper(*args, **kw):
             """Wrapped skipper function."""
             testobj = args[0]
             if not getattr(testobj, self.attr, False):
                 raise testtools.TestCase.skipException(self.message)
             func(*args, **kw)
-        _skipper.__name__ = func.__name__
-        _skipper.__doc__ = func.__doc__
         return _skipper
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
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/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 956fe88..7389722 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -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:
@@ -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:
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
deleted file mode 100644
index 5d4f7b3..0000000
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from six.moves import html_parser as HTMLParser
-from six.moves.urllib import parse
-from six.moves.urllib import request
-
-from tempest import config
-from tempest.scenario import manager
-from tempest import test
-
-CONF = config.CONF
-
-
-class HorizonHTMLParser(HTMLParser.HTMLParser):
-    csrf_token = None
-    region = None
-    login = None
-
-    def _find_name(self, attrs, name):
-        for attrpair in attrs:
-            if attrpair[0] == 'name' and attrpair[1] == name:
-                return True
-        return False
-
-    def _find_value(self, attrs):
-        for attrpair in attrs:
-            if attrpair[0] == 'value':
-                return attrpair[1]
-        return None
-
-    def _find_attr_value(self, attrs, attr_name):
-        for attrpair in attrs:
-            if attrpair[0] == attr_name:
-                return attrpair[1]
-        return None
-
-    def handle_starttag(self, tag, attrs):
-        if tag == 'input':
-            if self._find_name(attrs, 'csrfmiddlewaretoken'):
-                self.csrf_token = self._find_value(attrs)
-            if self._find_name(attrs, 'region'):
-                self.region = self._find_value(attrs)
-        if tag == 'form':
-            self.login = self._find_attr_value(attrs, 'action')
-
-
-class TestDashboardBasicOps(manager.ScenarioTest):
-
-    """The test suite for dashboard basic operations
-
-    This is a basic scenario test:
-    * checks that the login page is available
-    * logs in as a regular user
-    * checks that the user home page loads without error
-    """
-
-    @classmethod
-    def skip_checks(cls):
-        super(TestDashboardBasicOps, cls).skip_checks()
-        if not CONF.service_available.horizon:
-            raise cls.skipException("Horizon support is required")
-
-    @classmethod
-    def setup_credentials(cls):
-        cls.set_network_resources()
-        super(TestDashboardBasicOps, cls).setup_credentials()
-
-    def check_login_page(self):
-        response = request.urlopen(CONF.dashboard.dashboard_url)
-        self.assertIn("id_username", response.read())
-
-    def user_login(self, username, password):
-        self.opener = request.build_opener(request.HTTPCookieProcessor())
-        response = self.opener.open(CONF.dashboard.dashboard_url).read()
-
-        # Grab the CSRF token and default region
-        parser = HorizonHTMLParser()
-        parser.feed(response)
-
-        # construct login url for dashboard, discovery accommodates non-/ web
-        # root for dashboard
-        login_url = parse.urljoin(CONF.dashboard.dashboard_url, parser.login)
-
-        # Prepare login form request
-        req = request.Request(login_url)
-        req.add_header('Content-type', 'application/x-www-form-urlencoded')
-        req.add_header('Referer', CONF.dashboard.dashboard_url)
-
-        # Pass the default domain name regardless of the auth version in order
-        # to test the scenario of when horizon is running with keystone v3
-        params = {'username': username,
-                  'password': password,
-                  'region': parser.region,
-                  'domain': CONF.auth.default_credentials_domain_name,
-                  'csrfmiddlewaretoken': parser.csrf_token}
-        self.opener.open(req, parse.urlencode(params))
-
-    def check_home_page(self):
-        response = self.opener.open(CONF.dashboard.dashboard_url)
-        self.assertIn('Overview', response.read())
-
-    @test.idempotent_id('4f8851b1-0e69-482b-b63b-84c6e76f6c80')
-    @test.services('dashboard')
-    def test_basic_scenario(self):
-        creds = self.os.credentials
-        self.check_login_page()
-        self.user_login(creds.username, creds.password)
-        self.check_home_page()
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index b9fdd18..f0ae223 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -754,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.
@@ -778,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/services/baremetal/base.py b/tempest/services/baremetal/base.py
index 6e24801..2bdd092 100644
--- a/tempest/services/baremetal/base.py
+++ b/tempest/services/baremetal/base.py
@@ -111,7 +111,7 @@
             uri += "?%s" % urllib.urlencode(kwargs)
 
         resp, body = self.get(uri)
-        self.expected_success(200, resp['status'])
+        self.expected_success(200, resp.status)
 
         return resp, self.deserialize(body)
 
@@ -127,7 +127,7 @@
         else:
             uri = self._get_uri(resource, uuid=uuid, permanent=permanent)
         resp, body = self.get(uri)
-        self.expected_success(200, resp['status'])
+        self.expected_success(200, resp.status)
 
         return resp, self.deserialize(body)
 
@@ -145,7 +145,7 @@
         uri = self._get_uri(resource)
 
         resp, body = self.post(uri, body=body)
-        self.expected_success(201, resp['status'])
+        self.expected_success(201, resp.status)
 
         return resp, self.deserialize(body)
 
@@ -160,7 +160,7 @@
         uri = self._get_uri(resource, uuid)
 
         resp, body = self.delete(uri)
-        self.expected_success(204, resp['status'])
+        self.expected_success(204, resp.status)
         return resp, body
 
     def _patch_request(self, resource, uuid, patch_object):
@@ -176,7 +176,7 @@
         patch_body = json.dumps(patch_object)
 
         resp, body = self.patch(uri, body=patch_body)
-        self.expected_success(200, resp['status'])
+        self.expected_success(200, resp.status)
         return resp, self.deserialize(body)
 
     @handle_errors
@@ -201,5 +201,5 @@
         put_body = json.dumps(put_object)
 
         resp, body = self.put(uri, body=put_body)
-        self.expected_success(202, resp['status'])
+        self.expected_success([202, 204], resp.status)
         return resp, body
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..922b626 100644
--- a/tempest/services/image/v1/json/images_client.py
+++ b/tempest/services/image/v1/json/images_client.py
@@ -15,21 +15,19 @@
 
 import copy
 import errno
+import functools
 import os
-import time
 
 from oslo_log import log as logging
 from oslo_serialization import jsonutils as json
 import six
 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__)
+CHUNKSIZE = 1024 * 64  # 64kB
 
 
 class ImagesClient(rest_client.RestClient):
@@ -37,9 +35,6 @@
     def __init__(self, auth_provider, catalog_type, region, **kwargs):
         super(ImagesClient, self).__init__(
             auth_provider, catalog_type, region, **kwargs)
-        self._http = None
-        self.dscv = kwargs.get("disable_ssl_certificate_validation")
-        self.ca_certs = kwargs.get("ca_certs")
 
     def _image_meta_from_headers(self, headers):
         meta = {'properties': {}}
@@ -106,27 +101,29 @@
             # Cannot determine size of input image
             return None
 
-    def _get_http(self):
-        return glance_http.HTTPClient(auth_provider=self.auth_provider,
-                                      filters=self.filters,
-                                      insecure=self.dscv,
-                                      ca_certs=self.ca_certs)
-
     def _create_with_data(self, headers, data):
-        resp, body_iter = self.http.raw_request('POST', '/v1/images',
-                                                headers=headers, body=data)
+        # We are going to do chunked transfert, so split the input data
+        # info fixed-sized chunks.
+        headers['Content-Type'] = 'application/octet-stream'
+        data = iter(functools.partial(data.read, CHUNKSIZE), b'')
+        resp, body = self.request('POST', '/v1/images',
+                                  headers=headers, body=data, chunked=True)
         self._error_checker('POST', '/v1/images', headers, data, resp,
-                            body_iter)
-        body = json.loads(''.join([c for c in body_iter]))
+                            body)
+        body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
     def _update_with_data(self, image_id, headers, data):
+        # We are going to do chunked transfert, so split the input data
+        # info fixed-sized chunks.
+        headers['Content-Type'] = 'application/octet-stream'
+        data = iter(functools.partial(data.read, CHUNKSIZE), b'')
         url = '/v1/images/%s' % image_id
-        resp, body_iter = self.http.raw_request('PUT', url, headers=headers,
-                                                body=data)
+        resp, body = self.request('PUT', url, headers=headers,
+                                  body=data, chunked=True)
         self._error_checker('PUT', url, headers, data,
-                            resp, body_iter)
-        body = json.loads(''.join([c for c in body_iter]))
+                            resp, body)
+        body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
     @property
@@ -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..88eafe1 100644
--- a/tempest/services/image/v2/json/images_client.py
+++ b/tempest/services/image/v2/json/images_client.py
@@ -13,34 +13,22 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import functools
+
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
-from tempest.common import glance_http
 from tempest.lib.common import rest_client
 from tempest.lib import exceptions as lib_exc
 
+CHUNKSIZE = 1024 * 64  # 64kB
 
-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")
-        self.ca_certs = kwargs.get("ca_certs")
-
-    def _get_http(self):
-        return glance_http.HTTPClient(auth_provider=self.auth_provider,
-                                      filters=self.filters,
-                                      insecure=self.dscv,
-                                      ca_certs=self.ca_certs)
-
-    @property
-    def http(self):
-        if self._http is None:
-            self._http = self._get_http()
-        return self._http
 
     def update_image(self, image_id, patch):
         """Update an image.
@@ -118,9 +106,14 @@
 
     def store_image_file(self, image_id, data):
         url = 'v2/images/%s/file' % image_id
+
+        # We are going to do chunked transfert, so split the input data
+        # info fixed-sized chunks.
         headers = {'Content-Type': 'application/octet-stream'}
-        resp, body = self.http.raw_request('PUT', url, headers=headers,
-                                           body=data)
+        data = iter(functools.partial(data.read, CHUNKSIZE), b'')
+
+        resp, body = self.request('PUT', url, headers=headers,
+                                  body=data, chunked=True)
         self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp, body)
 
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 0acd4ad..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,51 +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"""
+    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'
-
         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,
@@ -211,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..d31c509 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -77,8 +77,6 @@
         'network': True,
         '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
     }
@@ -93,8 +91,8 @@
     """
     def decorator(f):
         services = ['compute', 'image', 'baremetal', 'volume', 'orchestration',
-                    'network', 'identity', 'object_storage', 'dashboard',
-                    'telemetry', 'data_processing', 'database']
+                    'network', 'identity', 'object_storage', 'data_processing',
+                    'database']
         for service in args:
             if service not in services:
                 raise exceptions.InvalidServiceTag('%s is not a valid '
@@ -350,11 +348,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/common/test_alt_available.py b/tempest/tests/common/test_alt_available.py
index d4cfab6..27db95c 100644
--- a/tempest/tests/common/test_alt_available.py
+++ b/tempest/tests/common/test_alt_available.py
@@ -49,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)
@@ -97,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 3c242b3..0000000
--- a/tempest/tests/common/test_configured_creds.py
+++ /dev/null
@@ -1,131 +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 base
-from tempest.tests import fake_config
-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.patchobject(config, 'TempestConfigPrivate',
-                         fake_config.FakePrivate)
-        self.patchobject(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 00f2d39..0000000
--- a/tempest/tests/common/test_credentials.py
+++ /dev/null
@@ -1,37 +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 base
-from tempest.tests import fake_config
-
-
-class TestLegacyCredentialsProvider(base.TestCase):
-
-    fixed_params = {'identity_version': 'v2'}
-
-    def setUp(self):
-        super(TestLegacyCredentialsProvider, self).setUp()
-        self.useFixture(fake_config.ConfigFixture())
-        self.patchobject(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_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index 8d4f33b..f025418 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -21,15 +21,19 @@
 from tempest import config
 from tempest import exceptions
 from tempest.lib.common import rest_client
-from tempest.lib.services.identity.v2 import token_client as json_token_client
-from tempest.services.identity.v2.json import identity_client as \
-    json_iden_client
-from tempest.services.identity.v2.json import roles_client as \
-    json_roles_client
+from tempest.lib.services.identity.v2 import token_client as v2_token_client
+from tempest.lib.services.identity.v3 import token_client as v3_token_client
+from tempest.services.identity.v2.json import identity_client as v2_iden_client
+from tempest.services.identity.v2.json import roles_client as v2_roles_client
 from tempest.services.identity.v2.json import tenants_client as \
-    json_tenants_client
-from tempest.services.identity.v2.json import users_client as \
-    json_users_client
+    v2_tenants_client
+from tempest.services.identity.v2.json import users_client as v2_users_client
+from tempest.services.identity.v3.json import domains_client
+from tempest.services.identity.v3.json import identity_client as v3_iden_client
+from tempest.services.identity.v3.json import projects_client as \
+    v3_projects_client
+from tempest.services.identity.v3.json import roles_client as v3_roles_client
+from tempest.services.identity.v3.json import users_clients as v3_users_client
 from tempest.services.network.json import routers_client
 from tempest.tests import base
 from tempest.tests import fake_config
@@ -43,13 +47,24 @@
                     'identity_version': 'v2',
                     'admin_role': 'admin'}
 
+    token_client = v2_token_client
+    iden_client = v2_iden_client
+    roles_client = v2_roles_client
+    tenants_client = v2_tenants_client
+    users_client = v2_users_client
+    token_client_class = token_client.TokenClient
+    fake_response = fake_identity._fake_v2_response
+    assign_role_on_project = 'assign_user_role'
+    tenants_client_class = tenants_client.TenantsClient
+    delete_tenant = 'delete_tenant'
+
     def setUp(self):
         super(TestDynamicCredentialProvider, self).setUp()
         self.useFixture(fake_config.ConfigFixture())
         self.patchobject(config, 'TempestConfigPrivate',
                          fake_config.FakePrivate)
-        self.patchobject(json_token_client.TokenClient, 'raw_request',
-                         fake_identity._fake_v2_response)
+        self.patchobject(self.token_client_class, 'raw_request',
+                         self.fake_response)
         cfg.CONF.set_default('operator_role', 'FakeRole',
                              group='object-storage')
         self._mock_list_ec2_credentials('fake_user_id', 'fake_tenant_id')
@@ -59,7 +74,7 @@
     def test_tempest_client(self):
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
         self.assertIsInstance(creds.identity_admin_client,
-                              json_iden_client.IdentityClient)
+                              self.iden_client.IdentityClient)
 
     def _get_fake_admin_creds(self):
         return credentials.get_credentials(
@@ -70,7 +85,7 @@
 
     def _mock_user_create(self, id, name):
         user_fix = self.useFixture(mockpatch.PatchObject(
-            json_users_client.UsersClient,
+            self.users_client.UsersClient,
             'create_user',
             return_value=(rest_client.ResponseBody
                           (200, {'user': {'id': id, 'name': name}}))))
@@ -78,7 +93,7 @@
 
     def _mock_tenant_create(self, id, name):
         tenant_fix = self.useFixture(mockpatch.PatchObject(
-            json_tenants_client.TenantsClient,
+            self.tenants_client.TenantsClient,
             'create_tenant',
             return_value=(rest_client.ResponseBody
                           (200, {'tenant': {'id': id, 'name': name}}))))
@@ -86,7 +101,7 @@
 
     def _mock_list_roles(self, id, name):
         roles_fix = self.useFixture(mockpatch.PatchObject(
-            json_roles_client.RolesClient,
+            self.roles_client.RolesClient,
             'list_roles',
             return_value=(rest_client.ResponseBody
                           (200,
@@ -97,7 +112,7 @@
 
     def _mock_list_2_roles(self):
         roles_fix = self.useFixture(mockpatch.PatchObject(
-            json_roles_client.RolesClient,
+            self.roles_client.RolesClient,
             'list_roles',
             return_value=(rest_client.ResponseBody
                           (200,
@@ -108,24 +123,25 @@
 
     def _mock_assign_user_role(self):
         tenant_fix = self.useFixture(mockpatch.PatchObject(
-            json_roles_client.RolesClient,
-            'assign_user_role',
+            self.roles_client.RolesClient,
+            self.assign_role_on_project,
             return_value=(rest_client.ResponseBody
                           (200, {}))))
         return tenant_fix
 
     def _mock_list_role(self):
         roles_fix = self.useFixture(mockpatch.PatchObject(
-            json_roles_client.RolesClient,
+            self.roles_client.RolesClient,
             'list_roles',
             return_value=(rest_client.ResponseBody
-                          (200, {'roles': [{'id': '1',
-                                 'name': 'FakeRole'}]}))))
+                          (200, {'roles': [
+                              {'id': '1', 'name': 'FakeRole'},
+                              {'id': '2', 'name': 'Member'}]}))))
         return roles_fix
 
     def _mock_list_ec2_credentials(self, user_id, tenant_id):
         ec2_creds_fix = self.useFixture(mockpatch.PatchObject(
-            json_users_client.UsersClient,
+            self.users_client.UsersClient,
             'list_user_ec2_credentials',
             return_value=(rest_client.ResponseBody
                           (200, {'credentials': [{
@@ -180,12 +196,12 @@
         self._mock_user_create('1234', 'fake_admin_user')
         self._mock_tenant_create('1234', 'fake_admin_tenant')
 
-        user_mock = mock.patch.object(json_roles_client.RolesClient,
-                                      'assign_user_role')
+        user_mock = mock.patch.object(self.roles_client.RolesClient,
+                                      self.assign_role_on_project)
         user_mock.start()
         self.addCleanup(user_mock.stop)
-        with mock.patch.object(json_roles_client.RolesClient,
-                               'assign_user_role') as user_mock:
+        with mock.patch.object(self.roles_client.RolesClient,
+                               self.assign_role_on_project) as user_mock:
             admin_creds = creds.get_admin_creds()
         user_mock.assert_has_calls([
             mock.call('1234', '1234', '1234')])
@@ -203,12 +219,12 @@
         self._mock_user_create('1234', 'fake_role_user')
         self._mock_tenant_create('1234', 'fake_role_tenant')
 
-        user_mock = mock.patch.object(json_roles_client.RolesClient,
-                                      'assign_user_role')
+        user_mock = mock.patch.object(self.roles_client.RolesClient,
+                                      self.assign_role_on_project)
         user_mock.start()
         self.addCleanup(user_mock.stop)
-        with mock.patch.object(json_roles_client.RolesClient,
-                               'assign_user_role') as user_mock:
+        with mock.patch.object(self.roles_client.RolesClient,
+                               self.assign_role_on_project) as user_mock:
             role_creds = creds.get_creds_by_roles(
                 roles=['role1', 'role2'])
         calls = user_mock.mock_calls
@@ -240,12 +256,10 @@
         self._mock_user_create('123456', 'fake_admin_user')
         self._mock_list_roles('123456', 'admin')
         creds.get_admin_creds()
-        user_mock = self.patch(
-            'tempest.services.identity.v2.json.users_client.'
-            'UsersClient.delete_user')
-        tenant_mock = self.patch(
-            'tempest.services.identity.v2.json.tenants_client.'
-            'TenantsClient.delete_tenant')
+        user_mock = self.patchobject(self.users_client.UsersClient,
+                                     'delete_user')
+        tenant_mock = self.patchobject(self.tenants_client_class,
+                                       self.delete_tenant)
         creds.clear_creds()
         # Verify user delete calls
         calls = user_mock.mock_calls
@@ -374,18 +388,13 @@
         self._mock_router_create('123456', 'fake_admin_router')
         self._mock_list_roles('123456', 'admin')
         creds.get_admin_creds()
-        self.patch('tempest.services.identity.v2.json.users_client.'
-                   'UsersClient.delete_user')
-        self.patch('tempest.services.identity.v2.json.tenants_client.'
-                   'TenantsClient.delete_tenant')
-        net = mock.patch.object(creds.networks_admin_client,
-                                'delete_network')
+        self.patchobject(self.users_client.UsersClient, 'delete_user')
+        self.patchobject(self.tenants_client_class, self.delete_tenant)
+        net = mock.patch.object(creds.networks_admin_client, 'delete_network')
         net_mock = net.start()
-        subnet = mock.patch.object(creds.subnets_admin_client,
-                                   'delete_subnet')
+        subnet = mock.patch.object(creds.subnets_admin_client, 'delete_subnet')
         subnet_mock = subnet.start()
-        router = mock.patch.object(creds.routers_admin_client,
-                                   'delete_router')
+        router = mock.patch.object(creds.routers_admin_client, 'delete_router')
         router_mock = router.start()
         remove_router_interface_mock = self.patch(
             'tempest.services.network.json.routers_client.RoutersClient.'
@@ -587,3 +596,42 @@
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         self.assertRaises(exceptions.InvalidConfiguration,
                           creds.get_primary_creds)
+
+
+class TestDynamicCredentialProviderV3(TestDynamicCredentialProvider):
+
+    fixed_params = {'name': 'test class',
+                    'identity_version': 'v3',
+                    'admin_role': 'admin'}
+
+    token_client = v3_token_client
+    iden_client = v3_iden_client
+    roles_client = v3_roles_client
+    tenants_client = v3_projects_client
+    users_client = v3_users_client
+    token_client_class = token_client.V3TokenClient
+    fake_response = fake_identity._fake_v3_response
+    assign_role_on_project = 'assign_user_role_on_project'
+    tenants_client_class = tenants_client.ProjectsClient
+    delete_tenant = 'delete_project'
+
+    def setUp(self):
+        super(TestDynamicCredentialProviderV3, self).setUp()
+        self.useFixture(fake_config.ConfigFixture())
+        self.useFixture(mockpatch.PatchObject(
+            domains_client.DomainsClient, 'list_domains',
+            return_value=dict(domains=[dict(id='default',
+                                            name='Default')])))
+        self.patchobject(self.roles_client.RolesClient,
+                         'assign_user_role_on_domain')
+
+    def _mock_list_ec2_credentials(self, user_id, tenant_id):
+        pass
+
+    def _mock_tenant_create(self, id, name):
+        project_fix = self.useFixture(mockpatch.PatchObject(
+            self.tenants_client.ProjectsClient,
+            'create_project',
+            return_value=(rest_client.ResponseBody
+                          (200, {'project': {'id': id, 'name': name}}))))
+        return project_fix
diff --git a/tempest/tests/common/test_preprov_creds.py b/tempest/tests/common/test_preprov_creds.py
index b595c88..13d4713 100644
--- a/tempest/tests/common/test_preprov_creds.py
+++ b/tempest/tests/common/test_preprov_creds.py
@@ -14,6 +14,7 @@
 
 import hashlib
 import os
+import testtools
 
 import mock
 from oslo_concurrency.fixture import lockutils as lockutils_fixtures
@@ -27,7 +28,6 @@
 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 fake_identity
@@ -43,40 +43,48 @@
                     'object_storage_operator_role': 'operator',
                     'object_storage_reseller_admin_role': 'reseller'}
 
+    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', 'project_name': 'test_tenant2',
+             'password': 'p'},
+            {'username': 'test_user3', 'tenant_name': 'test_tenant3',
+             'password': 'p'},
+            {'username': 'test_user4', 'project_name': 'test_tenant4',
+             'password': 'p'},
+            {'username': 'test_user5', 'tenant_name': 'test_tenant5',
+             'password': 'p'},
+            {'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', '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', 'project_name': 'test_tenant10',
+             'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']},
+            {'username': 'test_admin1', 'tenant_name': 'test_tenant11',
+             'password': 'p', 'roles': [admin_role]},
+            {'username': 'test_admin2', 'project_name': 'test_tenant12',
+             'password': 'p', 'roles': [admin_role]},
+            {'username': 'test_admin3', 'project_name': 'test_tenant13',
+             'password': 'p', 'types': ['admin']}]
+
     def setUp(self):
         super(TestPreProvisionedCredentials, self).setUp()
         self.useFixture(fake_config.ConfigFixture())
         self.patchobject(config, 'TempestConfigPrivate',
                          fake_config.FakePrivate)
-        self.patchobject(token_client.TokenClient, 'raw_request',
-                         fake_identity._fake_v2_response)
+        self.patch(self.token_client, side_effect=self.identity_response)
         self.useFixture(lockutils_fixtures.ExternalLockFixture())
-        self.test_accounts = [
-            {'username': 'test_user1', 'tenant_name': 'test_tenant1',
-             'password': 'p'},
-            {'username': 'test_user2', 'tenant_name': 'test_tenant2',
-             'password': 'p'},
-            {'username': 'test_user3', 'tenant_name': 'test_tenant3',
-             'password': 'p'},
-            {'username': 'test_user4', 'tenant_name': 'test_tenant4',
-             'password': 'p'},
-            {'username': 'test_user5', 'tenant_name': 'test_tenant5',
-             'password': 'p'},
-            {'username': 'test_user6', 'tenant_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',
-             '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',
-             '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]},
-        ]
+        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))
@@ -89,24 +97,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.patchobject(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(
@@ -248,9 +265,6 @@
         self.assertFalse(test_accounts_class.is_multi_user())
 
     def test__get_creds_by_roles_one_role(self):
-        self.useFixture(mockpatch.Patch(
-            'tempest.common.preprov_creds.read_accounts_yaml',
-            return_value=self.test_accounts))
         test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
             **self.fixed_params)
         hashes = test_accounts_class.hash_dict['roles']['role4']
@@ -266,9 +280,6 @@
             self.assertIn(i, args)
 
     def test__get_creds_by_roles_list_role(self):
-        self.useFixture(mockpatch.Patch(
-            'tempest.common.preprov_creds.read_accounts_yaml',
-            return_value=self.test_accounts))
         test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
             **self.fixed_params)
         hashes = test_accounts_class.hash_dict['roles']['role4']
@@ -286,9 +297,6 @@
             self.assertIn(i, args)
 
     def test__get_creds_by_roles_no_admin(self):
-        self.useFixture(mockpatch.Patch(
-            'tempest.common.preprov_creds.read_accounts_yaml',
-            return_value=self.test_accounts))
         test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
             **self.fixed_params)
         hashes = list(test_accounts_class.hash_dict['creds'].keys())
@@ -331,3 +339,135 @@
         self.assertIn('id', network)
         self.assertEqual('fake-id', network['id'])
         self.assertEqual('network-2', network['name'])
+
+    def test_get_primary_creds(self):
+        test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
+            **self.fixed_params)
+        primary_creds = test_accounts_class.get_primary_creds()
+        self.assertNotIn('test_admin', primary_creds.username)
+
+    def test_get_primary_creds_none_available(self):
+        admin_accounts = [x for x in self.test_accounts if 'test_admin'
+                          in x['username']]
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.preprov_creds.read_accounts_yaml',
+            return_value=admin_accounts))
+        test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
+            **self.fixed_params)
+        with testtools.ExpectedException(lib_exc.InvalidCredentials):
+            # Get one more
+            test_accounts_class.get_primary_creds()
+
+    def test_get_alt_creds(self):
+        test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
+            **self.fixed_params)
+        alt_creds = test_accounts_class.get_alt_creds()
+        self.assertNotIn('test_admin', alt_creds.username)
+
+    def test_get_alt_creds_none_available(self):
+        admin_accounts = [x for x in self.test_accounts if 'test_admin'
+                          in x['username']]
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.preprov_creds.read_accounts_yaml',
+            return_value=admin_accounts))
+        test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
+            **self.fixed_params)
+        with testtools.ExpectedException(lib_exc.InvalidCredentials):
+            # Get one more
+            test_accounts_class.get_alt_creds()
+
+    def test_get_admin_creds(self):
+        test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
+            **self.fixed_params)
+        admin_creds = test_accounts_class.get_admin_creds()
+        self.assertIn('test_admin', admin_creds.username)
+
+    def test_get_admin_creds_by_type(self):
+        test_accounts = [
+            {'username': 'test_user10', 'project_name': 'test_tenant10',
+             'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']},
+            {'username': 'test_admin1', 'tenant_name': 'test_tenant11',
+             'password': 'p', 'types': ['admin']}]
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.preprov_creds.read_accounts_yaml',
+            return_value=test_accounts))
+        test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
+            **self.fixed_params)
+        admin_creds = test_accounts_class.get_admin_creds()
+        self.assertIn('test_admin', admin_creds.username)
+
+    def test_get_admin_creds_by_role(self):
+        test_accounts = [
+            {'username': 'test_user10', 'project_name': 'test_tenant10',
+             'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']},
+            {'username': 'test_admin1', 'tenant_name': 'test_tenant11',
+             'password': 'p', 'roles': [cfg.CONF.identity.admin_role]}]
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.preprov_creds.read_accounts_yaml',
+            return_value=test_accounts))
+        test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
+            **self.fixed_params)
+        admin_creds = test_accounts_class.get_admin_creds()
+        self.assertIn('test_admin', admin_creds.username)
+
+    def test_get_admin_creds_none_available(self):
+        non_admin_accounts = [x for x in self.test_accounts if 'test_admin'
+                              not in x['username']]
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.preprov_creds.read_accounts_yaml',
+            return_value=non_admin_accounts))
+        test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
+            **self.fixed_params)
+        with testtools.ExpectedException(lib_exc.InvalidCredentials):
+            # Get one more
+            test_accounts_class.get_admin_creds()
+
+
+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_admin1', 'project_name': 'test_project11',
+             'domain_name': 'domain', 'password': 'p', 'roles': [admin_role]},
+            {'username': 'test_admin2', 'project_name': 'test_project12',
+             'domain_name': 'domain', 'password': 'p', 'roles': [admin_role]},
+            {'username': 'test_admin3', 'project_name': 'test_tenant13',
+             'domain_name': 'domain', 'password': 'p', 'types': ['admin']}]
diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py
index 492bdca..a56f837 100644
--- a/tempest/tests/common/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -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/test_file_utils.py b/tempest/tests/common/utils/test_file_utils.py
deleted file mode 100644
index 937aefa..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 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_execute.py b/tempest/tests/lib/cli/test_execute.py
index b846c46..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 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/common/utils/test_data_utils.py b/tempest/tests/lib/common/utils/test_data_utils.py
index f9e1f44..399c4af 100644
--- a/tempest/tests/lib/common/utils/test_data_utils.py
+++ b/tempest/tests/lib/common/utils/test_data_utils.py
@@ -169,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/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/test_auth.py b/tempest/tests/lib/test_auth.py
index cc71c92..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
 
@@ -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']
@@ -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 ca3baa1..b6f2cf6 100644
--- a/tempest/tests/lib/test_credentials.py
+++ b/tempest/tests/lib/test_credentials.py
@@ -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))
diff --git a/tempest/tests/lib/test_rest_client.py b/tempest/tests/lib/test_rest_client.py
index 2959294..106a1e5 100644
--- a/tempest/tests/lib/test_rest_client.py
+++ b/tempest/tests/lib/test_rest_client.py
@@ -547,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):
@@ -634,6 +693,24 @@
         self.assertRaises(AssertionError, self.rest_client.expected_success,
                           expected_code, read_code)
 
+    def test_non_success_read_code_as_string(self):
+        expected_code = 202
+        read_code = '202'
+        self.assertRaises(TypeError, self.rest_client.expected_success,
+                          expected_code, read_code)
+
+    def test_non_success_read_code_as_list(self):
+        expected_code = 202
+        read_code = [202]
+        self.assertRaises(TypeError, self.rest_client.expected_success,
+                          expected_code, read_code)
+
+    def test_non_success_expected_code_as_non_int(self):
+        expected_code = ['201', 202]
+        read_code = 202
+        self.assertRaises(AssertionError, self.rest_client.expected_success,
+                          expected_code, read_code)
+
 
 class TestResponseBody(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/test_glance_http.py b/tempest/tests/test_glance_http.py
deleted file mode 100644
index 768cd05..0000000
--- a/tempest/tests/test_glance_http.py
+++ /dev/null
@@ -1,225 +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 socket
-
-import mock
-from oslotest import mockpatch
-import six
-from six.moves import http_client as httplib
-
-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 fake_http
-
-
-class TestGlanceHTTPClient(base.TestCase):
-
-    def setUp(self):
-        super(TestGlanceHTTPClient, self).setUp()
-        self.endpoint = 'http://fake_url.com'
-        self.fake_auth = fake_auth_provider.FakeAuthProvider()
-
-        self.fake_auth.base_url = mock.MagicMock(return_value=self.endpoint)
-
-        self.useFixture(mockpatch.PatchObject(
-            httplib.HTTPConnection,
-            'request',
-            side_effect=b'fake_body'))
-        self.client = glance_http.HTTPClient(self.fake_auth, {})
-
-    def _set_response_fixture(self, header, status, resp_body):
-        resp = fake_http.fake_http_response(header, status=status,
-                                            body=six.StringIO(resp_body))
-        self.useFixture(mockpatch.PatchObject(httplib.HTTPConnection,
-                        'getresponse', return_value=resp))
-        return resp
-
-    def test_raw_request(self):
-        self._set_response_fixture({}, 200, 'fake_response_body')
-        resp, body = self.client.raw_request('GET', '/images')
-        self.assertEqual(200, resp.status)
-        self.assertEqual('fake_response_body', body.read())
-
-    def test_raw_request_with_response_chunked(self):
-        self._set_response_fixture({}, 200, 'fake_response_body')
-        self.useFixture(mockpatch.PatchObject(glance_http,
-                                              'CHUNKSIZE', 1))
-        resp, body = self.client.raw_request('GET', '/images')
-        self.assertEqual(200, resp.status)
-        self.assertEqual('fake_response_body', body.read())
-
-    def test_raw_request_chunked(self):
-        self.useFixture(mockpatch.PatchObject(glance_http,
-                                              'CHUNKSIZE', 1))
-        self.useFixture(mockpatch.PatchObject(httplib.HTTPConnection,
-                        'endheaders'))
-        self.useFixture(mockpatch.PatchObject(httplib.HTTPConnection,
-                        'send'))
-
-        self._set_response_fixture({}, 200, 'fake_response_body')
-        req_body = six.StringIO('fake_request_body')
-        resp, body = self.client.raw_request('PUT', '/images', body=req_body)
-        self.assertEqual(200, resp.status)
-        self.assertEqual('fake_response_body', body.read())
-        call_count = httplib.HTTPConnection.send.call_count
-        self.assertEqual(call_count - 1, req_body.tell())
-
-    def test_get_connection_class_for_https(self):
-        conn_class = self.client._get_connection_class('https')
-        self.assertEqual(glance_http.VerifiedHTTPSConnection, conn_class)
-
-    def test_get_connection_class_for_http(self):
-        conn_class = (self.client._get_connection_class('http'))
-        self.assertEqual(httplib.HTTPConnection, conn_class)
-
-    def test_get_connection_http(self):
-        self.assertIsInstance(self.client._get_connection(),
-                              httplib.HTTPConnection)
-
-    def test_get_connection_https(self):
-        endpoint = 'https://fake_url.com'
-        self.fake_auth.base_url = mock.MagicMock(return_value=endpoint)
-        self.client = glance_http.HTTPClient(self.fake_auth, {})
-        self.assertIsInstance(self.client._get_connection(),
-                              glance_http.VerifiedHTTPSConnection)
-
-    def test_get_connection_ipv4_https(self):
-        endpoint = 'https://127.0.0.1'
-        self.fake_auth.base_url = mock.MagicMock(return_value=endpoint)
-        self.client = glance_http.HTTPClient(self.fake_auth, {})
-        self.assertIsInstance(self.client._get_connection(),
-                              glance_http.VerifiedHTTPSConnection)
-
-    def test_get_connection_ipv6_https(self):
-        endpoint = 'https://[::1]'
-        self.fake_auth.base_url = mock.MagicMock(return_value=endpoint)
-        self.client = glance_http.HTTPClient(self.fake_auth, {})
-        self.assertIsInstance(self.client._get_connection(),
-                              glance_http.VerifiedHTTPSConnection)
-
-    def test_get_connection_url_not_fount(self):
-        self.useFixture(mockpatch.PatchObject(self.client, 'connection_class',
-                                              side_effect=httplib.InvalidURL()
-                                              ))
-        self.assertRaises(exceptions.EndpointNotFound,
-                          self.client._get_connection)
-
-    def test_get_connection_kwargs_default_for_http(self):
-        kwargs = self.client._get_connection_kwargs('http')
-        self.assertEqual(600, kwargs['timeout'])
-        self.assertEqual(1, len(kwargs.keys()))
-
-    def test_get_connection_kwargs_set_timeout_for_http(self):
-        kwargs = self.client._get_connection_kwargs('http', timeout=10,
-                                                    ca_certs='foo')
-        self.assertEqual(10, kwargs['timeout'])
-        # nothing more than timeout is evaluated for http connections
-        self.assertEqual(1, len(kwargs.keys()))
-
-    def test_get_connection_kwargs_default_for_https(self):
-        kwargs = self.client._get_connection_kwargs('https')
-        self.assertEqual(600, kwargs['timeout'])
-        self.assertIsNone(kwargs['ca_certs'])
-        self.assertIsNone(kwargs['cert_file'])
-        self.assertIsNone(kwargs['key_file'])
-        self.assertEqual(False, kwargs['insecure'])
-        self.assertEqual(True, kwargs['ssl_compression'])
-        self.assertEqual(6, len(kwargs.keys()))
-
-    def test_get_connection_kwargs_set_params_for_https(self):
-        kwargs = self.client._get_connection_kwargs('https', timeout=10,
-                                                    ca_certs='foo',
-                                                    cert_file='/foo/bar.cert',
-                                                    key_file='/foo/key.pem',
-                                                    insecure=True,
-                                                    ssl_compression=False)
-        self.assertEqual(10, kwargs['timeout'])
-        self.assertEqual('foo', kwargs['ca_certs'])
-        self.assertEqual('/foo/bar.cert', kwargs['cert_file'])
-        self.assertEqual('/foo/key.pem', kwargs['key_file'])
-        self.assertEqual(True, kwargs['insecure'])
-        self.assertEqual(False, kwargs['ssl_compression'])
-        self.assertEqual(6, len(kwargs.keys()))
-
-
-class TestVerifiedHTTPSConnection(base.TestCase):
-
-    @mock.patch('socket.socket')
-    @mock.patch('tempest.common.glance_http.OpenSSLConnectionDelegator')
-    def test_connect_ipv4(self, mock_delegator, mock_socket):
-        connection = glance_http.VerifiedHTTPSConnection('127.0.0.1')
-        connection.connect()
-
-        mock_socket.assert_called_once_with(socket.AF_INET, socket.SOCK_STREAM)
-        mock_delegator.assert_called_once_with(connection.context,
-                                               mock_socket.return_value)
-        mock_delegator.return_value.connect.assert_called_once_with(
-            (connection.host, 443))
-
-    @mock.patch('socket.socket')
-    @mock.patch('tempest.common.glance_http.OpenSSLConnectionDelegator')
-    def test_connect_ipv6(self, mock_delegator, mock_socket):
-        connection = glance_http.VerifiedHTTPSConnection('[::1]')
-        connection.connect()
-
-        mock_socket.assert_called_once_with(socket.AF_INET6,
-                                            socket.SOCK_STREAM)
-        mock_delegator.assert_called_once_with(connection.context,
-                                               mock_socket.return_value)
-        mock_delegator.return_value.connect.assert_called_once_with(
-            (connection.host, 443, 0, 0))
-
-    @mock.patch('tempest.common.glance_http.OpenSSLConnectionDelegator')
-    @mock.patch('socket.getaddrinfo',
-                side_effect=OSError('Gettaddrinfo failed'))
-    def test_connect_with_address_lookup_failure(self, mock_getaddrinfo,
-                                                 mock_delegator):
-        connection = glance_http.VerifiedHTTPSConnection('127.0.0.1')
-        self.assertRaises(exceptions.RestClientException, connection.connect)
-
-        mock_getaddrinfo.assert_called_once_with(
-            connection.host, connection.port, 0, socket.SOCK_STREAM)
-
-    @mock.patch('socket.socket')
-    @mock.patch('socket.getaddrinfo',
-                return_value=[(2, 1, 6, '', ('127.0.0.1', 443))])
-    @mock.patch('tempest.common.glance_http.OpenSSLConnectionDelegator')
-    def test_connect_with_socket_failure(self, mock_delegator,
-                                         mock_getaddrinfo,
-                                         mock_socket):
-        mock_delegator.return_value.connect.side_effect = \
-            OSError('Connect failed')
-
-        connection = glance_http.VerifiedHTTPSConnection('127.0.0.1')
-        self.assertRaises(exceptions.RestClientException, connection.connect)
-
-        mock_getaddrinfo.assert_called_once_with(
-            connection.host, connection.port, 0, socket.SOCK_STREAM)
-        mock_socket.assert_called_once_with(socket.AF_INET, socket.SOCK_STREAM)
-        mock_delegator.return_value.connect.\
-            assert_called_once_with((connection.host, 443))
-
-
-class TestResponseBodyIterator(base.TestCase):
-
-    def test_iter_default_chunk_size_64k(self):
-        resp = fake_http.fake_http_response({}, six.StringIO(
-            'X' * (glance_http.CHUNKSIZE + 1)))
-        iterator = glance_http.ResponseBodyIterator(resp)
-        chunks = list(iterator)
-        self.assertEqual(chunks, ['X' * glance_http.CHUNKSIZE, 'X'])
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index aba2aab..f005c21 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -167,3 +167,16 @@
         self.assertEqual(1, len(list(checks.dont_import_local_tempest_into_lib(
             "import tempest.exception",
             './tempest/lib/common/compute.py'))))
+
+    def test_dont_use_config_in_tempest_lib(self):
+        self.assertFalse(list(checks.dont_use_config_in_tempest_lib(
+            'from tempest import config', './tempest/common/compute.py')))
+        self.assertFalse(list(checks.dont_use_config_in_tempest_lib(
+            'from oslo_concurrency import lockutils',
+            './tempest/lib/auth.py')))
+        self.assertTrue(list(checks.dont_use_config_in_tempest_lib(
+            'from tempest import config', './tempest/lib/auth.py')))
+        self.assertTrue(list(checks.dont_use_config_in_tempest_lib(
+            'from oslo_config import cfg', './tempest/lib/decorators.py')))
+        self.assertTrue(list(checks.dont_use_config_in_tempest_lib(
+            'import tempest.config', './tempest/lib/common/rest_client.py')))
diff --git a/test-requirements.txt b/test-requirements.txt
index 9ef956a..763f0ba 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -7,6 +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
-mock>=1.2 # BSD
+mock>=2.0 # 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..caad85c 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -20,8 +20,8 @@
 import os
 import re
 import six
+import six.moves.urllib.request as urlreq
 import sys
-import urllib2
 
 import yaml
 
@@ -54,7 +54,6 @@
     'q-meta',
     'q-metering',
     'q-svc',
-    'q-vpn',
     's-proxy'])
 
 
@@ -68,9 +67,9 @@
                 logs_with_errors.append(name)
     for (name, url) in url_specs:
         whitelist = whitelists.get(name, [])
-        req = urllib2.Request(url)
+        req = urlreq.Request(url)
         req.add_header('Accept-Encoding', 'gzip')
-        page = urllib2.urlopen(req)
+        page = urlreq.urlopen(req)
         buf = six.StringIO(page.read())
         f = gzip.GzipFile(fileobj=buf)
         if scan_content(name, f.read().splitlines(), regexp, whitelist):
@@ -96,7 +95,7 @@
 
 
 def collect_url_logs(url):
-    page = urllib2.urlopen(url)
+    page = urlreq.urlopen(url)
     content = page.read()
     logs = re.findall('(screen-[\w-]+\.txt\.gz)</a>', content)
     return logs
diff --git a/tools/find_stack_traces.py b/tools/find_stack_traces.py
index 49a42fe..f2da27a 100755
--- a/tools/find_stack_traces.py
+++ b/tools/find_stack_traces.py
@@ -19,8 +19,8 @@
 import pprint
 import re
 import six
+import six.moves.urllib.request as urlreq
 import sys
-import urllib2
 
 
 pp = pprint.PrettyPrinter()
@@ -65,9 +65,9 @@
 
 def hunt_for_stacktrace(url):
     """Return TRACE or ERROR lines out of logs."""
-    req = urllib2.Request(url)
+    req = urlreq.Request(url)
     req.add_header('Accept-Encoding', 'gzip')
-    page = urllib2.urlopen(req)
+    page = urlreq.urlopen(req)
     buf = six.StringIO(page.read())
     f = gzip.GzipFile(fileobj=buf)
     content = f.read()
@@ -105,7 +105,7 @@
 
 
 def collect_logs(url):
-    page = urllib2.urlopen(url)
+    page = urlreq.urlopen(url)
     content = page.read()
     logs = re.findall('(screen-[\w-]+\.txt\.gz)</a>', content)
     return logs