Merge "Remove hyphen from rand_name calls in scenario tests"
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index 15369de..4fe2e9f 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -84,13 +84,11 @@
 
 To enable and use locking test accounts you need do a few things:
 
- #. Enable the locking test account provider with the
-    locking_credentials_provider option in the auth section
  #. Create a accounts.yaml file which contains the set of pre-existing
     credentials to use for testing. To make sure you don't have a credentials
     starvation issue when running in parallel make sure you have at least 2
-    times the number of parallel workers you are using to execute tempest
-    available in the file.
+    times the number of worker processes you are using to execute tempest
+    available in the file. (if running serially the worker count is 1)
 
     You can check the sample file packaged in tempest for the yaml format
  #. Provide tempest with the location of you accounts.yaml file with the
@@ -125,15 +123,3 @@
 is that if a test requires specific roles on accounts these tests can not be
 run. This is because the config options do not give sufficient flexibility to
 describe the roles assigned to a user for running the tests.
-
-You also can use the accounts.yaml file to specify the credentials used for
-testing. This will just allocate them serially so you only need to provide
-a pair of credentials. Do note that all the restrictions associated with
-locking test accounts applies to using the accounts.yaml file this way too,
-except since you can't run in parallel only 2 of each type of credential is
-required to run. However, the limitation on tests which require specific roles
-does not apply here.
-
-The procedure for doing this is very similar to with the locking accounts
-provider just don't set the locking_credentials_provider to true and you
-only should need a single pair of credentials.
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index f5e0cf8..175f0d9 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -94,8 +94,12 @@
 #
 
 # Path to the yaml file that contains the list of credentials to use
-# for running tests (string value)
-#test_accounts_file = etc/accounts.yaml
+# for running tests. If used when running in parallel you have to make
+# sure sufficient credentials are provided in the accounts file. For
+# example if no tests with roles are being run it requires at least `2
+# * CONC` distinct accounts configured in  the `test_accounts_file`,
+# with CONC == the number of concurrent test processes. (string value)
+#test_accounts_file = <None>
 
 # Allows test cases to create/destroy tenants and users. This option
 # requires that OpenStack Identity API admin credentials are known. If
@@ -105,14 +109,6 @@
 # Deprecated group/name - [orchestration]/allow_tenant_isolation
 #allow_tenant_isolation = true
 
-# If set to True it enables the Accounts provider, which locks
-# credentials to allow for parallel execution with pre-provisioned
-# accounts. It can only be used to run tests that ensure credentials
-# cleanup happens. It requires at least `2 * CONC` distinct accounts
-# configured in `test_accounts_file`, with CONC == the number of
-# concurrent test processes. (boolean value)
-#locking_credentials_provider = false
-
 # Roles to assign to all users created by tempest (list value)
 #tempest_roles =
 
@@ -395,7 +391,8 @@
 #block_migration_for_live_migration = false
 
 # Does the test environment block migration support cinder iSCSI
-# volumes (boolean value)
+# volumes. Note, libvirt doesn't support this, see
+# https://bugs.launchpad.net/nova/+bug/1398999 (boolean value)
 #block_migrate_cinder_iscsi = false
 
 # Enable VNC console. This configuration value should be same as
@@ -670,7 +667,7 @@
 #non_ssh_image_regex = ^.*[Ww]in.*$
 
 # List of user mapped to regex to matching image names. (string value)
-#ssh_user_regex = [["^.*[Cc]irros.*$", "root"]]
+#ssh_user_regex = [["^.*[Cc]irros.*$", "cirros"]]
 
 
 [messaging]
diff --git a/tempest/api/compute/test_live_block_migration.py b/tempest/api/compute/admin/test_live_migration.py
similarity index 100%
rename from tempest/api/compute/test_live_block_migration.py
rename to tempest/api/compute/admin/test_live_migration.py
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index c6d379c..5af9187 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -96,3 +96,15 @@
         self.assertEqual(d_name, domain['name'])
         self.assertFalse(domain['enabled'])
         self.assertEqual(d_desc, domain['description'])
+
+    @test.attr(type='smoke')
+    @test.idempotent_id('2abf8764-309a-4fa9-bc58-201b799817ad')
+    def test_create_domain_without_description(self):
+        # Create domain only with name
+        d_name = data_utils.rand_name('domain-')
+        domain = self.client.create_domain(d_name)
+        self.addCleanup(self._delete_domain, domain['id'])
+        self.assertIn('id', domain)
+        expected_data = {'name': d_name, 'enabled': True}
+        self.assertIsNone(domain['description'])
+        self.assertDictContainsSubset(expected_data, domain)
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index ad121b0..cf0b5e3 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -18,8 +18,16 @@
 from tempest import exceptions
 from tempest import test
 
+AGENT_TYPE = 'L3 agent'
+AGENT_MODES = (
+    'legacy',
+    'dvr_snat'
+)
+
 
 class L3AgentSchedulerTestJSON(base.BaseAdminNetworkTest):
+    _agent_mode = 'legacy'
+
     """
     Tests the following operations in the Neutron API using the REST client for
     Neutron:
@@ -46,12 +54,17 @@
         body = cls.admin_client.list_agents()
         agents = body['agents']
         for agent in agents:
-            if agent['agent_type'] == 'L3 agent':
+            # TODO(armax): falling back on default _agent_mode can be
+            # dropped as soon as Icehouse is dropped.
+            agent_mode = (
+                agent['configurations'].get('agent_mode', cls._agent_mode))
+            if agent['agent_type'] == AGENT_TYPE and agent_mode in AGENT_MODES:
                 cls.agent = agent
                 break
         else:
             msg = "L3 Agent Scheduler enabled in conf, but L3 Agent not found"
             raise exceptions.InvalidConfiguration(msg)
+        cls.router = cls.create_router(data_utils.rand_name('router'))
 
     @test.attr(type='smoke')
     @test.idempotent_id('b7ce6e89-e837-4ded-9b78-9ed3c9c6a45a')
@@ -62,22 +75,18 @@
     @test.idempotent_id('9464e5e7-8625-49c3-8fd1-89c52be59d66')
     def test_add_list_remove_router_on_l3_agent(self):
         l3_agent_ids = list()
-        name = data_utils.rand_name('router1-')
-        router = self.client.create_router(name)
-        self.addCleanup(self.client.delete_router, router['router']['id'])
         self.admin_client.add_router_to_l3_agent(
             self.agent['id'],
-            router['router']['id'])
-        body = self.admin_client.list_l3_agents_hosting_router(
-            router['router']['id'])
+            self.router['id'])
+        body = (
+            self.admin_client.list_l3_agents_hosting_router(self.router['id']))
         for agent in body['agents']:
             l3_agent_ids.append(agent['id'])
             self.assertIn('agent_type', agent)
             self.assertEqual('L3 agent', agent['agent_type'])
         self.assertIn(self.agent['id'], l3_agent_ids)
-        del l3_agent_ids[:]
         body = self.admin_client.remove_router_from_l3_agent(
             self.agent['id'],
-            router['router']['id'])
+            self.router['id'])
         # NOTE(afazekas): The deletion not asserted, because neutron
         # is not forbidden to reschedule the router to the same agent
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 09a5555..26a31cb 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -263,7 +263,8 @@
 
     @classmethod
     def create_router(cls, router_name=None, admin_state_up=False,
-                      external_network_id=None, enable_snat=None):
+                      external_network_id=None, enable_snat=None,
+                      **kwargs):
         ext_gw_info = {}
         if external_network_id:
             ext_gw_info['network_id'] = external_network_id
@@ -271,7 +272,7 @@
             ext_gw_info['enable_snat'] = enable_snat
         body = cls.client.create_router(
             router_name, external_gateway_info=ext_gw_info,
-            admin_state_up=admin_state_up)
+            admin_state_up=admin_state_up, **kwargs)
         router = body['router']
         cls.routers.append(router)
         return router
diff --git a/tempest/api/network/base_routers.py b/tempest/api/network/base_routers.py
index aa4e200..739e6f9 100644
--- a/tempest/api/network/base_routers.py
+++ b/tempest/api/network/base_routers.py
@@ -21,8 +21,21 @@
     # as some router operations, such as enabling or disabling SNAT
     # require admin credentials by default
 
-    def _delete_router(self, router_id):
-        self.client.delete_router(router_id)
+    def _cleanup_router(self, router):
+        self.delete_router(router)
+        self.routers.remove(router)
+
+    def _create_router(self, name, admin_state_up=False,
+                       external_network_id=None, enable_snat=None):
+        # associate a cleanup with created routers to avoid quota limits
+        router = self.create_router(name, admin_state_up,
+                                    external_network_id, enable_snat)
+        self.addCleanup(self._cleanup_router, router)
+        return router
+
+    def _delete_router(self, router_id, network_client=None):
+        client = network_client or self.client
+        client.delete_router(router_id)
         # Asserting that the router is not found in the list
         # after deletion
         list_body = self.client.list_routers()
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index c6f3849..7c0ab7f 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -44,18 +44,6 @@
                            if cls._ip_version == 4 else
                            CONF.network.tenant_network_v6_cidr)
 
-    def _cleanup_router(self, router):
-        self.delete_router(router)
-        self.routers.remove(router)
-
-    def _create_router(self, name, admin_state_up=False,
-                       external_network_id=None, enable_snat=None):
-        # associate a cleanup with created routers to avoid quota limits
-        router = self.create_router(name, admin_state_up,
-                                    external_network_id, enable_snat)
-        self.addCleanup(self._cleanup_router, router)
-        return router
-
     @test.attr(type='smoke')
     @test.idempotent_id('f64403e2-8483-4b34-8ccd-b09a87bcc68c')
     def test_create_show_list_update_delete_router(self):
@@ -363,3 +351,37 @@
 
 class RoutersIpV6Test(RoutersTest):
     _ip_version = 6
+
+
+class DvrRoutersTest(base.BaseRouterTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(DvrRoutersTest, cls).skip_checks()
+        if not test.is_extension_enabled('dvr', 'network'):
+            msg = "DVR extension not enabled."
+            raise cls.skipException(msg)
+
+    @test.attr(type='smoke')
+    @test.idempotent_id('141297aa-3424-455d-aa8d-f2d95731e00a')
+    def test_create_distributed_router(self):
+        name = data_utils.rand_name('router')
+        create_body = self.admin_client.create_router(
+            name, distributed=True)
+        self.addCleanup(self._delete_router,
+                        create_body['router']['id'],
+                        self.admin_client)
+        self.assertTrue(create_body['router']['distributed'])
+
+    @test.attr(type='smoke')
+    @test.idempotent_id('644d7a4a-01a1-4b68-bb8d-0c0042cb1729')
+    def test_convert_centralized_router(self):
+        router = self._create_router(data_utils.rand_name('router'))
+        self.assertNotIn('distributed', router)
+        update_body = self.admin_client.update_router(router['id'],
+                                                      distributed=True)
+        self.assertTrue(update_body['router']['distributed'])
+        show_body = self.admin_client.show_router(router['id'])
+        self.assertTrue(show_body['router']['distributed'])
+        show_body = self.client.show_router(router['id'])
+        self.assertNotIn('distributed', show_body['router'])
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index ae17222..4149be3 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -114,3 +114,28 @@
 
 class RoutersNegativeIpV6Test(RoutersNegativeTest):
     _ip_version = 6
+
+
+class DvrRoutersNegativeTest(base.BaseRouterTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(DvrRoutersNegativeTest, cls).skip_checks()
+        if not test.is_extension_enabled('dvr', 'network'):
+            msg = "DVR extension not enabled."
+            raise cls.skipException(msg)
+
+    @classmethod
+    def resource_setup(cls):
+        super(DvrRoutersNegativeTest, cls).resource_setup()
+        cls.router = cls.create_router(data_utils.rand_name('router'))
+        cls.network = cls.create_network()
+        cls.subnet = cls.create_subnet(cls.network)
+
+    @test.attr(type=['negative', 'smoke'])
+    @test.idempotent_id('4990b055-8fc7-48ab-bba7-aa28beaad0b9')
+    def test_router_create_tenant_distributed_returns_forbidden(self):
+        self.assertRaises(lib_exc.Forbidden,
+                          self.create_router,
+                          data_utils.rand_name('router'),
+                          distributed=True)
diff --git a/tempest/api_schema/response/compute/availability_zone.py b/tempest/api_schema/response/compute/availability_zone.py
deleted file mode 100644
index ab3e2ea..0000000
--- a/tempest/api_schema/response/compute/availability_zone.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2014 NEC Corporation.  All rights reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-# NOTE: This is the detail information for "get az detail" API.
-# The information is the same between v2 and v3 APIs.
-detail = {
-    'type': 'object',
-    'patternProperties': {
-        # NOTE: Here is for a hostname
-        '^[a-zA-Z0-9-_.]+$': {
-            'type': 'object',
-            'patternProperties': {
-                # NOTE: Here is for a service name
-                '^.*$': {
-                    'type': 'object',
-                    'properties': {
-                        'available': {'type': 'boolean'},
-                        'active': {'type': 'boolean'},
-                        'updated_at': {'type': ['string', 'null']}
-                    },
-                    'required': ['available', 'active', 'updated_at']
-                }
-            }
-        }
-    }
-}
diff --git a/tempest/api_schema/response/compute/v2_1/availability_zone.py b/tempest/api_schema/response/compute/v2_1/availability_zone.py
index e261d3d..5c1224e 100644
--- a/tempest/api_schema/response/compute/v2_1/availability_zone.py
+++ b/tempest/api_schema/response/compute/v2_1/availability_zone.py
@@ -14,8 +14,6 @@
 
 import copy
 
-from tempest.api_schema.response.compute import availability_zone as common
-
 
 base = {
     'status_code': [200],
@@ -47,8 +45,30 @@
     }
 }
 
-get_availability_zone_list = copy.deepcopy(base)
+detail = {
+    'type': 'object',
+    'patternProperties': {
+        # NOTE: Here is for a hostname
+        '^[a-zA-Z0-9-_.]+$': {
+            'type': 'object',
+            'patternProperties': {
+                # NOTE: Here is for a service name
+                '^.*$': {
+                    'type': 'object',
+                    'properties': {
+                        'available': {'type': 'boolean'},
+                        'active': {'type': 'boolean'},
+                        'updated_at': {'type': ['string', 'null']}
+                    },
+                    'required': ['available', 'active', 'updated_at']
+                }
+            }
+        }
+    }
+}
 
-get_availability_zone_list_detail = copy.deepcopy(base)
-get_availability_zone_list_detail['response_body']['properties'][
-    'availabilityZoneInfo']['items']['properties']['hosts'] = common.detail
+list_availability_zone_list = copy.deepcopy(base)
+
+list_availability_zone_list_detail = copy.deepcopy(base)
+list_availability_zone_list_detail['response_body']['properties'][
+    'availabilityZoneInfo']['items']['properties']['hosts'] = detail
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index e970249..05aaabe 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -992,9 +992,13 @@
         add_router_interface(RES['routers'])
 
     create_secgroups(RES['secgroups'])
-    create_servers(RES['servers'])
     create_volumes(RES['volumes'])
-    attach_volumes(RES['volumes'])
+
+    # Only attempt attaching the volumes if servers are defined in the
+    # resourcefile
+    if 'servers' in RES:
+        create_servers(RES['servers'])
+        attach_volumes(RES['volumes'])
 
 
 def destroy_resources():
diff --git a/tempest/common/accounts.py b/tempest/common/accounts.py
index 8e9a018..6d376d6 100644
--- a/tempest/common/accounts.py
+++ b/tempest/common/accounts.py
@@ -38,7 +38,8 @@
     def __init__(self, identity_version=None, name=None):
         super(Accounts, self).__init__(identity_version=identity_version,
                                        name=name)
-        if os.path.isfile(CONF.auth.test_accounts_file):
+        if (CONF.auth.test_accounts_file and
+                os.path.isfile(CONF.auth.test_accounts_file)):
             accounts = read_accounts_yaml(CONF.auth.test_accounts_file)
             self.use_default_creds = False
         else:
@@ -261,18 +262,14 @@
 
     def _unique_creds(self, cred_arg=None):
         """Verify that the configured credentials are valid and distinct """
-        if self.use_default_creds:
-            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)
-        else:
-            # TODO(andreaf) Add a uniqueness check here
-            return len(self.hash_dict['creds']) > 1
+        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')
@@ -280,42 +277,20 @@
     def is_multi_tenant(self):
         return self._unique_creds('tenant_id')
 
-    def get_creds(self, id, roles=None):
-        try:
-            hashes = self._get_match_hash_list(roles)
-            # No need to sort the dict as within the same python process
-            # the HASH seed won't change, so subsequent calls to keys()
-            # will return the same result
-            _hash = hashes[id]
-        except IndexError:
-            msg = 'Insufficient number of users provided'
-            raise exceptions.InvalidConfiguration(msg)
-        return self.hash_dict['creds'][_hash]
-
     def get_primary_creds(self):
         if self.isolated_creds.get('primary'):
             return self.isolated_creds.get('primary')
-        if not self.use_default_creds:
-            creds = self.get_creds(0)
-            primary_credential = cred_provider.get_credentials(
-                identity_version=self.identity_version, **creds)
-        else:
-            primary_credential = cred_provider.get_configured_credentials(
-                credential_type='user', identity_version=self.identity_version)
+        primary_credential = cred_provider.get_configured_credentials(
+            credential_type='user', identity_version=self.identity_version)
         self.isolated_creds['primary'] = primary_credential
         return primary_credential
 
     def get_alt_creds(self):
         if self.isolated_creds.get('alt'):
             return self.isolated_creds.get('alt')
-        if not self.use_default_creds:
-            creds = self.get_creds(1)
-            alt_credential = cred_provider.get_credentials(
-                identity_version=self.identity_version, **creds)
-        else:
-            alt_credential = cred_provider.get_configured_credentials(
-                credential_type='alt_user',
-                identity_version=self.identity_version)
+        alt_credential = cred_provider.get_configured_credentials(
+            credential_type='alt_user',
+            identity_version=self.identity_version)
         self.isolated_creds['alt'] = alt_credential
         return alt_credential
 
@@ -323,35 +298,14 @@
         self.isolated_creds = {}
 
     def get_admin_creds(self):
-        if not self.use_default_creds:
-            return self.get_creds_by_roles([CONF.identity.admin_role])
-        else:
-            creds = cred_provider.get_configured_credentials(
-                "identity_admin", fill_in=False)
-            self.isolated_creds['admin'] = creds
-            return creds
+        creds = cred_provider.get_configured_credentials(
+            "identity_admin", fill_in=False)
+        self.isolated_creds['admin'] = creds
+        return creds
 
     def get_creds_by_roles(self, roles, force_new=False):
-        roles = list(set(roles))
-        exist_creds = self.isolated_creds.get(str(roles), None)
-        index = 0
-        if exist_creds and not force_new:
-            return exist_creds
-        elif exist_creds and force_new:
-            new_index = str(roles) + '-' + str(len(self.isolated_creds))
-            self.isolated_creds[new_index] = exist_creds
-            # Figure out how many existing creds for this roles set are present
-            # use this as the index the returning hash list to ensure separate
-            # creds are returned with force_new being True
-            for creds_names in self.isolated_creds:
-                if str(roles) in creds_names:
-                    index = index + 1
-        if not self.use_default_creds:
-            creds = self.get_creds(index, roles=roles)
-            role_credential = cred_provider.get_credentials(**creds)
-            self.isolated_creds[str(roles)] = role_credential
-        else:
-            msg = "Default credentials can not be used with specifying "\
-                  "credentials by roles"
-            raise exceptions.InvalidConfiguration(msg)
-        return role_credential
+        msg = "Credentials being specified through the config file can not be"\
+              " used with tests that specify using credentials by roles. "\
+              "Either exclude/skip the tests doing this or use either an "\
+              "test_accounts_file or tenant isolation."
+        raise exceptions.InvalidConfiguration(msg)
diff --git a/tempest/common/credentials.py b/tempest/common/credentials.py
index 1ca0128..c34df48 100644
--- a/tempest/common/credentials.py
+++ b/tempest/common/credentials.py
@@ -38,7 +38,8 @@
             network_resources=network_resources,
             identity_version=identity_version)
     else:
-        if CONF.auth.locking_credentials_provider:
+        if (CONF.auth.test_accounts_file and
+                os.path.isfile(CONF.auth.test_accounts_file)):
             # Most params are not relevant for pre-created accounts
             return accounts.Accounts(name=name,
                                      identity_version=identity_version)
@@ -56,7 +57,8 @@
     if CONF.auth.allow_tenant_isolation:
         return is_admin
     # Check whether test accounts file has the admin specified or not
-    elif os.path.isfile(CONF.auth.test_accounts_file):
+    elif (CONF.auth.test_accounts_file and
+            os.path.isfile(CONF.auth.test_accounts_file)):
         check_accounts = accounts.Accounts(name='check_admin')
         if not check_accounts.admin_available():
             is_admin = False
diff --git a/tempest/common/fixed_network.py b/tempest/common/fixed_network.py
index b06ddf2..b533898 100644
--- a/tempest/common/fixed_network.py
+++ b/tempest/common/fixed_network.py
@@ -15,6 +15,7 @@
 
 from tempest_lib import exceptions as lib_exc
 
+from tempest.common import isolated_creds
 from tempest import config
 from tempest import exceptions
 
@@ -38,7 +39,7 @@
     network = None
     # NOTE(andreaf) get_primary_network will always be available once
     # bp test-accounts-continued is implemented
-    if (CONF.auth.allow_tenant_isolation and
+    if (isinstance(creds_provider, isolated_creds.IsolatedCreds) and
         (CONF.service_available.neutron and
          not CONF.service_available.ironic)):
         network = creds_provider.get_primary_network()
diff --git a/tempest/config.py b/tempest/config.py
index f884baa..3725f58 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -23,6 +23,13 @@
 from oslo_log import log as logging
 
 
+# TODO(marun) Replace use of oslo_config's global ConfigOpts
+# (cfg.CONF) instance with a local instance (cfg.ConfigOpts()) once
+# the cli tests move to the clients.  The cli tests rely on oslo
+# incubator modules that use the global cfg.CONF.
+_CONF = cfg.CONF
+
+
 def register_opt_group(conf, opt_group, options):
     conf.register_group(opt_group)
     for opt in options:
@@ -35,9 +42,14 @@
 
 AuthGroup = [
     cfg.StrOpt('test_accounts_file',
-               default='etc/accounts.yaml',
                help="Path to the yaml file that contains the list of "
-                    "credentials to use for running tests"),
+                    "credentials to use for running tests. If used when "
+                    "running in parallel you have to make sure sufficient "
+                    "credentials are provided in the accounts file. For "
+                    "example if no tests with roles are being run it requires "
+                    "at least `2 * CONC` distinct accounts configured in "
+                    " the `test_accounts_file`, with CONC == the "
+                    "number of concurrent test processes."),
     cfg.BoolOpt('allow_tenant_isolation',
                 default=True,
                 help="Allows test cases to create/destroy tenants and "
@@ -49,15 +61,6 @@
                                                    group='compute'),
                                  cfg.DeprecatedOpt('allow_tenant_isolation',
                                                    group='orchestration')]),
-    cfg.BoolOpt('locking_credentials_provider',
-                default=False,
-                help="If set to True it enables the Accounts provider, "
-                     "which locks credentials to allow for parallel execution "
-                     "with pre-provisioned accounts. It can only be used to "
-                     "run tests that ensure credentials cleanup happens. "
-                     "It requires at least `2 * CONC` distinct accounts "
-                     "configured in `test_accounts_file`, with CONC == the "
-                     "number of concurrent test processes."),
     cfg.ListOpt('tempest_roles',
                 help="Roles to assign to all users created by tempest",
                 default=[]),
@@ -327,7 +330,8 @@
     cfg.BoolOpt('block_migrate_cinder_iscsi',
                 default=False,
                 help="Does the test environment block migration support "
-                     "cinder iSCSI volumes"),
+                "cinder iSCSI volumes. Note, libvirt doesn't support this, "
+                "see https://bugs.launchpad.net/nova/+bug/1398999"),
     cfg.BoolOpt('vnc_console',
                 default=False,
                 help='Enable VNC console. This configuration value should '
@@ -998,7 +1002,7 @@
                help="SSH verification in tests is skipped"
                     "for matching images"),
     cfg.StrOpt('ssh_user_regex',
-               default="[[\"^.*[Cc]irros.*$\", \"root\"]]",
+               default="[[\"^.*[Cc]irros.*$\", \"cirros\"]]",
                help="List of user mapped to regex "
                     "to matching image names."),
 ]
@@ -1108,7 +1112,7 @@
 
 def register_opts():
     for g, o in _opts:
-        register_opt_group(cfg.CONF, g, o)
+        register_opt_group(_CONF, g, o)
 
 
 def list_opts():
@@ -1132,45 +1136,44 @@
 
     def __getattr__(self, attr):
         # Handles config options from the default group
-        return getattr(cfg.CONF, attr)
+        return getattr(_CONF, attr)
 
     def _set_attrs(self):
-        self.auth = cfg.CONF.auth
-        self.compute = cfg.CONF.compute
-        self.compute_feature_enabled = cfg.CONF['compute-feature-enabled']
-        self.identity = cfg.CONF.identity
-        self.identity_feature_enabled = cfg.CONF['identity-feature-enabled']
-        self.image = cfg.CONF.image
-        self.image_feature_enabled = cfg.CONF['image-feature-enabled']
-        self.network = cfg.CONF.network
-        self.network_feature_enabled = cfg.CONF['network-feature-enabled']
-        self.volume = cfg.CONF.volume
-        self.volume_feature_enabled = cfg.CONF['volume-feature-enabled']
-        self.object_storage = cfg.CONF['object-storage']
-        self.object_storage_feature_enabled = cfg.CONF[
+        self.auth = _CONF.auth
+        self.compute = _CONF.compute
+        self.compute_feature_enabled = _CONF['compute-feature-enabled']
+        self.identity = _CONF.identity
+        self.identity_feature_enabled = _CONF['identity-feature-enabled']
+        self.image = _CONF.image
+        self.image_feature_enabled = _CONF['image-feature-enabled']
+        self.network = _CONF.network
+        self.network_feature_enabled = _CONF['network-feature-enabled']
+        self.volume = _CONF.volume
+        self.volume_feature_enabled = _CONF['volume-feature-enabled']
+        self.object_storage = _CONF['object-storage']
+        self.object_storage_feature_enabled = _CONF[
             'object-storage-feature-enabled']
-        self.database = cfg.CONF.database
-        self.orchestration = cfg.CONF.orchestration
-        self.messaging = cfg.CONF.messaging
-        self.telemetry = cfg.CONF.telemetry
-        self.dashboard = cfg.CONF.dashboard
-        self.data_processing = cfg.CONF.data_processing
-        self.data_processing_feature_enabled = cfg.CONF[
+        self.database = _CONF.database
+        self.orchestration = _CONF.orchestration
+        self.messaging = _CONF.messaging
+        self.telemetry = _CONF.telemetry
+        self.dashboard = _CONF.dashboard
+        self.data_processing = _CONF.data_processing
+        self.data_processing_feature_enabled = _CONF[
             'data_processing-feature-enabled']
-        self.boto = cfg.CONF.boto
-        self.stress = cfg.CONF.stress
-        self.scenario = cfg.CONF.scenario
-        self.service_available = cfg.CONF.service_available
-        self.debug = cfg.CONF.debug
-        self.baremetal = cfg.CONF.baremetal
-        self.input_scenario = cfg.CONF['input-scenario']
-        self.cli = cfg.CONF.cli
-        self.negative = cfg.CONF.negative
-        cfg.CONF.set_default('domain_name', self.identity.admin_domain_name,
-                             group='identity')
-        cfg.CONF.set_default('alt_domain_name',
-                             self.identity.admin_domain_name,
-                             group='identity')
+        self.boto = _CONF.boto
+        self.stress = _CONF.stress
+        self.scenario = _CONF.scenario
+        self.service_available = _CONF.service_available
+        self.debug = _CONF.debug
+        self.baremetal = _CONF.baremetal
+        self.input_scenario = _CONF['input-scenario']
+        self.cli = _CONF.cli
+        self.negative = _CONF.negative
+        _CONF.set_default('domain_name', self.identity.admin_domain_name,
+                          group='identity')
+        _CONF.set_default('alt_domain_name', self.identity.admin_domain_name,
+                          group='identity')
 
     def __init__(self, parse_conf=True, config_path=None):
         """Initialize a configuration from a conf directory and conf file."""
@@ -1196,18 +1199,18 @@
         # to remove an issue with the config file up to date checker.
         if parse_conf:
             config_files.append(path)
-        logging.register_options(cfg.CONF)
+        logging.register_options(_CONF)
         if os.path.isfile(path):
-            cfg.CONF([], project='tempest', default_config_files=config_files)
+            _CONF([], project='tempest', default_config_files=config_files)
         else:
-            cfg.CONF([], project='tempest')
-        logging.setup(cfg.CONF, 'tempest')
+            _CONF([], project='tempest')
+        logging.setup(_CONF, 'tempest')
         LOG = logging.getLogger('tempest')
         LOG.info("Using tempest config file %s" % path)
         register_opts()
         self._set_attrs()
         if parse_conf:
-            cfg.CONF.log_opt_values(LOG, std_logging.DEBUG)
+            _CONF.log_opt_values(LOG, std_logging.DEBUG)
 
 
 class TempestConfigProxy(object):
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index ebdebcf..ce640b1 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -680,6 +680,8 @@
 
     def _get_network_by_name(self, network_name):
         net = self._list_networks(name=network_name)
+        self.assertNotEqual(len(net), 0,
+                            "Unable to get network by name: %s" % network_name)
         return net_resources.AttributeDict(net[0])
 
     def create_floating_ip(self, thing, external_network_id=None,
@@ -1049,6 +1051,9 @@
             # not (the current baremetal case). Likely can be removed when
             # test account mgmt is reworked:
             # https://blueprints.launchpad.net/tempest/+spec/test-accounts
+            if not CONF.compute.fixed_network_name:
+                m = 'fixed_network_name must be specified in config'
+                raise exceptions.InvalidConfiguration(m)
             network = self._get_network_by_name(
                 CONF.compute.fixed_network_name)
             router = None
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 3e259b0..8fa2df5 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -12,7 +12,6 @@
 
 from oslo_log import log
 from tempest_lib.common.utils import data_utils
-from tempest_lib import decorators
 
 from tempest import config
 from tempest.scenario import manager
@@ -132,7 +131,6 @@
         actual = self._get_content(ssh_client)
         self.assertEqual(expected, actual)
 
-    @decorators.skip_because(bug='1373513')
     @test.idempotent_id('557cd2c2-4eb8-4dce-98be-f86765ff311b')
     @test.services('compute', 'volume', 'image')
     def test_volume_boot_pattern(self):
@@ -176,7 +174,6 @@
         # NOTE(gfidente): ensure resources are in clean state for
         # deletion operations to succeed
         self._stop_instances([instance_2nd, instance_from_snapshot])
-        self._detach_volumes([volume_origin, volume])
 
 
 class TestVolumeBootPatternV2(TestVolumeBootPattern):
diff --git a/tempest/services/compute/json/availability_zone_client.py b/tempest/services/compute/json/availability_zone_client.py
index b541a2c..6c50398 100644
--- a/tempest/services/compute/json/availability_zone_client.py
+++ b/tempest/services/compute/json/availability_zone_client.py
@@ -25,14 +25,14 @@
     def get_availability_zone_list(self):
         resp, body = self.get('os-availability-zone')
         body = json.loads(body)
-        self.validate_response(schema.get_availability_zone_list, resp, body)
+        self.validate_response(schema.list_availability_zone_list, resp, body)
         return service_client.ResponseBodyList(resp,
                                                body['availabilityZoneInfo'])
 
     def get_availability_zone_list_detail(self):
         resp, body = self.get('os-availability-zone/detail')
         body = json.loads(body)
-        self.validate_response(schema.get_availability_zone_list_detail, resp,
+        self.validate_response(schema.list_availability_zone_list_detail, resp,
                                body)
         return service_client.ResponseBodyList(resp,
                                                body['availabilityZoneInfo'])
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index e84d627..62e60d6 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -23,7 +23,7 @@
 from tempest_lib.common.utils import data_utils
 
 from tempest import clients
-from tempest.common import cred_provider
+from tempest.common import isolated_creds
 from tempest.common import ssh
 from tempest import config
 from tempest import exceptions
@@ -149,15 +149,22 @@
                 username = data_utils.rand_name("stress_user")
                 tenant_name = data_utils.rand_name("stress_tenant")
                 password = "pass"
-                identity_client = admin_manager.identity_client
-                tenant = identity_client.create_tenant(name=tenant_name)
-                identity_client.create_user(username,
-                                            password,
-                                            tenant['id'],
-                                            "email")
-                creds = cred_provider.get_credentials(username=username,
-                                                      password=password,
-                                                      tenant_name=tenant_name)
+                if CONF.identity.auth_version == 'v2':
+                    identity_client = admin_manager.identity_client
+                else:
+                    identity_client = admin_manager.identity_v3_client
+                credentials_client = isolated_creds.get_creds_client(
+                    identity_client)
+                project = credentials_client.create_project(
+                    name=tenant_name, description=tenant_name)
+                user = credentials_client.create_user(username, password,
+                                                      project['id'], "email")
+                # Add roles specified in config file
+                for conf_role in CONF.auth.tempest_roles:
+                    credentials_client.assign_user_role(user, project,
+                                                        conf_role)
+                creds = credentials_client.get_credentials(user, project,
+                                                           password)
                 manager = clients.Manager(credentials=creds)
 
             test_obj = importutils.import_class(test['action'])
diff --git a/tempest/tests/common/test_accounts.py b/tempest/tests/common/test_accounts.py
index 2a98a06..6371e49 100644
--- a/tempest/tests/common/test_accounts.py
+++ b/tempest/tests/common/test_accounts.py
@@ -67,7 +67,7 @@
         self.useFixture(mockpatch.Patch(
             'tempest.common.accounts.read_accounts_yaml',
             return_value=self.test_accounts))
-        cfg.CONF.set_default('test_accounts_file', '', group='auth')
+        cfg.CONF.set_default('test_accounts_file', 'fake_path', group='auth')
         self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
 
     def _get_hash_list(self, accounts_list):
@@ -297,12 +297,8 @@
         cfg.CONF.set_default('test_accounts_file', '', group='auth')
         self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
 
-    def test_get_creds(self):
+    def test_get_creds_roles_nonlocking_invalid(self):
         test_accounts_class = accounts.NotLockingAccounts('v2', 'test_name')
-        for i in xrange(len(self.test_accounts)):
-            creds = test_accounts_class.get_creds(i)
-            msg = "Empty credentials returned for ID %s" % str(i)
-            self.assertIsNotNone(creds, msg)
         self.assertRaises(exceptions.InvalidConfiguration,
-                          test_accounts_class.get_creds,
-                          id=len(self.test_accounts))
+                          test_accounts_class.get_creds_by_roles,
+                          ['fake_role'])
diff --git a/tempest/tests/common/test_admin_available.py b/tempest/tests/common/test_admin_available.py
new file mode 100644
index 0000000..4e3aa4c
--- /dev/null
+++ b/tempest/tests/common/test_admin_available.py
@@ -0,0 +1,104 @@
+# Copyright 2015 Red Hat, Inc.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from oslo.config import cfg
+from oslotest import mockpatch
+
+from tempest.common import credentials
+from tempest import config
+from tempest.tests import base
+from tempest.tests import fake_config
+
+
+class TestAdminAvailable(base.TestCase):
+
+    def setUp(self):
+        super(TestAdminAvailable, self).setUp()
+        self.useFixture(fake_config.ConfigFixture())
+        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+
+    def run_test(self, tenant_isolation, use_accounts_file, admin_creds):
+
+        cfg.CONF.set_default('allow_tenant_isolation',
+                             tenant_isolation, group='auth')
+        if use_accounts_file:
+            accounts = [{'username': 'u1',
+                         'tenant_name': 't1',
+                         'password': 'p'},
+                        {'username': 'u2',
+                         'tenant_name': 't2',
+                         'password': 'p'}]
+            if admin_creds == 'role':
+                accounts.append({'username': 'admin',
+                                 'tenant_name': 'admin',
+                                 'password': 'p',
+                                 'roles': ['admin']})
+            elif admin_creds == 'type':
+                accounts.append({'username': 'admin',
+                                 'tenant_name': 'admin',
+                                 'password': 'p',
+                                 'types': ['admin']})
+            self.useFixture(mockpatch.Patch(
+                'tempest.common.accounts.read_accounts_yaml',
+                return_value=accounts))
+            cfg.CONF.set_default('test_accounts_file',
+                                 use_accounts_file, group='auth')
+            self.useFixture(mockpatch.Patch('os.path.isfile',
+                                            return_value=True))
+        else:
+            self.useFixture(mockpatch.Patch('os.path.isfile',
+                                            return_value=False))
+            if admin_creds:
+                (u, t, p) = ('u', 't', 'p')
+            else:
+                (u, t, p) = (None, None, None)
+
+            cfg.CONF.set_default('admin_username', u, group='identity')
+            cfg.CONF.set_default('admin_tenant_name', t, group='identity')
+            cfg.CONF.set_default('admin_password', p, group='identity')
+
+        expected = admin_creds is not None or tenant_isolation
+        observed = credentials.is_admin_available()
+        self.assertEqual(expected, observed)
+
+    # Tenant isolation implies admin so only one test case for True
+    def test__tenant_isolation__accounts_file__no_admin(self):
+        self.run_test(tenant_isolation=True,
+                      use_accounts_file=True,
+                      admin_creds=None)
+
+    def test__no_tenant_isolation__accounts_file__no_admin(self):
+        self.run_test(tenant_isolation=False,
+                      use_accounts_file=True,
+                      admin_creds=None)
+
+    def test__no_tenant_isolation__accounts_file__admin_role(self):
+        self.run_test(tenant_isolation=False,
+                      use_accounts_file=True,
+                      admin_creds='role')
+
+    def test__no_tenant_isolation__accounts_file__admin_type(self):
+        self.run_test(tenant_isolation=False,
+                      use_accounts_file=True,
+                      admin_creds='type')
+
+    def test__no_tenant_isolation__no_accounts_file__no_admin(self):
+        self.run_test(tenant_isolation=False,
+                      use_accounts_file=False,
+                      admin_creds=None)
+
+    def test__no_tenant_isolation__no_accounts_file__admin(self):
+        self.run_test(tenant_isolation=False,
+                      use_accounts_file=False,
+                      admin_creds='role')
diff --git a/tools/check_uuid.py b/tools/check_uuid.py
index 34effe4..e21c3d8 100755
--- a/tools/check_uuid.py
+++ b/tools/check_uuid.py
@@ -275,7 +275,7 @@
             if not test_uuid:
                 return
             if test_uuid in uuids:
-                error_str = "%s:%s\n uuid %s collision: %s<->%s\n%s:%s\n" % (
+                error_str = "%s:%s\n uuid %s collision: %s<->%s\n%s:%s" % (
                     tests[module_name]['source_path'],
                     tests[module_name]['tests'][test_name].lineno,
                     test_uuid,
@@ -285,6 +285,8 @@
                     uuids[test_uuid]['test_node'].lineno,
                 )
                 print(error_str)
+                print("cannot automatically resolve the collision, please "
+                      "manually remove the duplicate value on the new test.")
                 return True
             else:
                 uuids[test_uuid] = {