Merge "Add cost time printing in wait_for_volume_resource_status"
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index 573b7d4..307eb07 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -338,4 +338,4 @@
 
  * `3.3`_
 
- .. _3.3:  https://docs.openstack.org/cinder/ocata/devref/api_microversion_history.html#id4
+ .. _3.3:  https://docs.openstack.org/cinder/latest/contributor/api_microversion_history.html#id4
diff --git a/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml b/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml
index 4abfe9e..ca42014 100644
--- a/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml
+++ b/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml
@@ -1,5 +1,7 @@
 ---
 fixes:
-  Add a missing return statement to the retype_volume API in the v2 volumes_client library.
-  This changes the response body from None to an empty dictionary.
+  - |
+    Add a missing return statement to the retype_volume API in the v2
+    volumes_client library: Bug#1703997
 
+    This changes the response body from None to an empty dictionary.
diff --git a/releasenotes/notes/compare-header-version-func-de5139b2161b3627.yaml b/releasenotes/notes/compare-header-version-func-de5139b2161b3627.yaml
new file mode 100644
index 0000000..305e756
--- /dev/null
+++ b/releasenotes/notes/compare-header-version-func-de5139b2161b3627.yaml
@@ -0,0 +1,15 @@
+---
+features:
+  - |
+    Add a new function called ``compare_version_header_to_response`` to
+    ``tempest.lib.common.api_version_utils``, which compares the API
+    micoversion in the response header to another microversion using the
+    comparators defined in
+    ``tempest.lib.common.api_version_request.APIVersionRequest``.
+
+    It is now possible to determine how to retrieve an attribute from a
+    response body of an API call, depending on the returned microversion.
+
+    Add a new exception type called ``InvalidParam`` to
+    ``tempest.lib.exceptions``, allowing the possibility of raising an
+    exception if an invalid parameter is passed to a library function.
diff --git a/releasenotes/notes/identity-tests-domain-drivers-76235f6672221e45.yaml b/releasenotes/notes/identity-tests-domain-drivers-76235f6672221e45.yaml
new file mode 100644
index 0000000..7ed3081
--- /dev/null
+++ b/releasenotes/notes/identity-tests-domain-drivers-76235f6672221e45.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - |
+    A new boolean config option ``domain_specific_drivers``
+    is added to the section ``identity-feature-enabled``.
+    This option must be enabled when testing an environment that
+    is configured to use domain-specific identity drivers.
diff --git a/releasenotes/notes/start-of-pike-support-f2a1b7ea8e8b0311.yaml b/releasenotes/notes/start-of-pike-support-f2a1b7ea8e8b0311.yaml
new file mode 100644
index 0000000..0787821
--- /dev/null
+++ b/releasenotes/notes/start-of-pike-support-f2a1b7ea8e8b0311.yaml
@@ -0,0 +1,11 @@
+---
+prelude: >
+    This release marks the start of support for the Pike release in Tempest.
+other:
+    - OpenStack Releases supported after this release are **Pike**, **Ocata**,
+      and **Newton**.
+
+      The release under current development of this tag is Queens, meaning
+      that every Tempest commit is also tested against master during the Queens
+      cycle. However, this does not necessarily mean that using Tempest as of
+      this tag will work against a Queens (or future release) cloud.
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index db01da0..df1de46 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -6,6 +6,7 @@
     :maxdepth: 1
 
     unreleased
+    v17.0.0
     v16.1.0
     v16.0.0
     v15.0.0
diff --git a/releasenotes/source/v17.0.0.rst b/releasenotes/source/v17.0.0.rst
new file mode 100644
index 0000000..3f50f11
--- /dev/null
+++ b/releasenotes/source/v17.0.0.rst
@@ -0,0 +1,6 @@
+=====================
+v17.0.0 Release Notes
+=====================
+
+.. release-notes:: 17.0.0 Release Notes
+   :version: 17.0.0
diff --git a/requirements.txt b/requirements.txt
index aaecaaa..36b9efa 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,7 +10,7 @@
 testrepository>=0.0.18 # Apache-2.0/BSD
 oslo.concurrency>=3.8.0 # Apache-2.0
 oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
-oslo.log>=3.22.0 # Apache-2.0
+oslo.log>=3.30.0 # Apache-2.0
 oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0
 oslo.utils>=3.20.0 # Apache-2.0
 six>=1.9.0 # MIT
diff --git a/tempest/api/compute/admin/test_auto_allocate_network.py b/tempest/api/compute/admin/test_auto_allocate_network.py
index ea92563..0c80252 100644
--- a/tempest/api/compute/admin/test_auto_allocate_network.py
+++ b/tempest/api/compute/admin/test_auto_allocate_network.py
@@ -16,7 +16,6 @@
 
 from tempest.api.compute import base
 from tempest.common import compute
-from tempest.common import credentials_factory as credentials
 from tempest.common import utils
 from tempest import config
 from tempest.lib.common.utils import test_utils
@@ -46,11 +45,6 @@
     @classmethod
     def skip_checks(cls):
         super(AutoAllocateNetworkTest, cls).skip_checks()
-        identity_version = cls.get_identity_version()
-        if not credentials.is_admin_available(
-                identity_version=identity_version):
-            msg = "Missing Identity Admin API credentials in configuration."
-            raise cls.skipException(msg)
         if not CONF.service_available.neutron:
             raise cls.skipException('Neutron is required')
         if not utils.is_extension_enabled('auto-allocated-topology',
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index 69c8a82..ebba73c 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -29,6 +29,8 @@
         if CONF.service_available.neutron:
             msg = ("%s skipped as neutron is available" % cls.__name__)
             raise cls.skipException(msg)
+        if not utils.get_service_list()['network']:
+            raise cls.skipException("network service not enabled.")
 
     @classmethod
     def setup_clients(cls):
@@ -49,17 +51,14 @@
                 break
 
     @decorators.idempotent_id('16b7d848-2f7c-4709-85a3-2dfb4576cc52')
-    @utils.services('network')
     def test_list_fixed_ip_details(self):
         fixed_ip = self.client.show_fixed_ip(self.ip)
         self.assertEqual(fixed_ip['fixed_ip']['address'], self.ip)
 
     @decorators.idempotent_id('5485077b-7e46-4cec-b402-91dc3173433b')
-    @utils.services('network')
     def test_set_reserve(self):
         self.client.reserve_fixed_ip(self.ip, reserve="None")
 
     @decorators.idempotent_id('7476e322-b9ff-4710-bf82-49d51bac6e2e')
-    @utils.services('network')
     def test_set_unreserve(self):
         self.client.reserve_fixed_ip(self.ip, unreserve="None")
diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py
index c54c866..a5deb3c 100644
--- a/tempest/api/compute/admin/test_fixed_ips_negative.py
+++ b/tempest/api/compute/admin/test_fixed_ips_negative.py
@@ -29,6 +29,8 @@
         if CONF.service_available.neutron:
             msg = ("%s skipped as neutron is available" % cls.__name__)
             raise cls.skipException(msg)
+        if not utils.get_service_list()['network']:
+            raise cls.skipException("network service not enabled.")
 
     @classmethod
     def setup_clients(cls):
@@ -51,14 +53,12 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('9f17f47d-daad-4adc-986e-12370c93e407')
-    @utils.services('network')
     def test_list_fixed_ip_details_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_client.show_fixed_ip, self.ip)
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('ce60042c-fa60-4836-8d43-1c8e3359dc47')
-    @utils.services('network')
     def test_set_reserve_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_client.reserve_fixed_ip,
@@ -66,7 +66,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('f1f7a35b-0390-48c5-9803-5f27461439db')
-    @utils.services('network')
     def test_set_unreserve_with_non_admin_user(self):
         self.assertRaises(lib_exc.Forbidden,
                           self.non_admin_client.reserve_fixed_ip,
@@ -74,7 +73,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('f51cf464-7fc5-4352-bc3e-e75cfa2cb717')
-    @utils.services('network')
     def test_set_reserve_with_invalid_ip(self):
         # NOTE(maurosr): since this exercises the same code snippet, we do it
         # only for reserve action
@@ -87,7 +85,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('fd26ef50-f135-4232-9d32-281aab3f9176')
-    @utils.services('network')
     def test_fixed_ip_with_invalid_action(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.client.reserve_fixed_ip,
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index 4001e26..9ee0ac9 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -32,6 +32,8 @@
     @classmethod
     def skip_checks(cls):
         super(FloatingIPsTestJSON, cls).skip_checks()
+        if not utils.get_service_list()['network']:
+            raise cls.skipException("network service not enabled.")
         if not CONF.network_feature_enabled.floating_ips:
             raise cls.skipException("Floating ips are not available")
 
@@ -62,7 +64,6 @@
         super(FloatingIPsTestJSON, cls).resource_cleanup()
 
     @decorators.idempotent_id('f7bfb946-297e-41b8-9e8c-aba8e9bb5194')
-    @utils.services('network')
     def test_allocate_floating_ip(self):
         # Positive test:Allocation of a new floating IP to a project
         # should be successful
@@ -78,7 +79,6 @@
         self.assertIn(floating_ip_details, body)
 
     @decorators.idempotent_id('de45e989-b5ca-4a9b-916b-04a52e7bbb8b')
-    @utils.services('network')
     def test_delete_floating_ip(self):
         # Positive test:Deletion of valid floating IP from project
         # should be successful
@@ -93,7 +93,6 @@
         self.client.wait_for_resource_deletion(floating_ip_body['id'])
 
     @decorators.idempotent_id('307efa27-dc6f-48a0-8cd2-162ce3ef0b52')
-    @utils.services('network')
     @testtools.skipUnless(CONF.network.public_network_id,
                           'The public_network_id option must be specified.')
     def test_associate_disassociate_floating_ip(self):
@@ -116,7 +115,6 @@
             self.server_id)
 
     @decorators.idempotent_id('6edef4b2-aaf1-4abc-bbe3-993e2561e0fe')
-    @utils.services('network')
     @testtools.skipUnless(CONF.network.public_network_id,
                           'The public_network_id option must be specified.')
     def test_associate_already_associated_floating_ip(self):
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
index 3455a81..c3d7816 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
@@ -30,6 +30,8 @@
     @classmethod
     def skip_checks(cls):
         super(FloatingIPsNegativeTestJSON, cls).skip_checks()
+        if not utils.get_service_list()['network']:
+            raise cls.skipException("network service not enabled.")
         if not CONF.network_feature_enabled.floating_ips:
             raise cls.skipException("Floating ips are not available")
 
@@ -58,7 +60,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('6e0f059b-e4dd-48fb-8207-06e3bba5b074')
-    @utils.services('network')
     def test_allocate_floating_ip_from_nonexistent_pool(self):
         # Negative test:Allocation of a new floating IP from a nonexistent_pool
         # to a project should fail
@@ -68,7 +69,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('ae1c55a8-552b-44d4-bfb6-2a115a15d0ba')
-    @utils.services('network')
     def test_delete_nonexistent_floating_ip(self):
         # Negative test:Deletion of a nonexistent floating IP
         # from project should fail
@@ -79,7 +79,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('595fa616-1a71-4670-9614-46564ac49a4c')
-    @utils.services('network')
     def test_associate_nonexistent_floating_ip(self):
         # Negative test:Association of a non existent floating IP
         # to specific server should fail
@@ -90,7 +89,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('0a081a66-e568-4e6b-aa62-9587a876dca8')
-    @utils.services('network')
     def test_dissociate_nonexistent_floating_ip(self):
         # Negative test:Dissociation of a non existent floating IP should fail
         # Dissociating non existent floating IP
@@ -100,7 +98,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('804b4fcb-bbf5-412f-925d-896672b61eb3')
-    @utils.services('network')
     def test_associate_ip_to_server_without_passing_floating_ip(self):
         # Negative test:Association of empty floating IP to specific server
         # should raise NotFound or BadRequest(In case of Nova V2.1) exception.
@@ -110,7 +107,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('58a80596-ffb2-11e6-9393-fa163e4fa634')
-    @utils.services('network')
     @testtools.skipUnless(CONF.network.public_network_id,
                           'The public_network_id option must be specified.')
     def test_associate_ip_to_server_with_floating_ip(self):
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index 04d18c0..2314433 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -26,6 +26,8 @@
     @classmethod
     def skip_checks(cls):
         super(FloatingIPDetailsTestJSON, cls).skip_checks()
+        if not utils.get_service_list()['network']:
+            raise cls.skipException("network service not enabled.")
         if not CONF.network_feature_enabled.floating_ips:
             raise cls.skipException("Floating ips are not available")
 
@@ -53,7 +55,6 @@
         super(FloatingIPDetailsTestJSON, cls).resource_cleanup()
 
     @decorators.idempotent_id('16db31c3-fb85-40c9-bbe2-8cf7b67ff99f')
-    @utils.services('network')
     def test_list_floating_ips(self):
         # Positive test:Should return the list of floating IPs
         body = self.client.list_floating_ips()['floating_ips']
@@ -64,7 +65,6 @@
             self.assertIn(self.floating_ip[i], floating_ips)
 
     @decorators.idempotent_id('eef497e0-8ff7-43c8-85ef-558440574f84')
-    @utils.services('network')
     def test_get_floating_ip_details(self):
         # Positive test:Should be able to GET the details of floatingIP
         # Creating a floating IP for which details are to be checked
@@ -86,7 +86,6 @@
         self.assertEqual(floating_ip_id, body['id'])
 
     @decorators.idempotent_id('df389fc8-56f5-43cc-b290-20eda39854d3')
-    @utils.services('network')
     def test_list_floating_ip_pools(self):
         # Positive test:Should return the list of floating IP Pools
         floating_ip_pools = self.pools_client.list_floating_ip_pools()
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
index f0b9fa5..0ade872 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
@@ -28,6 +28,8 @@
     @classmethod
     def skip_checks(cls):
         super(FloatingIPDetailsNegativeTestJSON, cls).skip_checks()
+        if not utils.get_service_list()['network']:
+            raise cls.skipException("network service not enabled.")
         if not CONF.network_feature_enabled.floating_ips:
             raise cls.skipException("Floating ips are not available")
 
@@ -38,7 +40,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('7ab18834-4a4b-4f28-a2c5-440579866695')
-    @utils.services('network')
     def test_get_nonexistent_floating_ip_details(self):
         # Negative test:Should not be able to GET the details
         # of non-existent floating IP
diff --git a/tempest/api/compute/security_groups/base.py b/tempest/api/compute/security_groups/base.py
index 5260a99..54a6da8 100644
--- a/tempest/api/compute/security_groups/base.py
+++ b/tempest/api/compute/security_groups/base.py
@@ -24,6 +24,12 @@
 class BaseSecurityGroupsTest(base.BaseV2ComputeTest):
 
     @classmethod
+    def skip_checks(cls):
+        super(BaseSecurityGroupsTest, cls).skip_checks()
+        if not utils.get_service_list()['network']:
+            raise cls.skipException("network service not enabled.")
+
+    @classmethod
     def setup_credentials(cls):
         # A network and a subnet will be created for these tests
         cls.set_network_resources(network=True, subnet=True)
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 06edc1c..4c99ea6 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 from tempest.api.compute.security_groups import base
-from tempest.common import utils
 from tempest.lib import decorators
 
 
@@ -55,7 +54,6 @@
 
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('850795d7-d4d3-4e55-b527-a774c0123d3a')
-    @utils.services('network')
     def test_security_group_rules_create(self):
         # Positive test: Creation of Security Group rule
         # should be successful
@@ -73,7 +71,6 @@
         self._check_expected_response(rule)
 
     @decorators.idempotent_id('7a01873e-3c38-4f30-80be-31a043cfe2fd')
-    @utils.services('network')
     def test_security_group_rules_create_with_optional_cidr(self):
         # Positive test: Creation of Security Group rule
         # with optional argument cidr
@@ -96,7 +93,6 @@
         self._check_expected_response(rule)
 
     @decorators.idempotent_id('7f5d2899-7705-4d4b-8458-4505188ffab6')
-    @utils.services('network')
     def test_security_group_rules_create_with_optional_group_id(self):
         # Positive test: Creation of Security Group rule
         # with optional argument group_id
@@ -125,7 +121,6 @@
 
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('a6154130-5a55-4850-8be4-5e9e796dbf17')
-    @utils.services('network')
     def test_security_group_rules_list(self):
         # Positive test: Created Security Group rules should be
         # in the list of all rules
@@ -163,7 +158,6 @@
         self.assertNotEmpty([i for i in rules if i['id'] == rule2_id])
 
     @decorators.idempotent_id('fc5c5acf-2091-43a6-a6ae-e42760e9ffaf')
-    @utils.services('network')
     def test_security_group_rules_delete_when_peer_group_deleted(self):
         # Positive test:rule will delete when peer group deleting
         # Creating a Security Group to add rules to it
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index f344d84..8283aae 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 from tempest.api.compute.security_groups import base
-from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
@@ -29,7 +28,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('1d507e98-7951-469b-82c3-23f1e6b8c254')
-    @utils.services('network')
     def test_create_security_group_rule_with_non_existent_id(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with non existent Parent group id
@@ -46,7 +44,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('2244d7e4-adb7-4ecb-9930-2d77e123ce4f')
-    @utils.services('network')
     def test_create_security_group_rule_with_invalid_id(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with Parent group id which is not integer
@@ -63,7 +60,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('8bd56d02-3ffa-4d67-9933-b6b9a01d6089')
-    @utils.services('network')
     def test_create_security_group_rule_duplicate(self):
         # Negative test: Create Security Group rule duplicate should fail
         # Creating a Security Group to add rule to it
@@ -88,7 +84,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('84c81249-9f6e-439c-9bbf-cbb0d2cddbdf')
-    @utils.services('network')
     def test_create_security_group_rule_with_invalid_ip_protocol(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with invalid ip_protocol
@@ -108,7 +103,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('12bbc875-1045-4f7a-be46-751277baedb9')
-    @utils.services('network')
     def test_create_security_group_rule_with_invalid_from_port(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with invalid from_port
@@ -127,7 +121,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('ff88804d-144f-45d1-bf59-dd155838a43a')
-    @utils.services('network')
     def test_create_security_group_rule_with_invalid_to_port(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with invalid to_port
@@ -146,7 +139,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('00296fa9-0576-496a-ae15-fbab843189e0')
-    @utils.services('network')
     def test_create_security_group_rule_with_invalid_port_range(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with invalid port range.
@@ -165,7 +157,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('56fddcca-dbb8-4494-a0db-96e9f869527c')
-    @utils.services('network')
     def test_delete_security_group_rule_with_non_existent_id(self):
         # Negative test: Deletion of Security Group rule should be FAIL
         # with non existent id
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index 01b19ca..eeb423e 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 from tempest.api.compute.security_groups import base
-from tempest.common import utils
 from tempest.common import waiters
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
@@ -30,7 +29,6 @@
 
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('eb2b087d-633d-4d0d-a7bd-9e6ba35b32de')
-    @utils.services('network')
     def test_security_groups_create_list_delete(self):
         # Positive test:Should return the list of Security Groups
         # Create 3 Security Groups
@@ -62,7 +60,6 @@
                                             for m_group in deleted_sgs))
 
     @decorators.idempotent_id('ecc0da4a-2117-48af-91af-993cca39a615')
-    @utils.services('network')
     def test_security_group_create_get_delete(self):
         # Security Group should be created, fetched and deleted
         # with char space between name along with
@@ -83,7 +80,6 @@
         self.client.wait_for_resource_deletion(securitygroup['id'])
 
     @decorators.idempotent_id('fe4abc0d-83f5-4c50-ad11-57a1127297a2')
-    @utils.services('network')
     def test_server_security_groups(self):
         # Checks that security groups may be added and linked to a server
         # and not deleted if the server is active.
@@ -125,7 +121,6 @@
         self.client.delete_security_group(sg2['id'])
 
     @decorators.idempotent_id('7d4e1d3c-3209-4d6d-b020-986304ebad1f')
-    @utils.services('network')
     def test_update_security_groups(self):
         # Update security group name and description
         # Create a security group
@@ -144,7 +139,6 @@
         self.assertEqual(s_new_des, fetched_group['description'])
 
     @decorators.idempotent_id('79517d60-535a-438f-af3d-e6feab1cbea7')
-    @utils.services('network')
     def test_list_security_groups_by_server(self):
         # Create a couple security groups that we will use
         # for the server resource this test creates
diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py
index e727dbb..9c44bb2 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -16,7 +16,6 @@
 import testtools
 
 from tempest.api.compute.security_groups import base
-from tempest.common import utils
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
@@ -34,7 +33,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('673eaec1-9b3e-48ed-bdf1-2786c1b9661c')
-    @utils.services('network')
     def test_security_group_get_nonexistent_group(self):
         # Negative test:Should not be able to GET the details
         # of non-existent Security Group
@@ -46,7 +44,6 @@
                              condition=CONF.service_available.neutron)
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('1759c3cb-b0fc-44b7-86ce-c99236be911d')
-    @utils.services('network')
     def test_security_group_create_with_invalid_group_name(self):
         # Negative test: Security Group should not be created with group name
         # as an empty string/with white spaces/chars more than 255
@@ -69,7 +66,6 @@
                              condition=CONF.service_available.neutron)
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('777b6f14-aca9-4758-9e84-38783cfa58bc')
-    @utils.services('network')
     def test_security_group_create_with_invalid_group_description(self):
         # Negative test: Security Group should not be created with description
         # longer than 255 chars. Empty description is allowed by the API
@@ -85,7 +81,6 @@
     @testtools.skipIf(CONF.service_available.neutron,
                       "Neutron allows duplicate names for security groups")
     @decorators.attr(type=['negative'])
-    @utils.services('network')
     def test_security_group_create_with_duplicate_name(self):
         # Negative test:Security Group with duplicate name should not
         # be created
@@ -99,7 +94,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('36a1629f-c6da-4a26-b8b8-55e7e5d5cd58')
-    @utils.services('network')
     def test_delete_the_default_security_group(self):
         # Negative test:Deletion of the "default" Security Group should Fail
         default_security_group_id = None
@@ -115,7 +109,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('6727c00b-214c-4f9e-9a52-017ac3e98411')
-    @utils.services('network')
     def test_delete_nonexistent_security_group(self):
         # Negative test:Deletion of a non-existent Security Group should fail
         non_exist_id = self.generate_random_security_group_id()
@@ -124,7 +117,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('1438f330-8fa4-4aeb-8a94-37c250106d7f')
-    @utils.services('network')
     def test_delete_security_group_without_passing_id(self):
         # Negative test:Deletion of a Security Group with out passing ID
         # should Fail
@@ -135,7 +127,6 @@
     @testtools.skipIf(CONF.service_available.neutron,
                       "Neutron does not check the security group ID")
     @decorators.attr(type=['negative'])
-    @utils.services('network')
     def test_update_security_group_with_invalid_sg_id(self):
         # Update security_group with invalid sg_id should fail
         s_name = data_utils.rand_name('sg')
@@ -150,7 +141,6 @@
     @testtools.skipIf(CONF.service_available.neutron,
                       "Neutron does not check the security group name")
     @decorators.attr(type=['negative'])
-    @utils.services('network')
     def test_update_security_group_with_invalid_sg_name(self):
         # Update security_group with invalid sg_name should fail
         securitygroup = self.create_security_group()
@@ -165,7 +155,6 @@
     @testtools.skipIf(CONF.service_available.neutron,
                       "Neutron does not check the security group description")
     @decorators.attr(type=['negative'])
-    @utils.services('network')
     def test_update_security_group_with_invalid_sg_des(self):
         # Update security_group with invalid sg_des should fail
         securitygroup = self.create_security_group()
@@ -178,7 +167,6 @@
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('27edee9c-873d-4da6-a68a-3c256efebe8f')
-    @utils.services('network')
     def test_update_non_existent_security_group(self):
         # Update a non-existent Security Group should Fail
         non_exist_id = self.generate_random_security_group_id()
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 4870a3d..b5fc39c 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -23,6 +23,7 @@
 from tempest.common.utils.linux import remote_client
 from tempest.common import waiters
 from tempest import config
+from tempest.lib.common import api_version_utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
@@ -369,7 +370,11 @@
                                 "been successful as it should have been "
                                 "deleted during rotation.", oldest_backup)
 
-        image1_id = data_utils.parse_image_id(resp['location'])
+        if api_version_utils.compare_version_header_to_response(
+                "OpenStack-API-Version", "compute 2.45", resp, "lt"):
+            image1_id = resp['image_id']
+        else:
+            image1_id = data_utils.parse_image_id(resp['location'])
         self.addCleanup(_clean_oldest_backup, image1_id)
         waiters.wait_for_image_status(glance_client,
                                       image1_id, 'active')
@@ -380,7 +385,11 @@
                                          backup_type='daily',
                                          rotation=2,
                                          name=backup2).response
-        image2_id = data_utils.parse_image_id(resp['location'])
+        if api_version_utils.compare_version_header_to_response(
+                "OpenStack-API-Version", "compute 2.45", resp, "lt"):
+            image2_id = resp['image_id']
+        else:
+            image2_id = data_utils.parse_image_id(resp['location'])
         self.addCleanup(glance_client.delete_image, image2_id)
         waiters.wait_for_image_status(glance_client,
                                       image2_id, 'active')
@@ -419,7 +428,11 @@
                                          backup_type='daily',
                                          rotation=2,
                                          name=backup3).response
-        image3_id = data_utils.parse_image_id(resp['location'])
+        if api_version_utils.compare_version_header_to_response(
+                "OpenStack-API-Version", "compute 2.45", resp, "lt"):
+            image3_id = resp['image_id']
+        else:
+            image3_id = data_utils.parse_image_id(resp['location'])
         self.addCleanup(glance_client.delete_image, image3_id)
         # the first back up should be deleted
         waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index cd5418f..34faf5f 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -26,7 +26,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class ExtensionsTestJSON(base.BaseV2ComputeTest):
+class ExtensionsTest(base.BaseV2ComputeTest):
 
     @decorators.idempotent_id('3bb27738-b759-4e0d-a5fa-37d7a6df07d1')
     def test_list_extensions(self):
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 502bc1b..e0fed58 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.api.compute import base
 from tempest.common import compute
 from tempest.common.utils.linux import remote_client
@@ -143,6 +141,10 @@
             self.assertEqual(server['id'], body['serverId'])
             self.assertEqual(attachment['volumeId'], body['volumeId'])
             self.assertEqual(attachment['id'], body['id'])
+            self.servers_client.detach_volume(server['id'],
+                                              attachment['volumeId'])
+            waiters.wait_for_volume_resource_status(
+                self.volumes_client, attachment['volumeId'], 'available')
 
 
 class AttachVolumeShelveTestJSON(AttachVolumeTestJSON):
@@ -155,6 +157,12 @@
     min_microversion = '2.20'
     max_microversion = 'latest'
 
+    @classmethod
+    def skip_checks(cls):
+        super(AttachVolumeShelveTestJSON, cls).skip_checks()
+        if not CONF.compute_feature_enabled.shelve:
+            raise cls.skipException('Shelve is not available.')
+
     def _count_volumes(self, server):
         # Count number of volumes on an instance
         volumes = 0
@@ -202,8 +210,6 @@
             self.assertEqual(number_of_volumes, counted_volumes)
 
     @decorators.idempotent_id('13a940b6-3474-4c3c-b03f-29b89112bfee')
-    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
-                          'Shelve is not available.')
     def test_attach_volume_shelved_or_offload_server(self):
         # Create server, count number of volumes on it, shelve
         # server and attach pre-created volume to shelved server
@@ -229,8 +235,6 @@
         self.assertIsNotNone(volume_attachment['device'])
 
     @decorators.idempotent_id('b54e86dd-a070-49c4-9c07-59ae6dae15aa')
-    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
-                          'Shelve is not available.')
     def test_detach_volume_shelved_or_offload_server(self):
         # Count number of volumes on instance, shelve
         # server and attach pre-created volume to shelved server
diff --git a/tempest/api/compute/volumes/test_volume_snapshots.py b/tempest/api/compute/volumes/test_volume_snapshots.py
index 0f436eb..b8ca81d 100644
--- a/tempest/api/compute/volumes/test_volume_snapshots.py
+++ b/tempest/api/compute/volumes/test_volume_snapshots.py
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.api.compute import base
 from tempest.common import waiters
 from tempest import config
@@ -38,6 +36,9 @@
         if not CONF.service_available.cinder:
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
+        if not CONF.volume_feature_enabled.snapshot:
+            skip_msg = ("Cinder volume snapshots are disabled")
+            raise cls.skipException(skip_msg)
 
     @classmethod
     def setup_clients(cls):
@@ -46,8 +47,6 @@
         cls.snapshots_client = cls.snapshots_extensions_client
 
     @decorators.idempotent_id('cd4ec87d-7825-450d-8040-6e2068f2da8f')
-    @testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
-                          'Cinder volume snapshots are disabled')
     def test_volume_snapshot_create_get_list_delete(self):
         volume = self.create_volume()
         self.addCleanup(self.delete_volume, volume['id'])
diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py
index 4bc987f..17db3ea 100644
--- a/tempest/api/identity/admin/v3/test_groups.py
+++ b/tempest/api/identity/admin/v3/test_groups.py
@@ -14,9 +14,12 @@
 #    under the License.
 
 from tempest.api.identity import base
+from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
+CONF = config.CONF
+
 
 class GroupsV3TestJSON(base.BaseIdentityV3AdminTest):
 
@@ -130,7 +133,14 @@
             self.addCleanup(self.groups_client.delete_group, group['id'])
             group_ids.append(group['id'])
         # List and Verify Groups
-        body = self.groups_client.list_groups()['groups']
+        # When domain specific drivers are enabled the operations
+        # of listing all users and listing all groups are not supported,
+        # they need a domain filter to be specified
+        if CONF.identity_feature_enabled.domain_specific_drivers:
+            body = self.groups_client.list_groups(
+                domain_id=self.domain['id'])['groups']
+        else:
+            body = self.groups_client.list_groups()['groups']
         for g in body:
             fetched_ids.append(g['id'])
         missing_groups = [g for g in group_ids if g not in fetched_ids]
diff --git a/tempest/api/identity/admin/v3/test_list_users.py b/tempest/api/identity/admin/v3/test_list_users.py
index 47a3580..506c729 100644
--- a/tempest/api/identity/admin/v3/test_list_users.py
+++ b/tempest/api/identity/admin/v3/test_list_users.py
@@ -14,9 +14,12 @@
 #    under the License.
 
 from tempest.api.identity import base
+from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
+CONF = config.CONF
+
 
 class UsersV3TestJSON(base.BaseIdentityV3AdminTest):
 
@@ -82,6 +85,11 @@
     def test_list_users_with_name(self):
         # List users with name
         params = {'name': self.domain_enabled_user['name']}
+        # When domain specific drivers are enabled the operations
+        # of listing all users and listing all groups are not supported,
+        # they need a domain filter to be specified
+        if CONF.identity_feature_enabled.domain_specific_drivers:
+            params['domain_id'] = self.domain_enabled_user['domain_id']
         self._list_users_with_params(params, 'name',
                                      self.domain_enabled_user,
                                      self.non_domain_enabled_user)
@@ -89,7 +97,18 @@
     @decorators.idempotent_id('b30d4651-a2ea-4666-8551-0c0e49692635')
     def test_list_users(self):
         # List users
-        body = self.users_client.list_users()['users']
+        # When domain specific drivers are enabled the operations
+        # of listing all users and listing all groups are not supported,
+        # they need a domain filter to be specified
+        if CONF.identity_feature_enabled.domain_specific_drivers:
+            body_enabled_user = self.users_client.list_users(
+                domain_id=self.domain_enabled_user['domain_id'])['users']
+            body_non_enabled_user = self.users_client.list_users(
+                domain_id=self.non_domain_enabled_user['domain_id'])['users']
+            body = (body_enabled_user + body_non_enabled_user)
+        else:
+            body = self.users_client.list_users()['users']
+
         fetched_ids = [u['id'] for u in body]
         missing_users = [u['id'] for u in self.users
                          if u['id'] not in fetched_ids]
diff --git a/tempest/api/network/test_allowed_address_pair.py b/tempest/api/network/test_allowed_address_pair.py
index 37f5ec2..a471bd6 100644
--- a/tempest/api/network/test_allowed_address_pair.py
+++ b/tempest/api/network/test_allowed_address_pair.py
@@ -41,6 +41,8 @@
         api_extensions
     """
 
+    _project_network_cidr = CONF.network.project_network_cidr
+
     @classmethod
     def skip_checks(cls):
         super(AllowedAddressPairTestJSON, cls).skip_checks()
@@ -103,7 +105,7 @@
     @decorators.idempotent_id('4d6d178f-34f6-4bff-a01c-0a2f8fe909e4')
     def test_update_port_with_cidr_address_pair(self):
         # Update allowed address pair with cidr
-        cidr = str(netaddr.IPNetwork(CONF.network.project_network_cidr))
+        cidr = str(netaddr.IPNetwork(self._project_network_cidr))
         self._update_port_with_address(cidr)
 
     @decorators.idempotent_id('b3f20091-6cd5-472b-8487-3516137df933')
@@ -133,3 +135,4 @@
 
 class AllowedAddressPairIpV6TestJSON(AllowedAddressPairTestJSON):
     _ip_version = 6
+    _project_network_cidr = CONF.network.project_network_v6_cidr
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 206d1a8..88340c1 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -374,22 +374,36 @@
     @testtools.skipUnless(CONF.network.public_network_id,
                           'The public_network_id option must be specified.')
     def test_external_network_visibility(self):
-        """Verifies user can see external networks but not subnets."""
+        public_network_id = CONF.network.public_network_id
+
+        # find external network matching public_network_id
         body = self.networks_client.list_networks(**{'router:external': True})
-        networks = [network['id'] for network in body['networks']]
-        self.assertNotEmpty(networks, "No external networks found")
+        external_network = next((network for network in body['networks']
+                                 if network['id'] == public_network_id), None)
+        self.assertIsNotNone(external_network, "Public network %s not found "
+                                               "in external network list"
+                             % public_network_id)
 
         nonexternal = [net for net in body['networks'] if
                        not net['router:external']]
         self.assertEmpty(nonexternal, "Found non-external networks"
                                       " in filtered list (%s)." % nonexternal)
-        self.assertIn(CONF.network.public_network_id, networks)
+
         # only check the public network ID because the other networks may
         # belong to other tests and their state may have changed during this
         # test
-        body = self.subnets_client.list_subnets(
-            network_id=CONF.network.public_network_id)
-        self.assertEmpty(body['subnets'], "Public subnets visible")
+        body = self.subnets_client.list_subnets(network_id=public_network_id)
+
+        # check subnet visibility of external_network
+        if external_network['shared']:
+            self.assertNotEmpty(body['subnets'], "Subnets should be visible "
+                                                 "for shared public network %s"
+                                % public_network_id)
+        else:
+            self.assertEmpty(body['subnets'], "Subnets should not be visible "
+                                              "for non-shared public "
+                                              "network %s"
+                             % public_network_id)
 
     @decorators.idempotent_id('c72c1c0c-2193-4aca-ccc4-b1442640bbbb')
     @utils.requires_ext(extension="standard-attr-description",
diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py
index 471f39a..41849bc 100644
--- a/tempest/api/volume/admin/test_snapshots_actions.py
+++ b/tempest/api/volume/admin/test_snapshots_actions.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest.api.volume import base
+from tempest.common import waiters
 from tempest import config
 from tempest.lib import decorators
 
@@ -43,6 +44,8 @@
         snapshot_id = self.snapshot['id']
         self.admin_snapshots_client.reset_snapshot_status(snapshot_id,
                                                           status)
+        waiters.wait_for_volume_resource_status(self.snapshots_client,
+                                                snapshot_id, status)
         super(SnapshotsActionsTest, self).tearDown()
 
     def _create_reset_and_force_delete_temp_snapshot(self, status=None):
@@ -50,10 +53,11 @@
         # and force delete temp snapshot
         temp_snapshot = self.create_snapshot(volume_id=self.volume['id'])
         if status:
-            self.admin_snapshots_client.\
-                reset_snapshot_status(temp_snapshot['id'], status)
-        self.admin_snapshots_client.\
-            force_delete_snapshot(temp_snapshot['id'])
+            self.admin_snapshots_client.reset_snapshot_status(
+                temp_snapshot['id'], status)
+            waiters.wait_for_volume_resource_status(
+                self.snapshots_client, temp_snapshot['id'], status)
+        self.admin_snapshots_client.force_delete_snapshot(temp_snapshot['id'])
         self.snapshots_client.wait_for_resource_deletion(temp_snapshot['id'])
 
     def _get_progress_alias(self):
@@ -63,18 +67,19 @@
     def test_reset_snapshot_status(self):
         # Reset snapshot status to creating
         status = 'creating'
-        self.admin_snapshots_client.\
-            reset_snapshot_status(self.snapshot['id'], status)
-        snapshot_get = self.admin_snapshots_client.show_snapshot(
-            self.snapshot['id'])['snapshot']
-        self.assertEqual(status, snapshot_get['status'])
+        self.admin_snapshots_client.reset_snapshot_status(
+            self.snapshot['id'], status)
+        waiters.wait_for_volume_resource_status(self.snapshots_client,
+                                                self.snapshot['id'], status)
 
     @decorators.idempotent_id('41288afd-d463-485e-8f6e-4eea159413eb')
     def test_update_snapshot_status(self):
         # Reset snapshot status to creating
         status = 'creating'
-        self.admin_snapshots_client.\
-            reset_snapshot_status(self.snapshot['id'], status)
+        self.admin_snapshots_client.reset_snapshot_status(
+            self.snapshot['id'], status)
+        waiters.wait_for_volume_resource_status(self.snapshots_client,
+                                                self.snapshot['id'], status)
 
         # Update snapshot status to error
         progress = '80%'
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index e4ec442..ce0cbd2 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import random
-
 from tempest.api.volume import base
 from tempest.lib import decorators
 
@@ -42,20 +40,25 @@
                                 "The count of volume hosts is < 2, "
                                 "response of list hosts is: %s" % hosts)
 
-        # Note(jeremyZ): Host in volume is always presented in two formats:
-        # <host-name> or <host-name>@<driver-name>. Since Mitaka is EOL,
-        # both formats can be chosen for test.
-        host_names = [host['host_name'] for host in hosts]
-        self.assertNotEmpty(host_names, "No available volume host is found, "
-                                        "all hosts that found are: %s" % hosts)
+        # Note(jeremyZ): The show host API is to show volume usage info on the
+        # specified cinder-volume host. If the host does not run cinder-volume
+        # service, or the cinder-volume service is disabled on the host, the
+        # show host API should fail (return code: 404). The cinder-volume host
+        # is presented in format: <host-name>@driver-name.
+        c_vol_hosts = [host['host_name'] for host in hosts
+                       if (host['service'] == 'cinder-volume'
+                           and host['service-state'] == 'enabled')]
+        self.assertNotEmpty(c_vol_hosts,
+                            "No available cinder-volume host is found, "
+                            "all hosts that found are: %s" % hosts)
 
-        # Choose a random host to get and check its elements
-        host_details = self.admin_hosts_client.show_host(
-            random.choice(host_names))['host']
-        self.assertNotEmpty(host_details)
+        # Check each cinder-volume host.
         host_detail_keys = ['project', 'volume_count', 'snapshot_count',
                             'host', 'total_volume_gb', 'total_snapshot_gb']
-        for detail in host_details:
-            self.assertIn('resource', detail)
-            for key in host_detail_keys:
-                self.assertIn(key, detail['resource'])
+        for host in c_vol_hosts:
+            host_details = self.admin_hosts_client.show_host(host)['host']
+            self.assertNotEmpty(host_details)
+            for detail in host_details:
+                self.assertIn('resource', detail)
+                for key in host_detail_keys:
+                    self.assertIn(key, detail['resource'])
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index f99e03d..8d09217 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -30,6 +30,8 @@
         if status:
             self.admin_volume_client.reset_volume_status(
                 temp_volume['id'], status=status)
+            waiters.wait_for_volume_resource_status(
+                self.volumes_client, temp_volume['id'], status)
         self.admin_volume_client.force_delete_volume(temp_volume['id'])
         self.volumes_client.wait_for_resource_deletion(temp_volume['id'])
 
@@ -37,14 +39,15 @@
     def test_volume_reset_status(self):
         # test volume reset status : available->error->available
         volume = self.create_volume()
+        self.addCleanup(waiters.wait_for_volume_resource_status,
+                        self.volumes_client, volume['id'], 'available')
         self.addCleanup(self.admin_volume_client.reset_volume_status,
                         volume['id'], status='available')
         for status in ['error', 'available', 'maintenance']:
             self.admin_volume_client.reset_volume_status(
                 volume['id'], status=status)
-            volume_get = self.admin_volume_client.show_volume(
-                volume['id'])['volume']
-            self.assertEqual(status, volume_get['status'])
+            waiters.wait_for_volume_resource_status(
+                self.volumes_client, volume['id'], status)
 
     @decorators.idempotent_id('21737d5a-92f2-46d7-b009-a0cc0ee7a570')
     def test_volume_force_delete_when_volume_is_creating(self):
@@ -88,6 +91,8 @@
 
         # Reset volume's status to error
         self.admin_volume_client.reset_volume_status(volume_id, status='error')
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume_id, 'error')
 
         # Force detach volume
         self.admin_volume_client.force_detach_volume(
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index afc3281..375aacb 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -99,8 +99,7 @@
                                                 'available')
 
         # Verify Import Backup
-        backups = self.admin_backups_client.list_backups(
-            detail=True)['backups']
+        backups = self.admin_backups_client.list_backups()['backups']
         self.assertIn(new_id, [b['id'] for b in backups])
 
         # Restore backup
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 9142dc3..63ef85b 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -72,6 +72,11 @@
         if cls._api_version == 3:
             cls.backups_client = cls.os_primary.backups_v3_client
             cls.volumes_client = cls.os_primary.volumes_v3_client
+            cls.messages_client = cls.os_primary.volume_v3_messages_client
+            cls.versions_client = cls.os_primary.volume_v3_versions_client
+            cls.groups_client = cls.os_primary.groups_v3_client
+            cls.group_snapshots_client = (
+                cls.os_primary.group_snapshots_v3_client)
         else:
             cls.backups_client = cls.os_primary.backups_v2_client
             cls.volumes_client = cls.os_primary.volumes_v2_client
@@ -82,10 +87,6 @@
         cls.availability_zone_client = (
             cls.os_primary.volume_v2_availability_zone_client)
         cls.volume_limits_client = cls.os_primary.volume_v2_limits_client
-        cls.messages_client = cls.os_primary.volume_v3_messages_client
-        cls.versions_client = cls.os_primary.volume_v3_versions_client
-        cls.groups_client = cls.os_primary.groups_v3_client
-        cls.group_snapshots_client = cls.os_primary.group_snapshots_v3_client
 
     def setUp(self):
         super(BaseVolumeTest, self).setUp()
@@ -259,6 +260,11 @@
         cls.admin_volume_client = cls.os_admin.volumes_v2_client
         if cls._api_version == 3:
             cls.admin_volume_client = cls.os_admin.volumes_v3_client
+            cls.admin_groups_client = cls.os_admin.groups_v3_client
+            cls.admin_messages_client = cls.os_admin.volume_v3_messages_client
+            cls.admin_group_snapshots_client = \
+                cls.os_admin.group_snapshots_v3_client
+            cls.admin_group_types_client = cls.os_admin.group_types_v3_client
         cls.admin_hosts_client = cls.os_admin.volume_hosts_v2_client
         cls.admin_snapshot_manage_client = \
             cls.os_admin.snapshot_manage_v2_client
@@ -274,11 +280,6 @@
             cls.os_admin.volume_capabilities_v2_client
         cls.admin_scheduler_stats_client = \
             cls.os_admin.volume_scheduler_stats_v2_client
-        cls.admin_messages_client = cls.os_admin.volume_v3_messages_client
-        cls.admin_groups_client = cls.os_admin.groups_v3_client
-        cls.admin_group_snapshots_client = \
-            cls.os_admin.group_snapshots_v3_client
-        cls.admin_group_types_client = cls.os_admin.group_types_v3_client
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index eea65f1..be5638e 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -112,6 +112,10 @@
         waiters.wait_for_volume_resource_status(self.volumes_client,
                                                 self.volume['id'], 'available')
 
+        image_info = self.images_client.show_image(image_id)
+        self.assertEqual(image_name, image_info['name'])
+        self.assertEqual(CONF.volume.disk_format, image_info['disk_format'])
+
     @decorators.idempotent_id('92c4ef64-51b2-40c0-9f7e-4749fbaaba33')
     def test_reserve_unreserve_volume(self):
         # Mark volume as reserved.
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index f2d8801..1e240b8 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -83,6 +83,9 @@
         # Get all backups with detail
         backups = self.backups_client.list_backups(
             detail=True)['backups']
+        for backup_info in backups:
+            self.assertIn('created_at', backup_info)
+            self.assertIn('links', backup_info)
         self.assertIn((backup['name'], backup['id']),
                       [(m['name'], m['id']) for m in backups])
 
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 8593d3a..b5f98ea 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -50,7 +50,7 @@
             return
 
         def str_vol(vol):
-            return "%s:%s" % (vol['id'], vol[self.name])
+            return "%s:%s" % (vol['id'], vol['name'])
 
         raw_msg = "Could not find volumes %s in expected list %s; fetched %s"
         self.fail(raw_msg % ([str_vol(v) for v in missing_vols],
@@ -60,7 +60,6 @@
     @classmethod
     def resource_setup(cls):
         super(VolumesListTestJSON, cls).resource_setup()
-        cls.name = cls.VOLUME_FIELDS[1]
 
         existing_volumes = cls.volumes_client.list_volumes()['volumes']
         cls.volume_id_list = [vol['id'] for vol in existing_volumes]
@@ -117,22 +116,20 @@
     @decorators.idempotent_id('a28e8da4-0b56-472f-87a8-0f4d3f819c02')
     def test_volume_list_by_name(self):
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        params = {self.name: volume[self.name]}
+        params = {'name': volume['name']}
         fetched_vol = self.volumes_client.list_volumes(
             params=params)['volumes']
         self.assertEqual(1, len(fetched_vol), str(fetched_vol))
-        self.assertEqual(fetched_vol[0][self.name],
-                         volume[self.name])
+        self.assertEqual(fetched_vol[0]['name'], volume['name'])
 
     @decorators.idempotent_id('2de3a6d4-12aa-403b-a8f2-fdeb42a89623')
     def test_volume_list_details_by_name(self):
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        params = {self.name: volume[self.name]}
+        params = {'name': volume['name']}
         fetched_vol = self.volumes_client.list_volumes(
             detail=True, params=params)['volumes']
         self.assertEqual(1, len(fetched_vol), str(fetched_vol))
-        self.assertEqual(fetched_vol[0][self.name],
-                         volume[self.name])
+        self.assertEqual(fetched_vol[0]['name'], volume['name'])
 
     @decorators.idempotent_id('39654e13-734c-4dab-95ce-7613bf8407ce')
     def test_volumes_list_by_status(self):
@@ -213,7 +210,7 @@
     def test_volume_list_param_display_name_and_status(self):
         # Test to list volume when display name and status param is given
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        params = {self.name: volume[self.name],
+        params = {'name': volume['name'],
                   'status': 'available'}
         self._list_by_param_value_and_assert(params)
 
@@ -221,7 +218,7 @@
     def test_volume_list_with_detail_param_display_name_and_status(self):
         # Test to list volume when name and status param is given
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        params = {self.name: volume[self.name],
+        params = {'name': volume['name'],
                   'status': 'available'}
         self._list_by_param_value_and_assert(params, with_detail=True)
 
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 47196ec..df0f5a5 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -198,9 +198,27 @@
         body = rest_client.ResponseBody(body.response, body['server'])
         servers = [body]
 
-    # The name of the method to associate a floating IP to as server is too
-    # long for PEP8 compliance so:
-    assoc = clients.compute_floating_ips_client.associate_floating_ip_to_server
+    def _setup_validation_fip():
+        if CONF.service_available.neutron:
+            ifaces = clients.interfaces_client.list_interfaces(server['id'])
+            validation_port = None
+            for iface in ifaces['interfaceAttachments']:
+                if iface['net_id'] == tenant_network['id']:
+                    validation_port = iface['port_id']
+                    break
+            if not validation_port:
+                # NOTE(artom) This will get caught by the catch-all clause in
+                # the wait_until loop below
+                raise ValueError('Unable to setup floating IP for validation: '
+                                 'port not found on tenant network')
+            clients.floating_ips_client.update_floatingip(
+                validation_resources['floating_ip']['id'],
+                port_id=validation_port)
+        else:
+            fip_client = clients.compute_floating_ips_client
+            fip_client.associate_floating_ip_to_server(
+                floating_ip=validation_resources['floating_ip']['ip'],
+                server_id=servers[0]['id'])
 
     if wait_until:
         for server in servers:
@@ -212,9 +230,7 @@
                 # creation will fail with the condition above (l.58).
                 if CONF.validation.run_validation and validatable:
                     if CONF.validation.connect_method == 'floating':
-                        assoc(floating_ip=validation_resources[
-                              'floating_ip']['ip'],
-                              server_id=servers[0]['id'])
+                        _setup_validation_fip()
 
             except Exception:
                 with excutils.save_and_reraise_exception():
diff --git a/tempest/config.py b/tempest/config.py
index af9eefc..e78a07f 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -234,6 +234,12 @@
                 deprecated_reason="This feature flag was introduced to "
                                   "support testing of old OpenStack versions, "
                                   "which are not supported anymore"),
+    cfg.BoolOpt('domain_specific_drivers',
+                default=False,
+                help='Are domain specific drivers enabled? '
+                     'This configuration value should be same as '
+                     '[identity]->domain_specific_drivers_enabled '
+                     'in keystone.conf.'),
     cfg.BoolOpt('security_compliance',
                 default=False,
                 help='Does the environment have the security compliance '
diff --git a/tempest/lib/common/api_version_utils.py b/tempest/lib/common/api_version_utils.py
index 1371b3c..98f174d 100644
--- a/tempest/lib/common/api_version_utils.py
+++ b/tempest/lib/common/api_version_utils.py
@@ -12,6 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from oslo_log import log as logging
 import testtools
 
 from tempest.lib.common import api_version_request
@@ -19,6 +20,7 @@
 
 
 LATEST_MICROVERSION = 'latest'
+LOG = logging.getLogger(__name__)
 
 
 class BaseMicroversionTest(object):
@@ -120,3 +122,60 @@
                                     api_microversion,
                                     response_header))
         raise exceptions.InvalidHTTPResponseHeader(msg)
+
+
+def compare_version_header_to_response(api_microversion_header_name,
+                                       api_microversion,
+                                       response_header,
+                                       operation='eq'):
+    """Compares API microversion in response header to ``api_microversion``.
+
+    Compare the ``api_microversion`` value in response header if microversion
+    header is present in response, otherwise return false.
+
+    To make this function work for APIs which do not return microversion
+    header in response (example compute v2.0), this function does *not* raise
+    InvalidHTTPResponseHeader.
+
+    :param api_microversion_header_name: Microversion header name. Example:
+        'Openstack-Api-Version'.
+    :param api_microversion: Microversion number. Example:
+
+        * '2.10' for the old-style header name, 'X-OpenStack-Nova-API-Version'
+        * 'Compute 2.10' for the new-style header name, 'Openstack-Api-Version'
+
+    :param response_header: Response header where microversion is
+        expected to be present.
+    :param operation: The boolean operation to use to compare the
+        ``api_microversion`` to the microversion in ``response_header``.
+        Can be 'lt', 'eq', 'gt', 'le', 'ne', 'ge'. Default is 'eq'. The
+        operation type should be based on the order of the arguments:
+        ``api_microversion`` <operation> ``response_header`` microversion.
+    :returns: True if the comparison is logically true, else False if the
+        comparison is logically false or if ``api_microversion_header_name`` is
+        missing in the ``response_header``.
+    :raises InvalidParam: If the operation is not lt, eq, gt, le, ne or ge.
+    """
+    api_microversion_header_name = api_microversion_header_name.lower()
+    if api_microversion_header_name not in response_header:
+        return False
+
+    op = getattr(api_version_request.APIVersionRequest,
+                 '__%s__' % operation, None)
+
+    if op is None:
+        msg = ("Operation %s is invalid. Valid options include: lt, eq, gt, "
+               "le, ne, ge." % operation)
+        LOG.debug(msg)
+        raise exceptions.InvalidParam(invalid_param=msg)
+
+    # Remove "volume" from "volume <microversion>", for example, so that the
+    # microversion can be converted to `APIVersionRequest`.
+    api_version = api_microversion.split(' ')[-1]
+    resp_version = response_header[api_microversion_header_name].split(' ')[-1]
+    if not op(
+        api_version_request.APIVersionRequest(api_version),
+        api_version_request.APIVersionRequest(resp_version)):
+        return False
+
+    return True
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
index c538c72..9b2e87e 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -276,3 +276,7 @@
 
 class InvalidTestResource(TempestException):
     message = "%(name)s is not a valid %(type)s, or the name is ambiguous"
+
+
+class InvalidParam(TempestException):
+    message = ("Invalid Parameter passed: %(invalid_param)s")
diff --git a/tempest/test.py b/tempest/test.py
index f390ae4..a4cc2cc 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -220,10 +220,13 @@
         resource_setup or at test level.
         """
         identity_version = cls.get_identity_version()
-        if 'admin' in cls.credentials and not credentials.is_admin_available(
-                identity_version=identity_version):
-            msg = "Missing Identity Admin API credentials in configuration."
-            raise cls.skipException(msg)
+        # setting force_tenant_isolation to True also needs admin credentials.
+        if ('admin' in cls.credentials or
+                getattr(cls, 'force_tenant_isolation', False)):
+            if not credentials.is_admin_available(
+                    identity_version=identity_version):
+                raise cls.skipException(
+                    "Missing Identity Admin API credentials in configuration.")
         if 'alt' in cls.credentials and not credentials.is_alt_available(
                 identity_version=identity_version):
             msg = "Missing a 2nd set of API credentials in configuration."
diff --git a/tempest/tests/cmd/test_run.py b/tempest/tests/cmd/test_run.py
index 7ac347d..6e1250f 100644
--- a/tempest/tests/cmd/test_run.py
+++ b/tempest/tests/cmd/test_run.py
@@ -13,6 +13,7 @@
 # under the License.
 
 import argparse
+import atexit
 import os
 import shutil
 import subprocess
@@ -25,6 +26,7 @@
 from tempest.tests import base
 
 DEVNULL = open(os.devnull, 'wb')
+atexit.register(DEVNULL.close)
 
 
 class TestTempestRun(base.TestCase):
@@ -68,6 +70,34 @@
         self.assertEqual('i_am_a_fun_little_regex',
                          self.run_cmd._build_regex(args))
 
+    def test__build_whitelist_file(self):
+        args = mock.Mock(spec=argparse.Namespace)
+        setattr(args, 'smoke', False)
+        setattr(args, 'regex', None)
+        self.tests = tempfile.NamedTemporaryFile(
+            prefix='whitelist', delete=False)
+        self.tests.write(b"volume \n compute")
+        self.tests.close()
+        setattr(args, 'whitelist_file', self.tests.name)
+        setattr(args, 'blacklist_file', None)
+        self.assertEqual("volume|compute",
+                         self.run_cmd._build_regex(args))
+        os.unlink(self.tests.name)
+
+    def test__build_blacklist_file(self):
+        args = mock.Mock(spec=argparse.Namespace)
+        setattr(args, 'smoke', False)
+        setattr(args, 'regex', None)
+        self.tests = tempfile.NamedTemporaryFile(
+            prefix='blacklist', delete=False)
+        self.tests.write(b"volume \n compute")
+        self.tests.close()
+        setattr(args, 'whitelist_file', None)
+        setattr(args, 'blacklist_file', self.tests.name)
+        self.assertEqual("^((?!compute|volume).)*$",
+                         self.run_cmd._build_regex(args))
+        os.unlink(self.tests.name)
+
 
 class TestRunReturnCode(base.TestCase):
     def setUp(self):
diff --git a/tempest/tests/lib/common/test_api_version_utils.py b/tempest/tests/lib/common/test_api_version_utils.py
index c063556..b99e8d4 100644
--- a/tempest/tests/lib/common/test_api_version_utils.py
+++ b/tempest/tests/lib/common/test_api_version_utils.py
@@ -92,24 +92,106 @@
     def test_header_matches(self):
         microversion_header_name = 'x-openstack-xyz-api-version'
         request_microversion = '2.1'
-        test_respose = {microversion_header_name: request_microversion}
+        test_response = {microversion_header_name: request_microversion}
         api_version_utils.assert_version_header_matches_request(
-            microversion_header_name, request_microversion, test_respose)
+            microversion_header_name, request_microversion, test_response)
 
     def test_header_does_not_match(self):
         microversion_header_name = 'x-openstack-xyz-api-version'
         request_microversion = '2.1'
-        test_respose = {microversion_header_name: '2.2'}
+        test_response = {microversion_header_name: '2.2'}
         self.assertRaises(
             exceptions.InvalidHTTPResponseHeader,
             api_version_utils.assert_version_header_matches_request,
-            microversion_header_name, request_microversion, test_respose)
+            microversion_header_name, request_microversion, test_response)
 
     def test_header_not_present(self):
         microversion_header_name = 'x-openstack-xyz-api-version'
         request_microversion = '2.1'
-        test_respose = {}
+        test_response = {}
         self.assertRaises(
             exceptions.InvalidHTTPResponseHeader,
             api_version_utils.assert_version_header_matches_request,
-            microversion_header_name, request_microversion, test_respose)
+            microversion_header_name, request_microversion, test_response)
+
+    def test_compare_versions_less_than(self):
+        microversion_header_name = 'x-openstack-xyz-api-version'
+        request_microversion = '2.2'
+        test_response = {microversion_header_name: '2.1'}
+        self.assertFalse(
+            api_version_utils.compare_version_header_to_response(
+                microversion_header_name, request_microversion, test_response,
+                "lt"))
+
+    def test_compare_versions_less_than_equal(self):
+        microversion_header_name = 'x-openstack-xyz-api-version'
+        request_microversion = '2.2'
+        test_response = {microversion_header_name: '2.1'}
+        self.assertFalse(
+            api_version_utils.compare_version_header_to_response(
+                microversion_header_name, request_microversion, test_response,
+                "le"))
+
+    def test_compare_versions_greater_than_equal(self):
+        microversion_header_name = 'x-openstack-xyz-api-version'
+        request_microversion = '2.1'
+        test_response = {microversion_header_name: '2.2'}
+        self.assertFalse(
+            api_version_utils.compare_version_header_to_response(
+                microversion_header_name, request_microversion, test_response,
+                "ge"))
+
+    def test_compare_versions_greater_than(self):
+        microversion_header_name = 'x-openstack-xyz-api-version'
+        request_microversion = '2.1'
+        test_response = {microversion_header_name: '2.2'}
+        self.assertFalse(
+            api_version_utils.compare_version_header_to_response(
+                microversion_header_name, request_microversion, test_response,
+                "gt"))
+
+    def test_compare_versions_equal(self):
+        microversion_header_name = 'x-openstack-xyz-api-version'
+        request_microversion = '2.11'
+        test_response = {microversion_header_name: '2.1'}
+        self.assertFalse(
+            api_version_utils.compare_version_header_to_response(
+                microversion_header_name, request_microversion, test_response,
+                "eq"))
+
+    def test_compare_versions_not_equal(self):
+        microversion_header_name = 'x-openstack-xyz-api-version'
+        request_microversion = '2.1'
+        test_response = {microversion_header_name: '2.1'}
+        self.assertFalse(
+            api_version_utils.compare_version_header_to_response(
+                microversion_header_name, request_microversion, test_response,
+                "ne"))
+
+    def test_compare_versions_with_name_in_microversion(self):
+        microversion_header_name = 'x-openstack-xyz-api-version'
+        request_microversion = 'volume 3.1'
+        test_response = {microversion_header_name: 'volume 3.1'}
+        self.assertTrue(
+            api_version_utils.compare_version_header_to_response(
+                microversion_header_name, request_microversion, test_response,
+                "eq"))
+
+    def test_compare_versions_invalid_operation(self):
+        microversion_header_name = 'x-openstack-xyz-api-version'
+        request_microversion = '2.1'
+        test_response = {microversion_header_name: '2.1'}
+        self.assertRaises(
+            exceptions.InvalidParam,
+            api_version_utils.compare_version_header_to_response,
+            microversion_header_name, request_microversion, test_response,
+            "foo")
+
+    def test_compare_versions_header_not_present(self):
+        microversion_header_name = 'x-openstack-xyz-api-version'
+        request_microversion = '2.1'
+        test_response = {}
+        self.assertFalse(
+            api_version_utils.compare_version_header_to_response(
+                microversion_header_name, request_microversion, test_response,
+                "eq"))