Merge "Modify --endpoint-type to --os-endpoint-type for nova"
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index bcb1e3e..d610dc5 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
 -------
 
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/releasenotes/notes/add-scope-to-auth-b5a82493ea89f41e.yaml b/releasenotes/notes/add-scope-to-auth-b5a82493ea89f41e.yaml
new file mode 100644
index 0000000..297279f
--- /dev/null
+++ b/releasenotes/notes/add-scope-to-auth-b5a82493ea89f41e.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - Tempest library auth interface now supports scope. Scope allows to control
+    the scope of tokens requested via the identity API. Identity V2 supports
+    unscoped and project scoped tokens, but only the latter are implemented.
+    Identity V3 supports unscoped, project and domain scoped token, all three
+    are available.
\ No newline at end of file
diff --git a/releasenotes/notes/remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml b/releasenotes/notes/remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml
new file mode 100644
index 0000000..89b3f41
--- /dev/null
+++ b/releasenotes/notes/remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml
@@ -0,0 +1,5 @@
+---
+upgrade:
+  - The deprecated legacy credential provider has been removed. The only way to
+    configure credentials in tempest now is to use the dynamic or preprovisioned
+    credential providers
diff --git a/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/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 2ad1733..19f1a2a 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -131,7 +131,8 @@
 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
@@ -197,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()
@@ -330,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/javelin.py b/tempest/cmd/javelin.py
index 9b3cac7..17ee618 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -233,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,
diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py
index 6cb43f3..7c73ada 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
@@ -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
@@ -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
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 6360c3e..f5125b5 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"),
@@ -1250,12 +1218,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/lib/auth.py b/tempest/lib/auth.py
index a6833be..ffcc4fb 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):
@@ -669,7 +742,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/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/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..65677a0 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:
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/services/identity/v3/json/projects_client.py b/tempest/services/identity/v3/json/projects_client.py
index dc553d0..97e43df 100644
--- a/tempest/services/identity/v3/json/projects_client.py
+++ b/tempest/services/identity/v3/json/projects_client.py
@@ -23,17 +23,15 @@
     api_version = "v3"
 
     def create_project(self, name, **kwargs):
-        """Creates a project."""
-        description = kwargs.get('description', None)
-        en = kwargs.get('enabled', True)
-        domain_id = kwargs.get('domain_id', 'default')
-        post_body = {
-            'description': description,
-            'domain_id': domain_id,
-            'enabled': en,
-            'name': name
-        }
-        post_body = json.dumps({'project': post_body})
+        """Create a Project.
+
+        Available params: see http://developer.openstack.org/
+                          api-ref-identity-v3.html#createProject
+
+        """
+        # Include the project name to the kwargs parameters
+        kwargs['name'] = name
+        post_body = json.dumps({'project': kwargs})
         resp, body = self.post('projects', post_body)
         self.expected_success(201, resp.status)
         body = json.loads(body)
@@ -49,19 +47,13 @@
         return rest_client.ResponseBody(resp, body)
 
     def update_project(self, project_id, **kwargs):
-        body = self.show_project(project_id)['project']
-        name = kwargs.get('name', body['name'])
-        desc = kwargs.get('description', body['description'])
-        en = kwargs.get('enabled', body['enabled'])
-        domain_id = kwargs.get('domain_id', body['domain_id'])
-        post_body = {
-            'id': project_id,
-            'name': name,
-            'description': desc,
-            'enabled': en,
-            'domain_id': domain_id,
-        }
-        post_body = json.dumps({'project': post_body})
+        """Update a Project.
+
+        Available params: see http://developer.openstack.org/
+                          api-ref-identity-v3.html#updateProject
+
+        """
+        post_body = json.dumps({'project': kwargs})
         resp, body = self.patch('projects/%s' % project_id, post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
diff --git a/tempest/services/image/v1/json/images_client.py b/tempest/services/image/v1/json/images_client.py
index e29ff89..a36075f 100644
--- a/tempest/services/image/v1/json/images_client.py
+++ b/tempest/services/image/v1/json/images_client.py
@@ -16,7 +16,6 @@
 import copy
 import errno
 import os
-import time
 
 from oslo_log import log as logging
 from oslo_serialization import jsonutils as json
@@ -24,9 +23,7 @@
 from six.moves.urllib import parse as urllib
 
 from tempest.common import glance_http
-from tempest import exceptions
 from tempest.lib.common import rest_client
-from tempest.lib.common.utils import misc as misc_utils
 from tempest.lib import exceptions as lib_exc
 
 LOG = logging.getLogger(__name__)
@@ -198,7 +195,8 @@
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
-    def get_image_meta(self, image_id):
+    def check_image(self, image_id):
+        """Check image metadata."""
         url = 'v1/images/%s' % image_id
         resp, __ = self.head(url)
         self.expected_success(200, resp.status)
@@ -206,6 +204,7 @@
         return rest_client.ResponseBody(resp, body)
 
     def show_image(self, image_id):
+        """Get image details plus the image itself."""
         url = 'v1/images/%s' % image_id
         resp, body = self.get(url)
         self.expected_success(200, resp.status)
@@ -213,7 +212,7 @@
 
     def is_resource_deleted(self, id):
         try:
-            if self.get_image_meta(id)['status'] == 'deleted':
+            if self.check_image(id)['status'] == 'deleted':
                 return True
         except lib_exc.NotFound:
             return True
@@ -256,40 +255,3 @@
         resp, __ = self.delete(url)
         self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp)
-
-    # NOTE(afazekas): just for the wait function
-    def _get_image_status(self, image_id):
-        meta = self.get_image_meta(image_id)
-        status = meta['status']
-        return status
-
-    # NOTE(afazkas): Wait reinvented again. It is not in the correct layer
-    def wait_for_image_status(self, image_id, status):
-        """Waits for a Image to reach a given status."""
-        start_time = time.time()
-        old_value = value = self._get_image_status(image_id)
-        while True:
-            dtime = time.time() - start_time
-            time.sleep(self.build_interval)
-            if value != old_value:
-                LOG.info('Value transition from "%s" to "%s"'
-                         'in %d second(s).', old_value,
-                         value, dtime)
-            if value == status:
-                return value
-
-            if value == 'killed':
-                raise exceptions.ImageKilledException(image_id=image_id,
-                                                      status=status)
-            if dtime > self.build_timeout:
-                message = ('Time Limit Exceeded! (%ds)'
-                           'while waiting for %s, '
-                           'but we got %s.' %
-                           (self.build_timeout, status, value))
-                caller = misc_utils.find_test_caller()
-                if caller:
-                    message = '(%s) %s' % (caller, message)
-                raise exceptions.TimeoutException(message)
-            time.sleep(self.build_interval)
-            old_value = value
-            value = self._get_image_status(image_id)
diff --git a/tempest/services/image/v2/json/images_client.py b/tempest/services/image/v2/json/images_client.py
index 4e037af..a61f31d 100644
--- a/tempest/services/image/v2/json/images_client.py
+++ b/tempest/services/image/v2/json/images_client.py
@@ -21,10 +21,10 @@
 from tempest.lib import exceptions as lib_exc
 
 
-class ImagesClientV2(rest_client.RestClient):
+class ImagesClient(rest_client.RestClient):
 
     def __init__(self, auth_provider, catalog_type, region, **kwargs):
-        super(ImagesClientV2, self).__init__(
+        super(ImagesClient, self).__init__(
             auth_provider, catalog_type, region, **kwargs)
         self._http = None
         self.dscv = kwargs.get("disable_ssl_certificate_validation")
diff --git a/tempest/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_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/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/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_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/tools/check_logs.py b/tools/check_logs.py
index fa7129d..e34dec3 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -54,7 +54,6 @@
     'q-meta',
     'q-metering',
     'q-svc',
-    'q-vpn',
     's-proxy'])