Merge "Test glance distributed import"
diff --git a/releasenotes/notes/add-alt-project-dynamic-creds-1a3bc543e65d9433.yaml b/releasenotes/notes/add-alt-project-dynamic-creds-1a3bc543e65d9433.yaml
new file mode 100644
index 0000000..de81b2b
--- /dev/null
+++ b/releasenotes/notes/add-alt-project-dynamic-creds-1a3bc543e65d9433.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - |
+    Add project alternate admin, member and reader role for dynamic credentials.
diff --git a/releasenotes/notes/intermediate-wallaby-release-55a0b31b1dee7b23.yaml b/releasenotes/notes/intermediate-wallaby-release-55a0b31b1dee7b23.yaml
new file mode 100644
index 0000000..cda3b89
--- /dev/null
+++ b/releasenotes/notes/intermediate-wallaby-release-55a0b31b1dee7b23.yaml
@@ -0,0 +1,4 @@
+---
+prelude: >
+    This is an intermediate release during the Wallaby development cycle to
+    make new functionality available to plugins and other consumers.
diff --git a/releasenotes/notes/support-scope-in-get-roles-dynamic-creds-90bfab163c1c289a.yaml b/releasenotes/notes/support-scope-in-get-roles-dynamic-creds-90bfab163c1c289a.yaml
new file mode 100644
index 0000000..26282f0
--- /dev/null
+++ b/releasenotes/notes/support-scope-in-get-roles-dynamic-creds-90bfab163c1c289a.yaml
@@ -0,0 +1,36 @@
+---
+features:
+  - |
+    Dynamic credentials now support the scope type for specific roles
+    too along with ``admin``, ``member``, ``reader`` role.
+    Test can specify the scope in the prefix of ``cls.credentials`` name.
+    If ``system`` is prefix in ``cls.credentials`` name then creds will
+    be created with scope as ``system``. If ``domain`` is prefix in
+    ``cls.credentials`` name then creds will be created with scope as
+    ``domain`` otherwise default ``project`` scope will be used.
+    For Example::
+
+        credentials = [['my_role', 'role1'], # this will be old style and project scoped
+                       ['project_my_role', 'role1'], # this will be project scoped
+                       ['domain_my_role', 'role1'], # this will be domain scoped
+                       ['system_my_role', 'role1']] # this will be system scoped
+
+    And below is how test can access the credential manager of respective
+    credentials type::
+
+        cls.os_my_role.any_client
+        cls.os_project_my_role.any_client
+        cls.os_domain_my_role.any_client
+        cls.os_system_my_role.any_client
+
+
+    For backward compatibility, we set the credentials manager class attribute
+    in old style form too which is prefix with ``os_roles_*``, example
+    ``cls.os_roles_my_role`` but we recommend to use the new style attribute
+    as shown above.
+issues:
+  - |
+    Scope support for specific role is not yet added for pre-provisioned credentials.
+fixes:
+  - |
+    Fixes the `bug# 1917168 <https://bugs.launchpad.net/tempest/+bug/1917168>`_
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 941315e..52ccea7 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -169,8 +169,13 @@
                       block_migrate_cinder_iscsi,
                       'Block Live migration not configured for iSCSI')
     @utils.services('volume')
-    def test_iscsi_volume(self):
-        """Test live migrating a server with volume attached"""
+    def test_live_block_migration_with_attached_volume(self):
+        """Test the live-migration of an instance with an attached volume.
+
+        This tests the live-migration of an instance with both a local disk and
+        attach volume. This differs from test_volume_backed_live_migration
+        above that tests live-migration with only an attached volume.
+        """
         server = self.create_test_server(wait_until="ACTIVE")
         server_id = server['id']
         if not CONF.compute_feature_enabled.can_migrate_between_any_hosts:
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 102792e..ac18442 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -16,7 +16,6 @@
 import time
 
 from oslo_log import log
-import six
 
 from tempest.api.compute import base
 from tempest.common import compute
@@ -241,7 +240,7 @@
         except lib_exc.BadRequest as e:
             msg = ('Multiple possible networks found, use a Network ID to be '
                    'more specific.')
-            if not CONF.compute.fixed_network_name and six.text_type(e) == msg:
+            if not CONF.compute.fixed_network_name and str(e) == msg:
                 raise
         else:
             ifs.append(iface)
@@ -450,7 +449,7 @@
         except lib_exc.BadRequest as e:
             msg = ('Multiple possible networks found, use a Network ID to be '
                    'more specific.')
-            if not CONF.compute.fixed_network_name and six.text_type(e) == msg:
+            if not CONF.compute.fixed_network_name and str(e) == msg:
                 raise
         else:
             # just to check the response schema
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
index 34b3146..a9c0e56 100644
--- a/tempest/api/compute/servers/test_novnc.py
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -69,7 +69,7 @@
         resp = urllib3.PoolManager().request('GET', vnc_url)
         # Make sure that the GET request was accepted by the novncproxy
         self.assertEqual(resp.status, 200, 'Got a Bad HTTP Response on the '
-                         'initial call: ' + six.text_type(resp.status))
+                         'initial call: ' + str(resp.status))
         # Do some basic validation to make sure it is an expected HTML document
         resp_data = resp.data.decode()
         # This is needed in the case of example: <html lang="en">
@@ -165,11 +165,11 @@
             self._websocket.response.startswith(b'HTTP/1.1 101 Switching '
                                                 b'Protocols'),
             'Incorrect HTTP return status code: {}'.format(
-                six.text_type(self._websocket.response)
+                str(self._websocket.response)
             )
         )
         _required_header = 'upgrade: websocket'
-        _response = six.text_type(self._websocket.response).lower()
+        _response = str(self._websocket.response).lower()
         self.assertIn(
             _required_header,
             _response,
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index f3a7471..5bbd65c 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import six
-
 from tempest.api.identity import base
 from tempest import config
 from tempest.lib.common.utils import data_utils
@@ -70,8 +68,8 @@
         orig_expires_at = token_auth['token']['expires_at']
         orig_user = token_auth['token']['user']
 
-        self.assertIsInstance(token_auth['token']['expires_at'], six.text_type)
-        self.assertIsInstance(token_auth['token']['issued_at'], six.text_type)
+        self.assertIsInstance(token_auth['token']['expires_at'], str)
+        self.assertIsInstance(token_auth['token']['issued_at'], str)
         self.assertEqual(['password'], token_auth['token']['methods'])
         self.assertEqual(user['id'], token_auth['token']['user']['id'])
         self.assertEqual(user['name'], token_auth['token']['user']['name'])
@@ -91,7 +89,7 @@
 
         self.assertEqual(orig_expires_at, token_auth['token']['expires_at'],
                          'Expiration time should match original token')
-        self.assertIsInstance(token_auth['token']['issued_at'], six.text_type)
+        self.assertIsInstance(token_auth['token']['issued_at'], str)
         self.assertEqual(set(['password', 'token']),
                          set(token_auth['token']['methods']))
         self.assertEqual(orig_user, token_auth['token']['user'],
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 479578d..63078cd 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -16,7 +16,6 @@
 import ipaddress
 
 import netaddr
-import six
 import testtools
 
 from tempest.api.network import base_security_groups as sec_base
@@ -234,15 +233,15 @@
         # Get two IP addresses
         ip_address_1 = None
         ip_address_2 = None
-        ip_network = ipaddress.ip_network(six.text_type(subnet['cidr']))
+        ip_network = ipaddress.ip_network(str(subnet['cidr']))
         for ip in ip_network:
             if ip == ip_network.network_address:
                 continue
             if ip_address_1 is None:
-                ip_address_1 = six.text_type(ip)
+                ip_address_1 = str(ip)
             else:
                 ip_address_2 = ip_address_1
-                ip_address_1 = six.text_type(ip)
+                ip_address_1 = str(ip)
                 # Make sure these two IP addresses have different substring
                 if ip_address_1[:-1] != ip_address_2[:-1]:
                     break
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index e8f3f8b..478a834 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -13,12 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import time
-
 from tempest.common import custom_matchers
 from tempest import config
 from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_exc
 import tempest.test
 
@@ -50,12 +47,11 @@
             _, objlist = container_client.list_container_objects(cont, params)
             # delete every object in the container
             for obj in objlist:
-                test_utils.call_and_ignore_notfound_exc(
-                    object_client.delete_object, cont, obj['name'])
-            # sleep 2 seconds to sync the deletion of the objects
-            # in HA deployment
-            time.sleep(2)
+                object_client.delete_object(cont, obj['name'])
+                object_client.wait_for_resource_deletion(obj['name'], cont)
+            # Verify resource deletion
             container_client.delete_container(cont)
+            container_client.wait_for_resource_deletion(cont)
         except lib_exc.NotFound:
             pass
 
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index da8ad66..ffea6f6 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -62,7 +62,7 @@
         self.assertIsNotNone(container_list)
 
         for container_name in self.containers:
-            self.assertIn(six.text_type(container_name).encode('utf-8'),
+            self.assertIn(str(container_name).encode('utf-8'),
                           container_list)
 
     @decorators.idempotent_id('884ec421-fbad-4fcc-916b-0580f2699565')
diff --git a/tempest/cmd/subunit_describe_calls.py b/tempest/cmd/subunit_describe_calls.py
index 172fbaa..6c36d82 100644
--- a/tempest/cmd/subunit_describe_calls.py
+++ b/tempest/cmd/subunit_describe_calls.py
@@ -40,12 +40,14 @@
 
 subunit-describe-calls will take in either stdin subunit v1 or v2 stream or a
 file path which contains either a subunit v1 or v2 stream passed via the
---subunit parameter. This is then parsed checking for details contained in the
-file_bytes of the --non-subunit-name parameter (the default is pythonlogging
-which is what Tempest uses to store logs). By default the OpenStack Kilo
-release port defaults (http://bit.ly/22jpF5P) are used unless a file is
-provided via the --ports option. The resulting output is dumped in JSON output
-to the path provided in the --output-file option.
+``--subunit`` parameter. This is then parsed checking for details contained in
+the file_bytes of the ``--non-subunit-name`` parameter (the default is
+pythonlogging which is what Tempest uses to store logs). By default `the
+OpenStack default ports
+<https://docs.openstack.org/install-guide/firewalls-default-ports.html>`_
+are used unless a file is provided via the ``--ports`` option. The resulting
+output is dumped in JSON output to the path provided in the ``--output-file``
+option.
 
 Ports file JSON structure
 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -110,9 +112,8 @@
     response_re = re.compile(r'.* Response - Headers: (?P<headers>.*)')
     body_re = re.compile(r'.*Body: (?P<body>.*)')
 
-    # Based on newton defaults:
-    # http://docs.openstack.org/newton/config-reference/
-    # firewalls-default-ports.html
+    # Based on OpenStack default ports:
+    # https://docs.openstack.org/install-guide/firewalls-default-ports.html
     services = {
         "8776": "Block Storage",
         "8774": "Nova",
@@ -131,7 +132,10 @@
         "3260": "iSCSI",
         "3306": "MySQL",
         "5672": "AMQP",
-        "8082": "murano"}
+        "8082": "murano",
+        "8778": "Clustering",
+        "8999": "Vitrage",
+        "8989": "Mistral"}
 
     def __init__(self, services=None):
         super(UrlParser, self).__init__()
diff --git a/tempest/lib/common/cred_provider.py b/tempest/lib/common/cred_provider.py
index 35bca1d..069172a 100644
--- a/tempest/lib/common/cred_provider.py
+++ b/tempest/lib/common/cred_provider.py
@@ -86,14 +86,26 @@
         return
 
     @abc.abstractmethod
+    def get_project_alt_admin_creds(self):
+        return
+
+    @abc.abstractmethod
     def get_project_member_creds(self):
         return
 
     @abc.abstractmethod
+    def get_project_alt_member_creds(self):
+        return
+
+    @abc.abstractmethod
     def get_project_reader_creds(self):
         return
 
     @abc.abstractmethod
+    def get_project_alt_reader_creds(self):
+        return
+
+    @abc.abstractmethod
     def clear_creds(self):
         return
 
@@ -106,7 +118,7 @@
         return
 
     @abc.abstractmethod
-    def get_creds_by_roles(self, roles, force_new=False):
+    def get_creds_by_roles(self, roles, force_new=False, scope=None):
         return
 
     @abc.abstractmethod
diff --git a/tempest/lib/common/dynamic_creds.py b/tempest/lib/common/dynamic_creds.py
index 0244128..f334c36 100644
--- a/tempest/lib/common/dynamic_creds.py
+++ b/tempest/lib/common/dynamic_creds.py
@@ -228,8 +228,9 @@
         roles_to_assign = [r for r in roles]
         if admin:
             roles_to_assign.append(self.admin_role)
-            self.creds_client.assign_user_role(
-                user, project, self.identity_admin_role)
+            if scope == 'project':
+                self.creds_client.assign_user_role(
+                    user, project, self.identity_admin_role)
             if (self.identity_version == 'v3' and
                     self.identity_admin_domain_scope):
                 self.creds_client.assign_user_role_on_domain(
@@ -341,7 +342,7 @@
                             tenant_id=tenant_id,
                             enable_dhcp=self.network_resources['dhcp'],
                             ip_version=(ipaddress.ip_network(
-                                six.text_type(subnet_cidr)).version))
+                                str(subnet_cidr)).version))
                 else:
                     resp_body = self.subnets_admin_client.\
                         create_subnet(network_id=network_id,
@@ -349,7 +350,7 @@
                                       name=subnet_name,
                                       tenant_id=tenant_id,
                                       ip_version=(ipaddress.ip_network(
-                                          six.text_type(subnet_cidr)).version))
+                                          str(subnet_cidr)).version))
                 break
             except lib_exc.BadRequest as e:
                 if 'overlaps with another subnet' not in str(e):
@@ -375,13 +376,22 @@
     def get_credentials(self, credential_type, scope=None):
         if not scope and self._creds.get(str(credential_type)):
             credentials = self._creds[str(credential_type)]
-        elif scope and self._creds.get("%s_%s" % (scope, credential_type[0])):
-            credentials = self._creds["%s_%s" % (scope, credential_type[0])]
+        elif scope and (
+                self._creds.get("%s_%s" % (scope, str(credential_type)))):
+            credentials = self._creds["%s_%s" % (scope, str(credential_type))]
         else:
+            LOG.debug("Creating new dynamic creds for scope: %s and "
+                      "credential_type: %s", scope, credential_type)
             if scope:
-                if credential_type == 'admin':
+                if credential_type in [['admin'], ['alt_admin']]:
                     credentials = self._create_creds(
                         admin=True, scope=scope)
+                elif credential_type in [['alt_member'], ['alt_reader']]:
+                    cred_type = credential_type[0][4:]
+                    if isinstance(cred_type, str):
+                        cred_type = [cred_type]
+                    credentials = self._create_creds(
+                        roles=cred_type, scope=scope)
                 else:
                     credentials = self._create_creds(
                         roles=credential_type, scope=scope)
@@ -392,7 +402,7 @@
                 credentials = self._create_creds(roles=credential_type)
             if scope:
                 self._creds["%s_%s" %
-                            (scope, credential_type[0])] = credentials
+                            (scope, str(credential_type))] = credentials
             else:
                 self._creds[str(credential_type)] = credentials
             # Maintained until tests are ported
@@ -443,25 +453,37 @@
     def get_project_admin_creds(self):
         return self.get_credentials(['admin'], scope='project')
 
+    def get_project_alt_admin_creds(self):
+        return self.get_credentials(['alt_admin'], scope='project')
+
     def get_project_member_creds(self):
         return self.get_credentials(['member'], scope='project')
 
+    def get_project_alt_member_creds(self):
+        return self.get_credentials(['alt_member'], scope='project')
+
     def get_project_reader_creds(self):
         return self.get_credentials(['reader'], scope='project')
 
-    def get_creds_by_roles(self, roles, force_new=False):
+    def get_project_alt_reader_creds(self):
+        return self.get_credentials(['alt_reader'], scope='project')
+
+    def get_creds_by_roles(self, roles, force_new=False, scope=None):
         roles = list(set(roles))
         # The roles list as a str will become the index as the dict key for
         # the created credentials set in the dynamic_creds dict.
-        exist_creds = self._creds.get(str(roles))
+        creds_name = str(roles)
+        if scope:
+            creds_name = "%s_%s" % (scope, str(roles))
+        exist_creds = self._creds.get(creds_name)
         # If force_new flag is True 2 cred sets with the same roles are needed
         # handle this by creating a separate index for old one to store it
         # separately for cleanup
         if exist_creds and force_new:
-            new_index = str(roles) + '-' + str(len(self._creds))
+            new_index = creds_name + '-' + str(len(self._creds))
             self._creds[new_index] = exist_creds
-            del self._creds[str(roles)]
-        return self.get_credentials(roles)
+            del self._creds[creds_name]
+        return self.get_credentials(roles, scope=scope)
 
     def _clear_isolated_router(self, router_id, router_name):
         client = self.routers_admin_client
diff --git a/tempest/lib/common/jsonschema_validator.py b/tempest/lib/common/jsonschema_validator.py
index bbf5e89..0ac757d 100644
--- a/tempest/lib/common/jsonschema_validator.py
+++ b/tempest/lib/common/jsonschema_validator.py
@@ -15,7 +15,6 @@
 import jsonschema
 from oslo_serialization import base64
 from oslo_utils import timeutils
-import six
 
 # JSON Schema validator and format checker used for JSON Schema validation
 JSONSCHEMA_VALIDATOR = jsonschema.Draft4Validator
@@ -43,7 +42,7 @@
 @jsonschema.FormatChecker.cls_checks('base64')
 def _validate_base64_format(instance):
     try:
-        if isinstance(instance, six.text_type):
+        if isinstance(instance, str):
             instance = instance.encode('utf-8')
         base64.decode_as_bytes(instance)
     except TypeError:
diff --git a/tempest/lib/common/preprov_creds.py b/tempest/lib/common/preprov_creds.py
index 9784a1f..df0f4d6 100644
--- a/tempest/lib/common/preprov_creds.py
+++ b/tempest/lib/common/preprov_creds.py
@@ -17,7 +17,6 @@
 
 from oslo_concurrency import lockutils
 from oslo_log import log as logging
-import six
 import yaml
 
 from tempest.lib import auth
@@ -138,7 +137,7 @@
             temp_hash = hashlib.md5()
             account_for_hash = dict((k, v) for (k, v) in account.items()
                                     if k in cls.HASH_CRED_FIELDS)
-            temp_hash.update(six.text_type(account_for_hash).encode('utf-8'))
+            temp_hash.update(str(account_for_hash).encode('utf-8'))
             temp_hash_key = temp_hash.hexdigest()
             hash_dict['creds'][temp_hash_key] = account
             for role in roles:
@@ -375,6 +374,10 @@
         self._creds['project_admin'] = project_admin
         return project_admin
 
+    def get_project_alt_admin_creds(self):
+        # TODO(gmann): Implement alt admin hash.
+        return
+
     def get_project_member_creds(self):
         if self._creds.get('project_member'):
             return self._creds.get('project_member')
@@ -382,6 +385,10 @@
         self._creds['project_member'] = project_member
         return project_member
 
+    def get_project_alt_member_creds(self):
+        # TODO(gmann): Implement alt member hash.
+        return
+
     def get_project_reader_creds(self):
         if self._creds.get('project_reader'):
             return self._creds.get('project_reader')
@@ -389,9 +396,13 @@
         self._creds['project_reader'] = project_reader
         return project_reader
 
-    def get_creds_by_roles(self, roles, force_new=False):
+    def get_project_alt_reader_creds(self):
+        # TODO(gmann): Implement alt reader hash.
+        return
+
+    def get_creds_by_roles(self, roles, force_new=False, scope=None):
         roles = list(set(roles))
-        exist_creds = self._creds.get(six.text_type(roles).encode(
+        exist_creds = self._creds.get(str(roles).encode(
             'utf-8'), None)
         # The force kwarg is used to allocate an additional set of creds with
         # the same role list. The index used for the previously allocation
@@ -401,11 +412,11 @@
         elif exist_creds and force_new:
             # NOTE(andreaf) In py3.x encode returns bytes, and b'' is bytes
             # In py2.7 encode returns strings, and b'' is still string
-            new_index = six.text_type(roles).encode('utf-8') + b'-' + \
-                six.text_type(len(self._creds)).encode('utf-8')
+            new_index = str(roles).encode('utf-8') + b'-' + \
+                str(len(self._creds)).encode('utf-8')
             self._creds[new_index] = exist_creds
         net_creds = self._get_creds(roles=roles)
-        self._creds[six.text_type(roles).encode('utf-8')] = net_creds
+        self._creds[str(roles).encode('utf-8')] = net_creds
         return net_creds
 
     def clear_creds(self):
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index c950f63..00f2aeb 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -418,7 +418,7 @@
     def _safe_body(self, body, maxlen=4096):
         # convert a structure into a string safely
         try:
-            text = six.text_type(body)
+            text = str(body)
         except UnicodeDecodeError:
             # if this isn't actually text, return marker that
             return "<BinaryData: removed>"
@@ -890,7 +890,7 @@
             return True
         return 'exceed' in resp_body.get('message', 'blabla')
 
-    def wait_for_resource_deletion(self, id):
+    def wait_for_resource_deletion(self, id, *args, **kwargs):
         """Waits for a resource to be deleted
 
         This method will loop over is_resource_deleted until either
@@ -903,7 +903,7 @@
         """
         start_time = int(time.time())
         while True:
-            if self.is_resource_deleted(id):
+            if self.is_resource_deleted(id, *args, **kwargs):
                 return
             if int(time.time()) - start_time >= self.build_timeout:
                 message = ('Failed to delete %(resource_type)s %(id)s within '
diff --git a/tempest/lib/services/identity/v3/oauth_token_client.py b/tempest/lib/services/identity/v3/oauth_token_client.py
index 3336094..236b224 100644
--- a/tempest/lib/services/identity/v3/oauth_token_client.py
+++ b/tempest/lib/services/identity/v3/oauth_token_client.py
@@ -33,7 +33,7 @@
     def _escape(self, s):
         """Escape a unicode string in an OAuth-compatible fashion."""
         safe = b'~'
-        s = s.encode('utf-8') if isinstance(s, six.text_type) else s
+        s = s.encode('utf-8') if isinstance(s, str) else s
         s = urlparse.quote(s, safe)
         if isinstance(s, six.binary_type):
             s = s.decode('utf-8')
@@ -47,8 +47,8 @@
                                         verifier=None,
                                         http_method='GET'):
         """Generate OAUTH params along with signature."""
-        timestamp = six.text_type(int(time.time()))
-        nonce = six.text_type(random.getrandbits(64)) + timestamp
+        timestamp = str(int(time.time()))
+        nonce = str(random.getrandbits(64)) + timestamp
         oauth_params = [
             ('oauth_nonce', nonce),
             ('oauth_timestamp', timestamp),
diff --git a/tempest/lib/services/object_storage/container_client.py b/tempest/lib/services/object_storage/container_client.py
index 8472a97..6d07ec1 100644
--- a/tempest/lib/services/object_storage/container_client.py
+++ b/tempest/lib/services/object_storage/container_client.py
@@ -20,10 +20,18 @@
 from oslo_serialization import jsonutils as json
 
 from tempest.lib.common import rest_client
+from tempest.lib import exceptions
 
 
 class ContainerClient(rest_client.RestClient):
 
+    def is_resource_deleted(self, container):
+        try:
+            self.list_container_metadata(container)
+        except exceptions.NotFound:
+            return True
+        return False
+
     def update_container(self, container_name, **headers):
         """Creates or Updates a container
 
diff --git a/tempest/lib/services/object_storage/object_client.py b/tempest/lib/services/object_storage/object_client.py
index 8845d79..bb82975 100644
--- a/tempest/lib/services/object_storage/object_client.py
+++ b/tempest/lib/services/object_storage/object_client.py
@@ -23,6 +23,13 @@
 
 class ObjectClient(rest_client.RestClient):
 
+    def is_resource_deleted(self, object_name, container):
+        try:
+            self.get_object(container, object_name)
+        except exceptions.NotFound:
+            return True
+        return False
+
     def create_object(self, container, object_name, data,
                       params=None, metadata=None, headers=None,
                       chunked=False):
diff --git a/tempest/lib/services/placement/resource_providers_client.py b/tempest/lib/services/placement/resource_providers_client.py
index fcd220f..e6fbcb2 100644
--- a/tempest/lib/services/placement/resource_providers_client.py
+++ b/tempest/lib/services/placement/resource_providers_client.py
@@ -81,3 +81,29 @@
         self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
+
+    def update_resource_providers_inventories(self, rp_uuid, **kwargs):
+        """Update resource providers inventories.
+
+        For full list of available parameters, please refer to the official
+        API reference:
+        https://docs.openstack.org/api-ref/placement/#update-resource-provider-inventories
+        """
+        url = '/resource_providers/{}/inventories'.format(rp_uuid)
+        data = json.dumps(kwargs)
+        resp, body = self.put(url, data)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_resource_providers_inventories(self, rp_uuid):
+        """Delete resource providers inventories.
+
+        For full list of available parameters, please refer to the official
+        API reference:
+        https://docs.openstack.org/api-ref/placement/#delete-resource-provider-inventories
+        """
+        url = '/resource_providers/{}/inventories'.format(rp_uuid)
+        resp, body = self.delete(url)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 99a3f32..22d0fd2 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -18,6 +18,7 @@
 import subprocess
 
 import netaddr
+
 from oslo_log import log
 from oslo_serialization import jsonutils as json
 from oslo_utils import netutils
@@ -589,7 +590,7 @@
             rules.append(sg_rule)
         return rules
 
-    def _create_security_group(self, **kwargs):
+    def create_security_group(self, **kwargs):
         """Create security group and add rules to security group"""
         if not kwargs.get('name'):
             kwargs['name'] = data_utils.rand_name(self.__class__.__name__)
@@ -1060,10 +1061,10 @@
         if not CONF.service_available.neutron:
             raise cls.skipException('Neutron not available')
 
-    def _create_network(self, networks_client=None,
-                        project_id=None,
-                        namestart='network-smoke-',
-                        port_security_enabled=True, **net_dict):
+    def create_network(self, networks_client=None,
+                       project_id=None,
+                       namestart='network-smoke-',
+                       port_security_enabled=True, **net_dict):
         if not networks_client:
             networks_client = self.networks_client
         if not project_id:
@@ -1098,6 +1099,8 @@
         :Keyword Arguments:
 
             * *ip_version = ip version of the given network,
+            use_default_subnetpool = default subnetpool to
+                    manage IPv6 addresses range.
         """
 
         if not subnets_client:
@@ -1120,51 +1123,73 @@
                         network_id=ext_net['id'], cidr=cidr)['subnets'])
             return len(tenant_subnets + external_subnets) != 0
 
-        ip_version = kwargs.pop('ip_version', 4)
-
-        if ip_version == 6:
-            tenant_cidr = netaddr.IPNetwork(
-                CONF.network.project_network_v6_cidr)
-            num_bits = CONF.network.project_network_v6_mask_bits
-        else:
-            tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
-            num_bits = CONF.network.project_network_mask_bits
-
-        result = None
-        str_cidr = None
-        # Repeatedly attempt subnet creation with sequential cidr
-        # blocks until an unallocated block is found.
-        for subnet_cidr in tenant_cidr.subnet(num_bits):
-            str_cidr = str(subnet_cidr)
-            if cidr_in_use(str_cidr, project_id=network['project_id']):
-                continue
+        def _make_create_subnet_request(namestart, network,
+                                        ip_version, subnets_client, **kwargs):
 
             subnet = dict(
                 name=data_utils.rand_name(namestart),
                 network_id=network['id'],
                 project_id=network['project_id'],
-                cidr=str_cidr,
                 ip_version=ip_version,
                 **kwargs
             )
+
+            if ip_version == 6:
+                subnet['ipv6_address_mode'] = 'slaac'
+                subnet['ipv6_ra_mode'] = 'slaac'
+
             try:
-                result = subnets_client.create_subnet(**subnet)
-                break
+                return subnets_client.create_subnet(**subnet)
             except lib_exc.Conflict as e:
-                is_overlapping_cidr = 'overlaps with another subnet' in str(e)
-                if not is_overlapping_cidr:
+                if 'overlaps with another subnet' not in str(e):
                     raise
+
+        result = None
+        str_cidr = None
+
+        use_default_subnetpool = kwargs.get('use_default_subnetpool', False)
+        ip_version = kwargs.pop('ip_version', 4)
+
+        if not use_default_subnetpool:
+
+            if ip_version == 6:
+                tenant_cidr = netaddr.IPNetwork(
+                    CONF.network.project_network_v6_cidr)
+                num_bits = CONF.network.project_network_v6_mask_bits
+            else:
+                tenant_cidr = netaddr.IPNetwork(
+                    CONF.network.project_network_cidr)
+                num_bits = CONF.network.project_network_mask_bits
+
+        # Repeatedly attempt subnet creation with sequential cidr
+        # blocks until an unallocated block is found.
+            for subnet_cidr in tenant_cidr.subnet(num_bits):
+                str_cidr = str(subnet_cidr)
+                if cidr_in_use(str_cidr, project_id=network['project_id']):
+                    continue
+                result = _make_create_subnet_request(
+                    namestart, network, ip_version, subnets_client,
+                    cidr=str_cidr, **kwargs)
+
+                if result is not None:
+                    break
+
+        else:
+            result = _make_create_subnet_request(
+                namestart, network, ip_version, subnets_client,
+                **kwargs)
         self.assertIsNotNone(result, 'Unable to allocate tenant network')
 
         subnet = result['subnet']
-        self.assertEqual(subnet['cidr'], str_cidr)
+        if str_cidr is not None:
+            self.assertEqual(subnet['cidr'], str_cidr)
 
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         subnets_client.delete_subnet, subnet['id'])
 
         return subnet
 
-    def _get_server_port_id_and_ip4(self, server, ip_addr=None, **kwargs):
+    def get_server_port_id_and_ip4(self, server, ip_addr=None, **kwargs):
 
         if ip_addr and not kwargs.get('fixed_ips'):
             kwargs['fixed_ips'] = 'ip_address=%s' % ip_addr
@@ -1201,7 +1226,7 @@
                          % port_map)
         return port_map[0]
 
-    def _get_network_by_name(self, network_name):
+    def get_network_by_name(self, network_name):
         net = self.os_admin.networks_client.list_networks(
             name=network_name)['networks']
         self.assertNotEmpty(net,
@@ -1217,7 +1242,7 @@
         if not client:
             client = self.floating_ips_client
         if not port_id:
-            port_id, ip4 = self._get_server_port_id_and_ip4(server)
+            port_id, ip4 = self.get_server_port_id_and_ip4(server)
         else:
             ip4 = None
 
@@ -1245,7 +1270,7 @@
         This wrapper utility attaches the floating_ip for
         the respective port_id of server
         """
-        port_id, _ = self._get_server_port_id_and_ip4(server)
+        port_id, _ = self.get_server_port_id_and_ip4(server)
         kwargs = dict(port_id=port_id)
         floating_ip = self.floating_ips_client.update_floatingip(
             floating_ip['id'], **kwargs)['floatingip']
@@ -1361,17 +1386,17 @@
         self.log_console_output()
         self.fail(msg)
 
-    def _create_security_group(self, security_group_rules_client=None,
-                               project_id=None,
-                               namestart='secgroup-smoke',
-                               security_groups_client=None):
+    def create_security_group(self, security_group_rules_client=None,
+                              project_id=None,
+                              namestart='secgroup-smoke',
+                              security_groups_client=None):
         if security_group_rules_client is None:
             security_group_rules_client = self.security_group_rules_client
         if security_groups_client is None:
             security_groups_client = self.security_groups_client
         if project_id is None:
             project_id = security_groups_client.project_id
-        secgroup = self._create_empty_security_group(
+        secgroup = self.create_empty_security_group(
             namestart=namestart, client=security_groups_client,
             project_id=project_id)
 
@@ -1385,8 +1410,8 @@
             self.assertEqual(secgroup['id'], rule['security_group_id'])
         return secgroup
 
-    def _create_empty_security_group(self, client=None, project_id=None,
-                                     namestart='secgroup-smoke'):
+    def create_empty_security_group(self, client=None, project_id=None,
+                                    namestart='secgroup-smoke'):
         """Create a security group without rules.
 
         Default rules will be created:
@@ -1520,7 +1545,7 @@
 
         return rules
 
-    def _get_router(self, client=None, project_id=None, **kwargs):
+    def get_router(self, client=None, project_id=None, **kwargs):
         """Retrieve a router for the given tenant id.
 
         If a public router has been configured, it will be returned.
@@ -1589,18 +1614,18 @@
             if not CONF.compute.fixed_network_name:
                 m = 'fixed_network_name must be specified in config'
                 raise lib_exc.InvalidConfiguration(m)
-            network = self._get_network_by_name(
+            network = self.get_network_by_name(
                 CONF.compute.fixed_network_name)
             router = None
             subnet = None
         else:
-            network = self._create_network(
+            network = self.create_network(
                 networks_client=networks_client,
                 project_id=project_id,
                 port_security_enabled=port_security_enabled,
                 **net_dict)
-            router = self._get_router(client=routers_client,
-                                      project_id=project_id)
+            router = self.get_router(client=routers_client,
+                                     project_id=project_id)
             subnet_kwargs = dict(network=network,
                                  subnets_client=subnets_client)
             # use explicit check because empty list is a valid option
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index fe42583..5201315 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -78,7 +78,7 @@
         self.assertEqual(1, disks.count(CONF.compute.volume_device_name))
 
     def create_and_add_security_group_to_server(self, server):
-        secgroup = self._create_security_group()
+        secgroup = self.create_security_group()
         self.servers_client.add_security_group(server['id'],
                                                name=secgroup['name'])
         self.addCleanup(self.servers_client.remove_security_group,
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index dbab212..20d2e80 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -60,7 +60,7 @@
     def _setup_server(self, keypair):
         security_groups = []
         if utils.is_extension_enabled('security-group', 'network'):
-            security_group = self._create_security_group()
+            security_group = self.create_security_group()
             security_groups = [{'name': security_group['name']}]
         network, _, _ = self.create_networks()
         server = self.create_server(
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 6c1b3fa..e359c71 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -159,7 +159,7 @@
         keypair = self.create_keypair()
         self.keypairs[keypair['name']] = keypair
         security_groups = [
-            {'name': self._create_security_group()['name']}
+            {'name': self.create_security_group()['name']}
         ]
         network = {'uuid': network['id']}
         if port_id is not None:
@@ -223,14 +223,14 @@
         floating_ip, server = self.floating_ip_tuple
         # create a new server for the floating ip
         server = self._create_server(self.network)
-        port_id, _ = self._get_server_port_id_and_ip4(server)
+        port_id, _ = self.get_server_port_id_and_ip4(server)
         floating_ip = self.floating_ips_client.update_floatingip(
             floating_ip['id'], port_id=port_id)['floatingip']
         self.assertEqual(port_id, floating_ip['port_id'])
         self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
 
     def _create_new_network(self, create_gateway=False):
-        self.new_net = self._create_network()
+        self.new_net = self.create_network()
         if create_gateway:
             self.new_subnet = self.create_subnet(
                 network=self.new_net)
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 9be28c4..4f5118b 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -66,7 +66,7 @@
     def setUp(self):
         super(TestGettingAddress, self).setUp()
         self.keypair = self.create_keypair()
-        self.sec_grp = self._create_security_group()
+        self.sec_grp = self.create_security_group()
 
     def prepare_network(self, address6_mode, n_subnets6=1, dualnet=False):
         """Prepare network
@@ -77,15 +77,15 @@
         if dualnet - create IPv6 subnets on a different network
         :return: list of created networks
         """
-        network = self._create_network()
+        network = self.create_network()
         if dualnet:
-            network_v6 = self._create_network()
+            network_v6 = self.create_network()
 
         sub4 = self.create_subnet(network=network,
                                   namestart='sub4',
                                   ip_version=4)
 
-        router = self._get_router()
+        router = self.get_router()
         self.routers_client.add_router_interface(router['id'],
                                                  subnet_id=sub4['id'])
 
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 496a371..e078f23 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -197,14 +197,14 @@
         tenant.keypair = keypair
 
     def _create_tenant_security_groups(self, tenant):
-        access_sg = self._create_empty_security_group(
+        access_sg = self.create_empty_security_group(
             namestart='secgroup_access-',
             project_id=tenant.creds.project_id,
             client=tenant.manager.security_groups_client
         )
 
         # don't use default secgroup since it allows in-project traffic
-        def_sg = self._create_empty_security_group(
+        def_sg = self.create_empty_security_group(
             namestart='secgroup_general-',
             project_id=tenant.creds.project_id,
             client=tenant.manager.security_groups_client
@@ -534,7 +534,7 @@
         new_tenant = self.primary_tenant
 
         # Create empty security group and add icmp rule in it
-        new_sg = self._create_empty_security_group(
+        new_sg = self.create_empty_security_group(
             namestart='secgroup_new-',
             project_id=new_tenant.creds.project_id,
             client=new_tenant.manager.security_groups_client)
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 60242d5..4c82d84 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -128,7 +128,7 @@
     @utils.services('compute', 'network')
     def test_server_basic_ops(self):
         keypair = self.create_keypair()
-        security_group = self._create_security_group()
+        security_group = self.create_security_group()
         self.md = {'meta1': 'data1', 'meta2': 'data2', 'metaN': 'dataN'}
         self.instance = self.create_server(
             key_name=keypair['name'],
diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py
index ed06898..29612ec 100644
--- a/tempest/scenario/test_shelve_instance.py
+++ b/tempest/scenario/test_shelve_instance.py
@@ -76,7 +76,7 @@
                                                 cold_migrate=False):
         keypair = self.create_keypair()
 
-        security_group = self._create_security_group()
+        security_group = self.create_security_group()
         security_groups = [{'name': security_group['name']}]
 
         server = self.create_server(
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index a062d40..d04cb9a 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -50,7 +50,7 @@
     def test_snapshot_pattern(self):
         # prepare for booting an instance
         keypair = self.create_keypair()
-        security_group = self._create_security_group()
+        security_group = self.create_security_group()
 
         # boot an instance and create a timestamp file in it
         server = self.create_server(
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index a8e4c30..4b81b9e 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -81,7 +81,7 @@
     def test_stamp_pattern(self):
         # prepare for booting an instance
         keypair = self.create_keypair()
-        security_group = self._create_security_group()
+        security_group = self.create_security_group()
 
         # boot an instance and create a timestamp file in it
         volume = self.create_volume()
diff --git a/tempest/scenario/test_volume_backup_restore.py b/tempest/scenario/test_volume_backup_restore.py
index 8a8c54e..71e6b53 100644
--- a/tempest/scenario/test_volume_backup_restore.py
+++ b/tempest/scenario/test_volume_backup_restore.py
@@ -70,7 +70,7 @@
 
         # Create keypair and security group
         keypair = self.create_keypair()
-        security_group = self._create_security_group()
+        security_group = self.create_security_group()
 
         # Boot a server from the restored backup
         bd_map_v2 = [{
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 3b4bbda..5a5cc27 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -64,7 +64,7 @@
 
         LOG.info("Creating keypair and security group")
         keypair = self.create_keypair()
-        security_group = self._create_security_group()
+        security_group = self.create_security_group()
 
         # create an instance from volume
         LOG.info("Booting instance 1 from volume")
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
index 106500e..57d2a1a 100644
--- a/tempest/scenario/test_volume_migrate_attached.py
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -100,7 +100,7 @@
     def test_volume_retype_attached(self):
         LOG.info("Creating keypair and security group")
         keypair = self.create_keypair()
-        security_group = self._create_security_group()
+        security_group = self.create_security_group()
 
         # create volume types
         LOG.info("Creating Volume types")
@@ -156,7 +156,7 @@
     def test_volume_migrate_attached(self):
         LOG.info("Creating keypair and security group")
         keypair = self.create_keypair()
-        security_group = self._create_security_group()
+        security_group = self.create_security_group()
 
         LOG.info("Creating volume")
         # Create a unique volume type to avoid using the backend default
diff --git a/tempest/test.py b/tempest/test.py
index 68602d6..655b9a4 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -296,6 +296,7 @@
         identity_version = cls.get_identity_version()
         # setting force_tenant_isolation to True also needs admin credentials.
         if ('admin' in cls.credentials or
+                'alt_admin' in cls.credentials or
                 getattr(cls, 'force_tenant_isolation', False)):
             if not credentials.is_admin_available(
                     identity_version=identity_version):
@@ -414,8 +415,18 @@
                             'alt_manager', 'os_alt', version='Pike',
                             removal_version='Queens')
             elif isinstance(credentials_type, list):
+                scope = 'project'
+                if credentials_type[0].startswith('system'):
+                    scope = 'system'
+                elif credentials_type[0].startswith('domain'):
+                    scope = 'domain'
                 manager = cls.get_client_manager(roles=credentials_type[1:],
-                                                 force_new=True)
+                                                 force_new=True,
+                                                 scope=scope)
+                setattr(cls, 'os_%s' % credentials_type[0], manager)
+                # TODO(gmann): Setting the old style attribute too for
+                # backward compatibility but at some point we should
+                # remove this.
                 setattr(cls, 'os_roles_%s' % credentials_type[0], manager)
 
     @classmethod
@@ -657,7 +668,7 @@
 
     @classmethod
     def get_client_manager(cls, credential_type=None, roles=None,
-                           force_new=None):
+                           force_new=None, scope=None):
         """Returns an OpenStack client manager
 
         Returns an OpenStack client manager based on either credential_type
@@ -665,6 +676,7 @@
         credential_type 'primary'
         :param credential_type: string - primary, alt or admin
         :param roles: list of roles
+        :param scope: scope for the test user
 
         :returns: the created client manager
         :raises skipException: if the requested credentials are not available
@@ -683,7 +695,7 @@
                         " is not able to provide credentials with the %s role "
                         "assigned." % (cls.__name__, role))
                     raise cls.skipException(skip_msg)
-            params = dict(roles=roles)
+            params = dict(roles=roles, scope=scope)
             if force_new is not None:
                 params.update(force_new=force_new)
             creds = cred_provider.get_creds_by_roles(**params)
@@ -850,7 +862,13 @@
         if isinstance(credentials_type, six.string_types):
             manager = cls.get_client_manager(credential_type=credentials_type)
         elif isinstance(credentials_type, list):
-            manager = cls.get_client_manager(roles=credentials_type[1:])
+            scope = 'project'
+            if credentials_type[0].startswith('system'):
+                scope = 'system'
+            elif credentials_type[0].startswith('domain'):
+                scope = 'domain'
+            manager = cls.get_client_manager(roles=credentials_type[1:],
+                                             scope=scope)
         else:
             manager = cls.get_client_manager()
 
diff --git a/tempest/tests/api/compute/test_base.py b/tempest/tests/api/compute/test_base.py
index 74d2625..8a1873b 100644
--- a/tempest/tests/api/compute/test_base.py
+++ b/tempest/tests/api/compute/test_base.py
@@ -15,7 +15,6 @@
 from unittest import mock
 
 from oslo_utils import uuidutils
-import six
 
 from tempest.api.compute import base as compute_base
 from tempest.common import waiters
@@ -128,9 +127,9 @@
             mock.sentinel.server_id, wait_until='active')
         # make our assertions
         if fault:
-            self.assertIn(fault, six.text_type(ex))
+            self.assertIn(fault, str(ex))
         else:
-            self.assertNotIn(fault, six.text_type(ex))
+            self.assertNotIn(fault, str(ex))
         if compute_base.BaseV2ComputeTest.is_requested_microversion_compatible(
             '2.35'):
             status = 'ACTIVE'
diff --git a/tempest/tests/cmd/test_run.py b/tempest/tests/cmd/test_run.py
index ec7b760..3b5e901 100644
--- a/tempest/tests/cmd/test_run.py
+++ b/tempest/tests/cmd/test_run.py
@@ -21,7 +21,6 @@
 from unittest import mock
 
 import fixtures
-import six
 
 from tempest.cmd import run
 from tempest.cmd import workspace
@@ -153,12 +152,12 @@
         subprocess.call(['stestr', 'init'])
         out, err = self.assertRunExit(['tempest', 'run', '-l'], 0)
         tests = out.split()
-        tests = sorted([six.text_type(x.rstrip()) for x in tests if x])
+        tests = sorted([str(x.rstrip()) for x in tests if x])
         result = [
-            six.text_type('tests.test_failing.FakeTestClass.test_pass'),
-            six.text_type('tests.test_failing.FakeTestClass.test_pass_list'),
-            six.text_type('tests.test_passing.FakeTestClass.test_pass'),
-            six.text_type('tests.test_passing.FakeTestClass.test_pass_list'),
+            str('tests.test_failing.FakeTestClass.test_pass'),
+            str('tests.test_failing.FakeTestClass.test_pass_list'),
+            str('tests.test_passing.FakeTestClass.test_pass'),
+            str('tests.test_passing.FakeTestClass.test_pass_list'),
         ]
         # NOTE(mtreinish): on python 3 the subprocess prints b'' around
         # stdout.
diff --git a/tempest/tests/lib/common/test_api_version_utils.py b/tempest/tests/lib/common/test_api_version_utils.py
index b99e8d4..8d5de09 100644
--- a/tempest/tests/lib/common/test_api_version_utils.py
+++ b/tempest/tests/lib/common/test_api_version_utils.py
@@ -12,7 +12,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import six
 import testtools
 
 from tempest.lib.common import api_version_utils
@@ -31,7 +30,7 @@
                                                            cfg_max_version)
         except testtools.TestCase.skipException as e:
             if not expected_skip:
-                raise testtools.TestCase.failureException(six.text_type(e))
+                raise testtools.TestCase.failureException(str(e))
 
     def test_version_min_in_range(self):
         self._test_version('2.2', '2.10', '2.1', '2.7')
diff --git a/tempest/tests/lib/common/test_dynamic_creds.py b/tempest/tests/lib/common/test_dynamic_creds.py
index e9073cc..b4b1b91 100644
--- a/tempest/tests/lib/common/test_dynamic_creds.py
+++ b/tempest/tests/lib/common/test_dynamic_creds.py
@@ -214,6 +214,56 @@
         self.assertEqual(admin_creds.user_id, '1234')
 
     @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def test_project_alt_admin_creds(self, MockRestClient):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_list_roles('1234', 'admin')
+        self._mock_user_create('1234', 'fake_alt_admin_user')
+        self._mock_tenant_create('1234', 'fake_alt_admin')
+
+        user_mock = mock.patch.object(self.roles_client.RolesClient,
+                                      'create_user_role_on_project')
+        user_mock.start()
+        self.addCleanup(user_mock.stop)
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_project') as user_mock:
+            alt_admin_creds = creds.get_project_alt_admin_creds()
+        user_mock.assert_has_calls([
+            mock.call('1234', '1234', '1234')])
+        self.assertEqual(alt_admin_creds.username, 'fake_alt_admin_user')
+        self.assertEqual(alt_admin_creds.project_name, 'fake_alt_admin')
+        # Verify IDs
+        self.assertEqual(alt_admin_creds.project_id, '1234')
+        self.assertEqual(alt_admin_creds.user_id, '1234')
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def test_project_alt_member_creds(self, MockRestClient):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_assign_user_role()
+        self._mock_list_role()
+        self._mock_tenant_create('1234', 'fake_alt_member')
+        self._mock_user_create('1234', 'fake_alt_user')
+        alt_member_creds = creds.get_project_alt_member_creds()
+        self.assertEqual(alt_member_creds.username, 'fake_alt_user')
+        self.assertEqual(alt_member_creds.project_name, 'fake_alt_member')
+        # Verify IDs
+        self.assertEqual(alt_member_creds.project_id, '1234')
+        self.assertEqual(alt_member_creds.user_id, '1234')
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def test_project_alt_reader_creds(self, MockRestClient):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_assign_user_role()
+        self._mock_list_roles('1234', 'reader')
+        self._mock_tenant_create('1234', 'fake_alt_reader')
+        self._mock_user_create('1234', 'fake_alt_user')
+        alt_reader_creds = creds.get_project_alt_reader_creds()
+        self.assertEqual(alt_reader_creds.username, 'fake_alt_user')
+        self.assertEqual(alt_reader_creds.project_name, 'fake_alt_reader')
+        # Verify IDs
+        self.assertEqual(alt_reader_creds.project_id, '1234')
+        self.assertEqual(alt_reader_creds.user_id, '1234')
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_role_creds(self, MockRestClient):
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
         self._mock_list_2_roles()
@@ -242,6 +292,100 @@
         self.assertEqual(role_creds.user_id, '1234')
 
     @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def test_role_creds_with_project_scope(self, MockRestClient):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_list_2_roles()
+        self._mock_user_create('1234', 'fake_role_user')
+        self._mock_tenant_create('1234', 'fake_role_project')
+
+        user_mock = mock.patch.object(self.roles_client.RolesClient,
+                                      'create_user_role_on_project')
+        user_mock.start()
+        self.addCleanup(user_mock.stop)
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_project') as user_mock:
+            role_creds = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope='project')
+        calls = user_mock.mock_calls
+        # Assert that the role creation is called with the 2 specified roles
+        self.assertEqual(len(calls), 2)
+        args = map(lambda x: x[1], calls)
+        args = list(args)
+        self.assertIn(('1234', '1234', '1234'), args)
+        self.assertIn(('1234', '1234', '12345'), args)
+        self.assertEqual(role_creds.username, 'fake_role_user')
+        self.assertEqual(role_creds.project_name, 'fake_role_project')
+        # Verify IDs
+        self.assertEqual(role_creds.project_id, '1234')
+        self.assertEqual(role_creds.user_id, '1234')
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def _test_get_same_role_creds_with_project_scope(self, MockRestClient,
+                                                     scope=None):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_list_2_roles()
+        self._mock_user_create('1234', 'fake_role_user')
+        self._mock_tenant_create('1234', 'fake_role_project')
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_project') as user_mock:
+            role_creds = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope=scope)
+        calls = user_mock.mock_calls
+        # Assert that the role creation is called with the 2 specified roles
+        self.assertEqual(len(calls), 2)
+
+        # Fetch the same creds again
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_project') as user_mock1:
+            role_creds_new = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope=scope)
+        calls = user_mock1.mock_calls
+        # Assert that previously created creds are return and no call to
+        # role creation.
+        self.assertEqual(len(calls), 0)
+        # Check if previously created creds are returned.
+        self.assertEqual(role_creds, role_creds_new)
+
+    def test_get_same_role_creds_with_project_scope(self):
+        self._test_get_same_role_creds_with_project_scope(scope='project')
+
+    def test_get_same_role_creds_with_default_scope(self):
+        self._test_get_same_role_creds_with_project_scope()
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def _test_get_different_role_creds_with_project_scope(
+            self, MockRestClient, scope=None):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_list_2_roles()
+        self._mock_user_create('1234', 'fake_role_user')
+        self._mock_tenant_create('1234', 'fake_role_project')
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_project') as user_mock:
+            role_creds = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope=scope)
+        calls = user_mock.mock_calls
+        # Assert that the role creation is called with the 2 specified roles
+        self.assertEqual(len(calls), 2)
+        # Fetch the creds with one role different
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_project') as user_mock1:
+            role_creds_new = creds.get_creds_by_roles(
+                roles=['role1'], scope=scope)
+        calls = user_mock1.mock_calls
+        # Because one role is different, assert that the role creation
+        # is called with the 1 specified roles
+        self.assertEqual(len(calls), 1)
+        # Check new creds is created for new roles.
+        self.assertNotEqual(role_creds, role_creds_new)
+
+    def test_get_different_role_creds_with_project_scope(self):
+        self._test_get_different_role_creds_with_project_scope(
+            scope='project')
+
+    def test_get_different_role_creds_with_default_scope(self):
+        self._test_get_different_role_creds_with_project_scope()
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_all_cred_cleanup(self, MockRestClient):
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
         self._mock_assign_user_role()
@@ -658,6 +802,232 @@
         return project_fix
 
     @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def test_role_creds_with_system_scope(self, MockRestClient):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_list_2_roles()
+        self._mock_user_create('1234', 'fake_role_user')
+
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_system') as user_mock:
+            role_creds = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope='system')
+        calls = user_mock.mock_calls
+        # Assert that the role creation is called with the 2 specified roles
+        self.assertEqual(len(calls), 2)
+        args = map(lambda x: x[1], calls)
+        args = list(args)
+        self.assertIn(('1234', '1234'), args)
+        self.assertIn(('1234', '12345'), args)
+        self.assertEqual(role_creds.username, 'fake_role_user')
+        self.assertEqual(role_creds.user_id, '1234')
+        # Verify system scope
+        self.assertEqual(role_creds.system, 'all')
+        # Verify domain is default
+        self.assertEqual(role_creds.domain_id, 'default')
+        self.assertEqual(role_creds.domain_name, 'Default')
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def test_get_same_role_creds_with_system_scope(self, MockRestClient):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_list_2_roles()
+        self._mock_user_create('1234', 'fake_role_user')
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_system') as user_mock:
+            role_creds = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope='system')
+        calls = user_mock.mock_calls
+        # Assert that the role creation is called with the 2 specified roles
+        self.assertEqual(len(calls), 2)
+
+        # Fetch the same creds again
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_system') as user_mock1:
+            role_creds_new = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope='system')
+        calls = user_mock1.mock_calls
+        # Assert that previously created creds are return and no call to
+        # role creation.
+        self.assertEqual(len(calls), 0)
+        # Verify system scope
+        self.assertEqual(role_creds_new.system, 'all')
+        # Check if previously created creds are returned.
+        self.assertEqual(role_creds, role_creds_new)
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def test_get_different_role_creds_with_system_scope(self, MockRestClient):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_list_2_roles()
+        self._mock_user_create('1234', 'fake_role_user')
+
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_system') as user_mock:
+            role_creds = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope='system')
+        calls = user_mock.mock_calls
+        # Assert that the role creation is called with the 2 specified roles
+        self.assertEqual(len(calls), 2)
+        # Verify system scope
+        self.assertEqual(role_creds.system, 'all')
+        # Fetch the creds with one role different
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_system') as user_mock1:
+            role_creds_new = creds.get_creds_by_roles(
+                roles=['role1'], scope='system')
+        calls = user_mock1.mock_calls
+        # Because one role is different, assert that the role creation
+        # is called with the 1 specified roles
+        self.assertEqual(len(calls), 1)
+        # Verify Scope
+        self.assertEqual(role_creds_new.system, 'all')
+        # Check new creds is created for new roles.
+        self.assertNotEqual(role_creds, role_creds_new)
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def test_role_creds_with_domain_scope(self, MockRestClient):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_list_2_roles()
+        self._mock_user_create('1234', 'fake_role_user')
+
+        domain = {
+            "id": '12',
+            "enabled": True,
+            "name": "TestDomain"
+        }
+
+        self.useFixture(fixtures.MockPatch(
+            'tempest.lib.common.cred_client.V3CredsClient.create_domain',
+            return_value=domain))
+
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_domain') as user_mock:
+            role_creds = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope='domain')
+        calls = user_mock.mock_calls
+        # Assert that the role creation is called with the 2 specified roles
+        self.assertEqual(len(calls), 2)
+        args = map(lambda x: x[1], calls)
+        args = list(args)
+        self.assertIn((domain['id'], '1234', '1234'), args)
+        self.assertIn((domain['id'], '1234', '12345'), args)
+        self.assertEqual(role_creds.username, 'fake_role_user')
+        self.assertEqual(role_creds.user_id, '1234')
+        # Verify creds are under new created domain
+        self.assertEqual(role_creds.domain_id, domain['id'])
+        self.assertEqual(role_creds.domain_name, domain['name'])
+        # Verify that Scope is None
+        self.assertIsNone(role_creds.system)
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def test_get_same_role_creds_with_domain_scope(self, MockRestClient):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_list_2_roles()
+        self._mock_user_create('1234', 'fake_role_user')
+
+        domain = {
+            "id": '12',
+            "enabled": True,
+            "name": "TestDomain"
+        }
+
+        self.useFixture(fixtures.MockPatch(
+            'tempest.lib.common.cred_client.V3CredsClient.create_domain',
+            return_value=domain))
+
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_domain') as user_mock:
+            role_creds = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope='domain')
+        calls = user_mock.mock_calls
+        # Assert that the role creation is called with the 2 specified roles
+        self.assertEqual(len(calls), 2)
+        self.assertEqual(role_creds.user_id, '1234')
+        # Verify Scope
+        self.assertIsNone(role_creds.system)
+        # Fetch the same creds again
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_domain') as user_mock1:
+            role_creds_new = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope='domain')
+        calls = user_mock1.mock_calls
+        # Assert that previously created creds are return and no call to
+        # role creation.
+        self.assertEqual(len(calls), 0)
+        # Verify Scope
+        self.assertIsNone(role_creds_new.system)
+        # Check if previously created creds are returned.
+        self.assertEqual(role_creds, role_creds_new)
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def test_get_different_role_creds_with_domain_scope(self, MockRestClient):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_list_2_roles()
+        self._mock_user_create('1234', 'fake_role_user')
+
+        domain = {
+            "id": '12',
+            "enabled": True,
+            "name": "TestDomain"
+        }
+
+        self.useFixture(fixtures.MockPatch(
+            'tempest.lib.common.cred_client.V3CredsClient.create_domain',
+            return_value=domain))
+
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_domain') as user_mock:
+            role_creds = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope='domain')
+        calls = user_mock.mock_calls
+        # Assert that the role creation is called with the 2 specified roles
+        self.assertEqual(len(calls), 2)
+        self.assertEqual(role_creds.user_id, '1234')
+        # Verify Scope
+        self.assertIsNone(role_creds.system)
+        # Fetch the same creds again
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_domain') as user_mock1:
+            role_creds_new = creds.get_creds_by_roles(
+                roles=['role1'], scope='domain')
+        calls = user_mock1.mock_calls
+        # Because one role is different, assert that the role creation
+        # is called with the 1 specified roles
+        self.assertEqual(len(calls), 1)
+        # Verify Scope
+        self.assertIsNone(role_creds_new.system)
+        # Check new creds is created for new roles.
+        self.assertNotEqual(role_creds, role_creds_new)
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def test_get_role_creds_with_different_scope(self, MockRestClient):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        self._mock_list_2_roles()
+        self._mock_user_create('1234', 'fake_role_user')
+        self._mock_tenant_create('1234', 'fake_role_project')
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_system') as user_mock:
+            role_creds = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope='system')
+        calls = user_mock.mock_calls
+        # Assert that the role creation is called with the 2 specified roles
+        self.assertEqual(len(calls), 2)
+        # Verify Scope
+        self.assertEqual(role_creds.system, 'all')
+
+        # Fetch the same role creds but with different scope
+        with mock.patch.object(self.roles_client.RolesClient,
+                               'create_user_role_on_project') as user_mock1:
+            role_creds_new = creds.get_creds_by_roles(
+                roles=['role1', 'role2'], scope='project')
+        calls = user_mock1.mock_calls
+        # Because scope is different, assert that the role creation
+        # is called with the 2 specified roles
+        self.assertEqual(len(calls), 2)
+        # Verify Scope
+        self.assertIsNone(role_creds_new.system)
+        # Check that created creds are different
+        self.assertNotEqual(role_creds, role_creds_new)
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
     def test_member_role_creation_with_duplicate(self, rest_client_mock):
         creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
         creds.creds_client = mock.MagicMock()
diff --git a/tempest/tests/lib/common/test_preprov_creds.py b/tempest/tests/lib/common/test_preprov_creds.py
index 579363e..499b6fe 100644
--- a/tempest/tests/lib/common/test_preprov_creds.py
+++ b/tempest/tests/lib/common/test_preprov_creds.py
@@ -17,7 +17,6 @@
 import shutil
 from unittest import mock
 
-import six
 import testtools
 
 import fixtures
@@ -109,7 +108,7 @@
             hash = hashlib.md5()
             account_for_hash = dict((k, v) for (k, v) in account.items()
                                     if k in hash_fields)
-            hash.update(six.text_type(account_for_hash).encode('utf-8'))
+            hash.update(str(account_for_hash).encode('utf-8'))
             temp_hash = hash.hexdigest()
             hash_list.append(temp_hash)
         return hash_list
diff --git a/tempest/tests/lib/services/placement/test_resource_providers_client.py b/tempest/tests/lib/services/placement/test_resource_providers_client.py
index 11aeaf2..485f584 100644
--- a/tempest/tests/lib/services/placement/test_resource_providers_client.py
+++ b/tempest/tests/lib/services/placement/test_resource_providers_client.py
@@ -48,6 +48,43 @@
     FAKE_RESOURCE_PROVIDER_AGGREGATES = {
         'aggregates': [FAKE_AGGREGATE_UUID]
     }
+    FAKE_RESOURCE_UPDATE_INVENTORIES_RESPONSE = {
+        "inventories": {
+            "MEMORY_MB": {
+                "allocation_ratio": 2.0,
+                "max_unit": 16,
+                "min_unit": 1,
+                "reserved": 0,
+                "step_size": 4,
+                "total": 128
+            },
+            "VCPU": {
+                "allocation_ratio": 10.0,
+                "max_unit": 2147483647,
+                "min_unit": 1,
+                "reserved": 2,
+                "step_size": 1,
+                "total": 64
+            }
+        },
+        "resource_provider_generation": 2
+    }
+    FAKE_RESOURCE_UPDATE_INVENTORIES_REQUEST = {
+        "inventories": {
+            "MEMORY_MB": {
+                "allocation_ratio": 2.0,
+                "max_unit": 16,
+                "step_size": 4,
+                "total": 128
+            },
+            "VCPU": {
+                "allocation_ratio": 10.0,
+                "reserved": 2,
+                "total": 64
+            }
+        },
+        "resource_provider_generation": 1
+    }
 
     def setUp(self):
         super(TestResourceProvidersClient, self).setUp()
@@ -102,6 +139,32 @@
     def test_list_resource_provider_inventories_with_bytes_body(self):
         self._test_list_resource_provider_inventories(bytes_body=True)
 
+    def _test_update_resource_providers_inventories(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_resource_providers_inventories,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_RESOURCE_UPDATE_INVENTORIES_RESPONSE,
+            to_utf=bytes_body,
+            status=200,
+            rp_uuid=self.FAKE_RESOURCE_PROVIDER_UUID,
+            **self.FAKE_RESOURCE_UPDATE_INVENTORIES_REQUEST
+        )
+
+    def test_update_resource_providers_inventories_with_str_body(self):
+        self._test_update_resource_providers_inventories()
+
+    def test_update_resource_providers_inventories_with_bytes_body(self):
+        self._test_update_resource_providers_inventories(bytes_body=True)
+
+    def test_delete_resource_providers_inventories(self):
+        self.check_service_client_function(
+            self.client.delete_resource_providers_inventories,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            status=204,
+            rp_uuid=self.FAKE_RESOURCE_PROVIDER_UUID,
+        )
+
     def _test_list_resource_provider_aggregates(self, bytes_body=False):
         self.check_service_client_function(
             self.client.list_resource_provider_aggregates,
diff --git a/tempest/tests/lib/test_ssh.py b/tempest/tests/lib/test_ssh.py
index 0ec9262..035bdb0 100644
--- a/tempest/tests/lib/test_ssh.py
+++ b/tempest/tests/lib/test_ssh.py
@@ -274,7 +274,7 @@
         client = ssh.Client('localhost', 'root', timeout=2)
         exc = self.assertRaises(exceptions.SSHExecCommandFailed,
                                 client.exec_command, "test")
-        self.assertIn('R' + self._utf8_string, six.text_type(exc))
+        self.assertIn('R' + self._utf8_string, str(exc))
 
     def test_exec_command_no_select(self):
         gsc_mock = self.patch('tempest.lib.common.ssh.Client.'
diff --git a/tempest/tests/test_base_test.py b/tempest/tests/test_base_test.py
index b154cd5..88c28bf 100644
--- a/tempest/tests/test_base_test.py
+++ b/tempest/tests/test_base_test.py
@@ -109,7 +109,7 @@
 
         test.BaseTestCase.get_tenant_network(credentials_type=creds)
 
-        mock_gcm.assert_called_once_with(roles=['role1'])
+        mock_gcm.assert_called_once_with(roles=['role1'], scope='project')
         mock_gprov.assert_called_once_with()
         mock_gtn.assert_called_once_with(mock_prov, net_client,
                                          self.fixed_network_name)
diff --git a/tempest/tests/test_list_tests.py b/tempest/tests/test_list_tests.py
index 1cc9c9a..fe44ef6 100644
--- a/tempest/tests/test_list_tests.py
+++ b/tempest/tests/test_list_tests.py
@@ -16,8 +16,6 @@
 import re
 import subprocess
 
-import six
-
 from tempest.tests import base
 
 
@@ -32,7 +30,7 @@
         self.assertEqual(0, p.returncode,
                          "test discovery failed, one or more files cause an "
                          "error on import %s" % ids)
-        ids = six.text_type(ids).split('\n')
+        ids = str(ids).split('\n')
         for test_id in ids:
             if re.match(r'(\w+\.){3}\w+', test_id):
                 if not test_id.startswith('tempest.'):
diff --git a/tempest/tests/test_microversions.py b/tempest/tests/test_microversions.py
index ee6db71..835f51c 100644
--- a/tempest/tests/test_microversions.py
+++ b/tempest/tests/test_microversions.py
@@ -13,7 +13,6 @@
 #    under the License.
 
 from oslo_config import cfg
-import six
 import testtools
 
 from tempest.api.compute import base as compute_base
@@ -75,7 +74,7 @@
                 self.assertRaises(testtools.TestCase.skipException,
                                   test_class.skip_checks)
         except testtools.TestCase.skipException as e:
-            raise testtools.TestCase.failureException(six.text_type(e))
+            raise testtools.TestCase.failureException(str(e))
 
     def test_config_version_none_none(self):
         expected_pass_tests = [VersionTestNoneTolatest, VersionTestNoneTo2_2]
diff --git a/tempest/tests/test_test.py b/tempest/tests/test_test.py
index 72e8b6d..9aeedb3 100644
--- a/tempest/tests/test_test.py
+++ b/tempest/tests/test_test.py
@@ -453,6 +453,130 @@
             expected_creds[1][1:],
             mock_get_client_manager.mock_calls[1][2]['roles'])
 
+    def test_setup_credentials_with_role_and_system_scope(self):
+        expected_creds = [['system_my_role', 'role1', 'role2']]
+
+        class SystemRoleCredentials(self.parent_test):
+            credentials = expected_creds
+
+        expected_clients = 'clients'
+        with mock.patch.object(
+                SystemRoleCredentials,
+                'get_client_manager') as mock_get_client_manager:
+            mock_get_client_manager.return_value = expected_clients
+            sys_creds = SystemRoleCredentials()
+            sys_creds.setup_credentials()
+        self.assertTrue(hasattr(sys_creds, 'os_system_my_role'))
+        self.assertEqual(expected_clients, sys_creds.os_system_my_role)
+        self.assertTrue(hasattr(sys_creds, 'os_roles_system_my_role'))
+        self.assertEqual(expected_clients, sys_creds.os_roles_system_my_role)
+        self.assertEqual(1, mock_get_client_manager.call_count)
+        self.assertEqual(
+            expected_creds[0][1:],
+            mock_get_client_manager.mock_calls[0][2]['roles'])
+        self.assertEqual(
+            'system',
+            mock_get_client_manager.mock_calls[0][2]['scope'])
+
+    def test_setup_credentials_with_multiple_role_and_system_scope(self):
+        expected_creds = [['system_my_role', 'role1', 'role2'],
+                          ['system_my_role2', 'role1', 'role2'],
+                          ['system_my_role3', 'role3']]
+
+        class SystemRoleCredentials(self.parent_test):
+            credentials = expected_creds
+
+        expected_clients = 'clients'
+        with mock.patch.object(
+                SystemRoleCredentials,
+                'get_client_manager') as mock_get_client_manager:
+            mock_get_client_manager.return_value = expected_clients
+            sys_creds = SystemRoleCredentials()
+            sys_creds.setup_credentials()
+        self.assertTrue(hasattr(sys_creds, 'os_system_my_role'))
+        self.assertEqual(expected_clients, sys_creds.os_system_my_role)
+        self.assertTrue(hasattr(sys_creds, 'os_roles_system_my_role'))
+        self.assertEqual(expected_clients, sys_creds.os_roles_system_my_role)
+        self.assertTrue(hasattr(sys_creds, 'os_system_my_role2'))
+        self.assertEqual(expected_clients, sys_creds.os_system_my_role2)
+        self.assertTrue(hasattr(sys_creds, 'os_roles_system_my_role2'))
+        self.assertEqual(expected_clients, sys_creds.os_roles_system_my_role2)
+        self.assertTrue(hasattr(sys_creds, 'os_system_my_role3'))
+        self.assertEqual(expected_clients, sys_creds.os_system_my_role3)
+        self.assertTrue(hasattr(sys_creds, 'os_roles_system_my_role3'))
+        self.assertEqual(expected_clients, sys_creds.os_roles_system_my_role3)
+        self.assertEqual(3, mock_get_client_manager.call_count)
+        self.assertEqual(
+            expected_creds[0][1:],
+            mock_get_client_manager.mock_calls[0][2]['roles'])
+        self.assertEqual(
+            'system', mock_get_client_manager.mock_calls[0][2]['scope'])
+        self.assertEqual(
+            expected_creds[1][1:],
+            mock_get_client_manager.mock_calls[1][2]['roles'])
+        self.assertEqual(
+            'system', mock_get_client_manager.mock_calls[1][2]['scope'])
+        self.assertEqual(
+            expected_creds[2][1:],
+            mock_get_client_manager.mock_calls[2][2]['roles'])
+        self.assertEqual(
+            'system', mock_get_client_manager.mock_calls[2][2]['scope'])
+
+    def test_setup_credentials_with_role_and_multiple_scope(self):
+        expected_creds = [['my_role', 'role1', 'role2'],
+                          ['project_my_role', 'role1', 'role2'],
+                          ['domain_my_role', 'role1', 'role2'],
+                          ['system_my_role', 'role1', 'role2']]
+
+        class SystemRoleCredentials(self.parent_test):
+            credentials = expected_creds
+
+        expected_clients = 'clients'
+        with mock.patch.object(
+                SystemRoleCredentials,
+                'get_client_manager') as mock_get_client_manager:
+            mock_get_client_manager.return_value = expected_clients
+            sys_creds = SystemRoleCredentials()
+            sys_creds.setup_credentials()
+        self.assertTrue(hasattr(sys_creds, 'os_my_role'))
+        self.assertEqual(expected_clients, sys_creds.os_my_role)
+        self.assertTrue(hasattr(sys_creds, 'os_roles_my_role'))
+        self.assertEqual(expected_clients, sys_creds.os_roles_my_role)
+        self.assertTrue(hasattr(sys_creds, 'os_project_my_role'))
+        self.assertEqual(expected_clients, sys_creds.os_project_my_role)
+        self.assertTrue(hasattr(sys_creds, 'os_roles_project_my_role'))
+        self.assertEqual(expected_clients, sys_creds.os_roles_project_my_role)
+        self.assertTrue(hasattr(sys_creds, 'os_domain_my_role'))
+        self.assertEqual(expected_clients, sys_creds.os_domain_my_role)
+        self.assertTrue(hasattr(sys_creds, 'os_roles_domain_my_role'))
+        self.assertEqual(expected_clients, sys_creds.os_roles_domain_my_role)
+        self.assertTrue(hasattr(sys_creds, 'os_system_my_role'))
+        self.assertEqual(expected_clients, sys_creds.os_system_my_role)
+        self.assertTrue(hasattr(sys_creds, 'os_roles_system_my_role'))
+        self.assertEqual(expected_clients, sys_creds.os_roles_system_my_role)
+
+        self.assertEqual(4, mock_get_client_manager.call_count)
+        self.assertEqual(
+            expected_creds[0][1:],
+            mock_get_client_manager.mock_calls[0][2]['roles'])
+        self.assertEqual(
+            'project', mock_get_client_manager.mock_calls[0][2]['scope'])
+        self.assertEqual(
+            expected_creds[1][1:],
+            mock_get_client_manager.mock_calls[1][2]['roles'])
+        self.assertEqual(
+            'project', mock_get_client_manager.mock_calls[1][2]['scope'])
+        self.assertEqual(
+            expected_creds[2][1:],
+            mock_get_client_manager.mock_calls[2][2]['roles'])
+        self.assertEqual(
+            'domain', mock_get_client_manager.mock_calls[2][2]['scope'])
+        self.assertEqual(
+            expected_creds[3][1:],
+            mock_get_client_manager.mock_calls[3][2]['roles'])
+        self.assertEqual(
+            'system', mock_get_client_manager.mock_calls[3][2]['scope'])
+
     def test_setup_class_overwritten(self):
 
         class OverridesSetup(self.parent_test):
diff --git a/zuul.d/integrated-gate.yaml b/zuul.d/integrated-gate.yaml
index 0a9fb71..4e62d67 100644
--- a/zuul.d/integrated-gate.yaml
+++ b/zuul.d/integrated-gate.yaml
@@ -306,6 +306,12 @@
       subnode:
         devstack_localrc:
           USE_PYTHON3: true
+        devstack_local_conf:
+          post-config:
+            "/$NEUTRON_CORE_PLUGIN_CONF":
+              ovs:
+                bridge_mappings: public:br-ex
+                resource_provider_bandwidths: br-ex:1000000:1000000
 
 - job:
     name: tempest-slow