Merge "Add server param in manager.get_remote_client"
diff --git a/HACKING.rst b/HACKING.rst
index c0a857c..dbb758b 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -22,6 +22,7 @@
 - [T112] Check that tempest.lib should not import local tempest code
 - [T113] Check that tests use data_utils.rand_uuid() instead of uuid.uuid4()
 - [T114] Check that tempest.lib does not use tempest config
+- [T115] Check that admin tests should exist under admin path
 - [N322] Method's default argument shouldn't be mutable
 
 Test Data/Configuration
@@ -232,9 +233,9 @@
   and xml version of the same test class there could still be a race between
   methods.
 
-- The rand_name() function from tempest.common.utils.data_utils should be used
-  anywhere a resource is created with a name. Static naming should be avoided
-  to prevent resource conflicts.
+- The rand_name() function from tempest.lib.common.utils.data_utils should be
+  used anywhere a resource is created with a name. Static naming should be
+  avoided to prevent resource conflicts.
 
 - If the execution of a set of tests is required to be serialized then locking
   can be used to perform this. See AggregatesAdminTest in
diff --git a/doc/source/conf.py b/doc/source/conf.py
index f11d96a..b9e22b5 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -155,8 +155,7 @@
 git_cmd = ["git", "log", "--pretty=format:'%ad, commit %h'", "--date=local",
    "-n1"]
 try:
-    html_last_updated_fmt = str(
-        subprocess.Popen(git_cmd, stdout=subprocess.PIPE).communicate()[0])
+    html_last_updated_fmt = subprocess.check_output(git_cmd).decode('utf-8')
 except Exception:
     warnings.warn('Cannot get last updated time from git repository. '
                   'Not setting "html_last_updated_fmt".')
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index 2314222..4accd94 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -52,8 +52,7 @@
  #. ``uri_v3``
 
 The ``auth_version`` option is used to tell Tempest whether it should be using
-keystone's v2 or v3 api for communicating with keystone. (except for the
-identity api tests which will test a specific version) The two uri options are
+keystone's v2 or v3 api for communicating with keystone. The two uri options are
 used to tell Tempest the url of the keystone endpoint. The ``uri`` option is
 used for keystone v2 request and ``uri_v3`` is used for keystone v3. You want to
 ensure that which ever version you set for ``auth_version`` has its uri option
diff --git a/doc/source/index.rst b/doc/source/index.rst
index c4affd2..f562850 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -24,8 +24,8 @@
    field_guide/scenario
    field_guide/unit_tests
 
-For users
-=========
+Users Guide
+===========
 
 Tempest Configuration Guide
 ---------------------------
@@ -48,8 +48,8 @@
    workspace
    run
 
-For developers
-==============
+Developers Guide
+================
 
 Development
 -----------
diff --git a/doc/source/write_tests.rst b/doc/source/write_tests.rst
index 2363fa6..4e3bfa2 100644
--- a/doc/source/write_tests.rst
+++ b/doc/source/write_tests.rst
@@ -178,16 +178,16 @@
 +-------------------+---------------------+
 | Credentials Entry | Manager Variable    |
 +===================+=====================+
-| primary           | cls.os              |
+| primary           | cls.os_primary      |
 +-------------------+---------------------+
-| admin             | cls.os_adm          |
+| admin             | cls.os_admin        |
 +-------------------+---------------------+
 | alt               | cls.os_alt          |
 +-------------------+---------------------+
 | [$label, $role]   | cls.os_roles_$label |
 +-------------------+---------------------+
 
-By default cls.os is available since it is allocated in the base tempest test
+By default cls.os_primary is available since it is allocated in the base tempest test
 class (located in tempest/test.py). If your TestCase inherits from a different
 direct parent class (it'll still inherit from the BaseTestCase, just not
 directly) be sure to check if that class overrides allocated credentials.
@@ -270,13 +270,13 @@
 
   class TestExampleCase(test.BaseTestCase):
     def test_example_create_server(self):
-      self.os.servers_client.create_server(...)
+      self.os_primary.servers_client.create_server(...)
 
-is all you need to do. As described previously, in the above example the ``self.os``
-is created automatically because the base test class sets the ``credentials``
-attribute to allocate a primary credential set and initializes the client
-manager as ``self.os``. This same access pattern can be used for all of the
-clients in Tempest.
+is all you need to do. As described previously, in the above example the
+``self.os_primary`` is created automatically because the base test class sets the
+``credentials`` attribute to allocate a primary credential set and initializes
+the client manager as ``self.os_primary``. This same access pattern can be used
+for all of the clients in Tempest.
 
 Credentials Objects
 -------------------
@@ -293,7 +293,7 @@
 
   class TestExampleCase(test.BaseTestCase):
     def test_example_create_server(self):
-      credentials = self.os.credentials
+      credentials = self.os_primary.credentials
 
 The credentials object provides access to all of the credential information you
 would need to make API requests. For example, building off the previous
@@ -304,7 +304,7 @@
 
   class TestExampleCase(test.BaseTestCase):
     def test_example_create_server(self):
-      credentials = self.os.credentials
+      credentials = self.os_primary.credentials
       username = credentials.username
       user_id = credentials.user_id
       password = credentials.password
diff --git a/releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml b/releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml
new file mode 100644
index 0000000..8221d78
--- /dev/null
+++ b/releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - A new config option in the network-feature-enabled section, floating_ips,
+    to specify whether floating ips are available in the cloud under test. By
+    default this is set to True.
diff --git a/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml b/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml
new file mode 100644
index 0000000..bc7bcc8
--- /dev/null
+++ b/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - |
+    A new config option 'manage_snapshot_ref' is added in the volume section,
+    to specify snapshot ref parameter for different storage backend drivers
+    when managing an existing snapshot. By default it is set to fit the LVM
+    driver.
diff --git a/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml b/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml
new file mode 100644
index 0000000..9af57b1
--- /dev/null
+++ b/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml
@@ -0,0 +1,8 @@
+---
+features:
+  - |
+    Define v2.0 ``tags_client`` for the network service as a library
+    interface, allowing other projects to use this module as a stable
+    library without maintenance changes.
+
+    * tags_client(v2.0)
diff --git a/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml b/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml
new file mode 100644
index 0000000..afb6006
--- /dev/null
+++ b/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+  - |
+    When receiving nullable list as a response body, tempest.lib
+    rest_client module raised an exception without valid json
+    deserialization. A new release fixes this bug.
diff --git a/releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml b/releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml
new file mode 100644
index 0000000..1c8fa77
--- /dev/null
+++ b/releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+  - verify_tempest_config command starts using extension_client of
+    cinder v2 API only, because cinder v3 API is current and v2 and
+    v1 are deprecated and v3 extension API is the same as v2. Then
+    we can reuse the v2 client for v3 API also.
diff --git a/requirements.txt b/requirements.txt
index 26e1f02..259a4cf 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,7 +9,7 @@
 netaddr!=0.7.16,>=0.7.13 # BSD
 testrepository>=0.0.18 # Apache-2.0/BSD
 oslo.concurrency>=3.8.0 # Apache-2.0
-oslo.config>=3.22.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.serialization>=1.10.0 # Apache-2.0
 oslo.utils>=3.20.0 # Apache-2.0
@@ -20,6 +20,6 @@
 stevedore>=1.20.0 # Apache-2.0
 PrettyTable<0.8,>=0.7.1 # BSD
 os-testr>=0.8.0 # Apache-2.0
-urllib3>=1.15.1 # MIT
+urllib3>=1.21.1 # MIT
 debtcollector>=1.2.0 # Apache-2.0
 unittest2 # BSD
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
index 31976ec..69cbfb5 100644
--- a/tempest/api/compute/admin/test_agents.py
+++ b/tempest/api/compute/admin/test_agents.py
@@ -86,8 +86,7 @@
         body = self.client.create_agent(**self.params_agent)['agent']
         self.addCleanup(self.client.delete_agent, body['agent_id'])
         agents = self.client.list_agents()['agents']
-        self.assertGreater(len(agents), 0,
-                           'Cannot get any agents.(%s)' % agents)
+        self.assertNotEmpty(agents, 'Cannot get any agents.(%s)' % agents)
         self.assertIn(body['agent_id'], map(lambda x: x['agent_id'], agents))
 
     @decorators.idempotent_id('eabadde4-3cd7-4ec4-a4b5-5a936d2d4408')
@@ -105,8 +104,7 @@
         agent_id_xen = agent_xen['agent_id']
         agents = (self.client.list_agents(hypervisor=agent_xen['hypervisor'])
                   ['agents'])
-        self.assertGreater(len(agents), 0,
-                           'Cannot get any agents.(%s)' % agents)
+        self.assertNotEmpty(agents, 'Cannot get any agents.(%s)' % agents)
         self.assertIn(agent_id_xen, map(lambda x: x['agent_id'], agents))
         self.assertNotIn(body['agent_id'], map(lambda x: x['agent_id'],
                                                agents))
diff --git a/tempest/api/compute/admin/test_auto_allocate_network.py b/tempest/api/compute/admin/test_auto_allocate_network.py
index c4db5e3..ba8a214 100644
--- a/tempest/api/compute/admin/test_auto_allocate_network.py
+++ b/tempest/api/compute/admin/test_auto_allocate_network.py
@@ -151,7 +151,7 @@
         """Tests that no networking is allocated for the server."""
         # create the server with no networking
         server, _ = compute.create_test_server(
-            self.os, networks='none', wait_until='ACTIVE')
+            self.os_primary, networks='none', wait_until='ACTIVE')
         self.addCleanup(self.delete_server, server['id'])
         # get the server ips
         addresses = self.servers_client.list_addresses(
@@ -176,7 +176,7 @@
         # - Third request sees net1 and net2 for the tenant and fails with a
         #   NetworkAmbiguous 400 error.
         _, servers = compute.create_test_server(
-            self.os, networks='auto', wait_until='ACTIVE',
+            self.os_primary, networks='auto', wait_until='ACTIVE',
             min_count=3)
         server_nets = set()
         for server in servers:
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index 50dec28..bbd39b6 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -29,10 +29,10 @@
     def test_get_availability_zone_list(self):
         # List of availability zone
         availability_zone = self.client.list_availability_zones()
-        self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
+        self.assertNotEmpty(availability_zone['availabilityZoneInfo'])
 
     @decorators.idempotent_id('ef726c58-530f-44c2-968c-c7bed22d5b8c')
     def test_get_availability_zone_list_detail(self):
         # List of availability zones and available services
         availability_zone = self.client.list_availability_zones(detail=True)
-        self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
+        self.assertNotEmpty(availability_zone['availabilityZoneInfo'])
diff --git a/tempest/api/compute/admin/test_delete_server.py b/tempest/api/compute/admin/test_delete_server.py
index 2569161..83444b9 100644
--- a/tempest/api/compute/admin/test_delete_server.py
+++ b/tempest/api/compute/admin/test_delete_server.py
@@ -29,7 +29,7 @@
     def setup_clients(cls):
         super(DeleteServersAdminTestJSON, cls).setup_clients()
         cls.non_admin_client = cls.servers_client
-        cls.admin_client = cls.os_adm.servers_client
+        cls.admin_client = cls.os_admin.servers_client
 
     @decorators.idempotent_id('99774678-e072-49d1-9d2a-49a59bc56063')
     def test_delete_server_while_in_error_state(self):
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index 5a38acc..2c236ec 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -50,7 +50,7 @@
 
         flavor_access = (self.admin_flavors_client.list_flavor_access(
                          flavor['id'])['flavor_access'])
-        self.assertEqual(len(flavor_access), 0, str(flavor_access))
+        self.assertEmpty(flavor_access)
 
     @decorators.idempotent_id('59e622f6-bdf6-45e3-8ba8-fedad905a6b4')
     def test_flavor_access_add_remove(self):
diff --git a/tempest/api/compute/admin/test_floating_ips_bulk.py b/tempest/api/compute/admin/test_floating_ips_bulk.py
index 056b4bd..496f119 100644
--- a/tempest/api/compute/admin/test_floating_ips_bulk.py
+++ b/tempest/api/compute/admin/test_floating_ips_bulk.py
@@ -73,7 +73,7 @@
                         self.client.delete_floating_ips_bulk, self.ip_range)
         self.assertEqual(self.ip_range, body['ip_range'])
         ips_list = self.client.list_floating_ips_bulk()['floating_ip_info']
-        self.assertNotEqual(0, len(ips_list))
+        self.assertNotEmpty(ips_list)
         for ip in netaddr.IPNetwork(self.ip_range).iter_hosts():
             self.assertIn(str(ip), map(lambda x: x['address'], ips_list))
         body = (self.client.delete_floating_ips_bulk(self.ip_range)
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index 8e2f6ed..0e1e7ed 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -36,7 +36,7 @@
         hosts = self.client.list_hosts()['hosts']
         host = hosts[0]
         hosts = self.client.list_hosts(zone=host['zone'])['hosts']
-        self.assertGreaterEqual(len(hosts), 1)
+        self.assertNotEmpty(hosts)
         self.assertIn(host, hosts)
 
     @decorators.idempotent_id('9af3c171-fbf4-4150-a624-22109733c2a6')
@@ -44,26 +44,26 @@
         # If send the request with a blank zone, the request will be successful
         # and it will return all the hosts list
         hosts = self.client.list_hosts(zone='')['hosts']
-        self.assertNotEqual(0, len(hosts))
+        self.assertNotEmpty(hosts)
 
     @decorators.idempotent_id('c6ddbadb-c94e-4500-b12f-8ffc43843ff8')
     def test_list_hosts_with_nonexistent_zone(self):
         # If send the request with a nonexistent zone, the request will be
         # successful and no hosts will be returned
         hosts = self.client.list_hosts(zone='xxx')['hosts']
-        self.assertEqual(0, len(hosts))
+        self.assertEmpty(hosts)
 
     @decorators.idempotent_id('38adbb12-aee2-4498-8aec-329c72423aa4')
     def test_show_host_detail(self):
         hosts = self.client.list_hosts()['hosts']
 
         hosts = [host for host in hosts if host['service'] == 'compute']
-        self.assertGreaterEqual(len(hosts), 1)
+        self.assertNotEmpty(hosts)
 
         for host in hosts:
             hostname = host['host_name']
             resources = self.client.show_host(hostname)['host']
-            self.assertGreaterEqual(len(resources), 1)
+            self.assertNotEmpty(resources)
             host_resource = resources[0]['resource']
             self.assertIsNotNone(host_resource)
             self.assertIsNotNone(host_resource['cpu'])
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index 4544267..0db802c 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -31,7 +31,7 @@
         return hypers
 
     def assertHypervisors(self, hypers):
-        self.assertGreater(len(hypers), 0, "No hypervisors found: %s" % hypers)
+        self.assertNotEmpty(hypers, "No hypervisors found: %s" % hypers)
 
     @decorators.idempotent_id('7f0ceacd-c64d-4e96-b8ee-d02943142cc5')
     def test_get_hypervisor_list(self):
@@ -52,7 +52,7 @@
         self.assertHypervisors(hypers)
 
         details = self.client.show_hypervisor(hypers[0]['id'])['hypervisor']
-        self.assertGreater(len(details), 0)
+        self.assertNotEmpty(details)
         self.assertEqual(details['hypervisor_hostname'],
                          hypers[0]['hypervisor_hostname'])
 
@@ -65,14 +65,14 @@
         hostname = hypers[0]['hypervisor_hostname']
         hypervisors = (self.client.list_servers_on_hypervisor(hostname)
                        ['hypervisors'])
-        self.assertGreater(len(hypervisors), 0)
+        self.assertNotEmpty(hypervisors)
 
     @decorators.idempotent_id('797e4f28-b6e0-454d-a548-80cc77c00816')
     def test_get_hypervisor_stats(self):
         # Verify the stats of the all hypervisor
         stats = (self.client.show_hypervisor_statistics()
                  ['hypervisor_statistics'])
-        self.assertGreater(len(stats), 0)
+        self.assertNotEmpty(stats)
 
     @decorators.idempotent_id('91a50d7d-1c2b-4f24-b55a-a1fe20efca70')
     def test_get_hypervisor_uptime(self):
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index af87287..431e823 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -47,7 +47,7 @@
     @decorators.idempotent_id('51e663d0-6b89-4817-a465-20aca0667d03')
     def test_show_hypervisor_with_non_admin_user(self):
         hypers = self._list_hypervisors()
-        self.assertGreater(len(hypers), 0)
+        self.assertNotEmpty(hypers)
 
         self.assertRaises(
             lib_exc.Forbidden,
@@ -58,7 +58,7 @@
     @decorators.idempotent_id('2a0a3938-832e-4859-95bf-1c57c236b924')
     def test_show_servers_with_non_admin_user(self):
         hypers = self._list_hypervisors()
-        self.assertGreater(len(hypers), 0)
+        self.assertNotEmpty(hypers)
 
         self.assertRaises(
             lib_exc.Forbidden,
@@ -96,7 +96,7 @@
     @decorators.idempotent_id('6c3461f9-c04c-4e2a-bebb-71dc9cb47df2')
     def test_get_hypervisor_uptime_with_non_admin_user(self):
         hypers = self._list_hypervisors()
-        self.assertGreater(len(hypers), 0)
+        self.assertNotEmpty(hypers)
 
         self.assertRaises(
             lib_exc.Forbidden,
@@ -131,7 +131,7 @@
     @decorators.idempotent_id('5b6a6c79-5dc1-4fa5-9c58-9c8085948e74')
     def test_search_hypervisor_with_non_admin_user(self):
         hypers = self._list_hypervisors()
-        self.assertGreater(len(hypers), 0)
+        self.assertNotEmpty(hypers)
 
         self.assertRaises(
             lib_exc.Forbidden,
diff --git a/tempest/api/compute/admin/test_networks.py b/tempest/api/compute/admin/test_networks.py
index 0ea0a78..acb0d90 100644
--- a/tempest/api/compute/admin/test_networks.py
+++ b/tempest/api/compute/admin/test_networks.py
@@ -62,4 +62,4 @@
             self.assertIn(configured_network, [x['label'] for x in networks])
         else:
             network_labels = [x['label'] for x in networks]
-            self.assertGreaterEqual(len(network_labels), 1)
+            self.assertNotEmpty(network_labels)
diff --git a/tempest/api/compute/admin/test_security_group_default_rules.py b/tempest/api/compute/admin/test_security_group_default_rules.py
index 6c7cde2..f2f3b57 100644
--- a/tempest/api/compute/admin/test_security_group_default_rules.py
+++ b/tempest/api/compute/admin/test_security_group_default_rules.py
@@ -111,7 +111,7 @@
                         rule['id'])
         rules = (self.adm_client.list_security_group_default_rules()
                  ['security_group_default_rules'])
-        self.assertNotEqual(0, len(rules))
+        self.assertNotEmpty(rules)
         self.assertIn(rule, rules)
 
     @decorators.idempotent_id('15cbb349-86b4-4f71-a048-04b7ef3f150b')
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index a492b43..789049b 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -133,7 +133,7 @@
         # self.create_test_server() here as this method creates the server
         # in the "primary" (i.e non-admin) tenant.
         test_server, _ = compute.create_test_server(
-            self.os_adm, wait_until="ACTIVE", name=name, **network_kwargs)
+            self.os_admin, wait_until="ACTIVE", name=name, **network_kwargs)
         self.addCleanup(self.client.delete_server, test_server['id'])
         server = self.client.show_server(test_server['id'])['server']
         self.assertEqual(server['status'], 'ACTIVE')
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index 1dfc13e..f3eb597 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -29,13 +29,13 @@
     @decorators.idempotent_id('5be41ef4-53d1-41cc-8839-5c2a48a1b283')
     def test_list_services(self):
         services = self.client.list_services()['services']
-        self.assertNotEqual(0, len(services))
+        self.assertNotEmpty(services)
 
     @decorators.idempotent_id('f345b1ec-bc6e-4c38-a527-3ca2bc00bef5')
     def test_get_service_by_service_binary_name(self):
         binary_name = 'nova-compute'
         services = self.client.list_services(binary=binary_name)['services']
-        self.assertNotEqual(0, len(services))
+        self.assertNotEmpty(services)
         for service in services:
             self.assertEqual(binary_name, service['binary'])
 
diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py
index 38bb5ec..201670a 100644
--- a/tempest/api/compute/admin/test_services_negative.py
+++ b/tempest/api/compute/admin/test_services_negative.py
@@ -48,7 +48,7 @@
         host_name = services[0]['host']
         services = self.client.list_services(host=host_name,
                                              binary='xxx')['services']
-        self.assertEqual(0, len(services))
+        self.assertEmpty(services)
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('64e7e7fb-69e8-4cb6-a71d-8d5eb0c98655')
@@ -57,4 +57,4 @@
         binary_name = services[0]['binary']
         services = self.client.list_services(host='xxx',
                                              binary=binary_name)['services']
-        self.assertEqual(0, len(services))
+        self.assertEmpty(services)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 141b9f3..d893446 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -204,7 +204,7 @@
             kwargs['name'] = data_utils.rand_name(cls.__name__ + "-server")
         tenant_network = cls.get_tenant_network()
         body, servers = compute.create_test_server(
-            cls.os,
+            cls.os_primary,
             validatable,
             validation_resources=cls.validation_resources,
             tenant_network=tenant_network,
@@ -350,7 +350,7 @@
     @classmethod
     def delete_volume(cls, volume_id):
         """Deletes the given volume and waits for it to be gone."""
-        cls._delete_volume(cls.volumes_extensions_client, volume_id)
+        cls._delete_volume(cls.volumes_client, volume_id)
 
     @classmethod
     def get_server_ip(cls, server):
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 2769245..faa7b5d 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -30,6 +30,12 @@
     floating_ip = None
 
     @classmethod
+    def skip_checks(cls):
+        super(FloatingIPsTestJSON, cls).skip_checks()
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
+
+    @classmethod
     def setup_clients(cls):
         super(FloatingIPsTestJSON, cls).setup_clients()
         cls.client = cls.floating_ips_client
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 96983b0..483bd95 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
@@ -28,6 +28,12 @@
 class FloatingIPsNegativeTestJSON(base.BaseFloatingIPsTest):
 
     @classmethod
+    def skip_checks(cls):
+        super(FloatingIPsNegativeTestJSON, cls).skip_checks()
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
+
+    @classmethod
     def setup_clients(cls):
         super(FloatingIPsNegativeTestJSON, cls).setup_clients()
         cls.client = cls.floating_ips_client
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 71f5f13..913b992 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -24,6 +24,12 @@
 class FloatingIPDetailsTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
+    def skip_checks(cls):
+        super(FloatingIPDetailsTestJSON, cls).skip_checks()
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
+
+    @classmethod
     def setup_clients(cls):
         super(FloatingIPDetailsTestJSON, cls).setup_clients()
         cls.client = cls.floating_ips_client
@@ -52,7 +58,7 @@
         # Positive test:Should return the list of floating IPs
         body = self.client.list_floating_ips()['floating_ips']
         floating_ips = body
-        self.assertNotEqual(0, len(floating_ips),
+        self.assertNotEmpty(floating_ips,
                             "Expected floating IPs. Got zero.")
         for i in range(3):
             self.assertIn(self.floating_ip[i], floating_ips)
@@ -84,5 +90,5 @@
     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()
-        self.assertNotEqual(0, len(floating_ip_pools['floating_ip_pools']),
+        self.assertNotEmpty(floating_ip_pools['floating_ip_pools'],
                             "Expected floating IP Pools. Got zero.")
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 9d70bf7..b5bbb8c 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
@@ -26,6 +26,12 @@
 class FloatingIPDetailsNegativeTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
+    def skip_checks(cls):
+        super(FloatingIPDetailsNegativeTestJSON, cls).skip_checks()
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
+
+    @classmethod
     def setup_clients(cls):
         super(FloatingIPDetailsNegativeTestJSON, cls).setup_clients()
         cls.client = cls.floating_ips_client
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 83447b6..5987d39 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -80,11 +80,11 @@
     @decorators.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6')
     def test_create_image_specify_multibyte_character_image_name(self):
         # prefix character is:
-        # http://www.fileformat.info/info/unicode/char/1F4A9/index.htm
+        # http://unicode.org/cldr/utility/character.jsp?a=20A1
 
-        # We use a string with 3 byte utf-8 character due to bug
-        # #1370954 in glance which will 500 if mysql is used as the
-        # backend and it attempts to store a 4 byte utf-8 character
+        # We use a string with 3 byte utf-8 character due to nova/glance which
+        # will return 400(Bad Request) if we attempt to send a name which has
+        # 4 byte utf-8 character.
         utf8_name = data_utils.rand_name(b'\xe2\x82\xa1'.decode('utf-8'))
         body = self.client.create_image(self.server_id, name=utf8_name)
         image_id = data_utils.parse_image_id(body.response['location'])
diff --git a/tempest/api/compute/limits/test_absolute_limits.py b/tempest/api/compute/limits/test_absolute_limits.py
index 58352bd..0585fec 100644
--- a/tempest/api/compute/limits/test_absolute_limits.py
+++ b/tempest/api/compute/limits/test_absolute_limits.py
@@ -42,6 +42,6 @@
         # check whether all expected elements exist
         missing_elements =\
             [ele for ele in expected_elements if ele not in absolute_limits]
-        self.assertEqual(0, len(missing_elements),
+        self.assertEmpty(missing_elements,
                          "Failed to find element %s in absolute limits list"
                          % ', '.join(ele for ele in missing_elements))
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 3378ef8..b568f7d 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -186,4 +186,4 @@
         rules = (self.security_groups_client.show_security_group(sg1_id)
                  ['security_group']['rules'])
         # The group1 has no rules because group2 has deleted
-        self.assertEqual(0, len(rules))
+        self.assertEmpty(rules)
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index e50b29a..65d5042 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -49,7 +49,6 @@
         cls.subnets_client = cls.os_primary.subnets_client
         cls.ports_client = cls.os_primary.ports_client
 
-    # TODO(mriedem): move this into a common waiters utility module
     def wait_for_port_detach(self, port_id):
         """Waits for the port's device_id to be unset.
 
@@ -264,7 +263,8 @@
 
         # create two servers
         _, servers = compute.create_test_server(
-            self.os, tenant_network=network, wait_until='ACTIVE', min_count=2)
+            self.os_primary, tenant_network=network,
+            wait_until='ACTIVE', min_count=2)
         # add our cleanups for the servers since we bypassed the base class
         for server in servers:
             self.addCleanup(self.delete_server, server['id'])
diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py
index 82e74ed..36828d6 100644
--- a/tempest/api/compute/servers/test_availability_zone.py
+++ b/tempest/api/compute/servers/test_availability_zone.py
@@ -29,4 +29,4 @@
     def test_get_availability_zone_list_with_non_admin_user(self):
         # List of availability zone with non-administrator user
         availability_zone = self.client.list_availability_zones()
-        self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
+        self.assertNotEmpty(availability_zone['availabilityZoneInfo'])
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 1ad153a..921b7da 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -142,7 +142,7 @@
         # Verify only the expected number of servers are returned
         params = {'limit': 0}
         servers = self.client.list_servers(**params)
-        self.assertEqual(0, len(servers['servers']))
+        self.assertEmpty(servers['servers'])
 
     @decorators.idempotent_id('37791bbd-90c0-4de0-831e-5f38cba9c6b3')
     def test_list_servers_filter_by_exceed_limit(self):
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 3e32c2d..6c9b287 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -84,12 +84,6 @@
         servers = body['servers']
         self.assertEmpty(servers)
 
-    @decorators.idempotent_id('12c80a9f-2dec-480e-882b-98ba15757659')
-    def test_list_servers_by_limits(self):
-        # List servers by specifying limits
-        body = self.client.list_servers(limit=1)
-        self.assertEqual(1, len([x for x in body['servers'] if 'id' in x]))
-
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('d47c17fb-eebd-4287-8e95-f20a7e627b18')
     def test_list_servers_by_limits_greater_than_actual_count(self):
@@ -128,7 +122,7 @@
         # Return an empty list when a date in the future is passed
         changes_since = {'changes-since': '2051-01-01T12:34:00Z'}
         body = self.client.list_servers(**changes_since)
-        self.assertEqual(0, len(body['servers']))
+        self.assertEmpty(body['servers'])
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('93055106-2d34-46fe-af68-d9ddbf7ee570')
diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py
index 7cbb513..059454d 100644
--- a/tempest/api/compute/servers/test_multiple_create.py
+++ b/tempest/api/compute/servers/test_multiple_create.py
@@ -24,7 +24,7 @@
     def test_multiple_create(self):
         tenant_network = self.get_tenant_network()
         body, servers = compute.create_test_server(
-            self.os,
+            self.os_primary,
             wait_until='ACTIVE',
             min_count=2,
             tenant_network=tenant_network)
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 76b9c44..6f072b2 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -531,6 +531,10 @@
         self.client.unshelve_server(self.server_id)
         waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
 
+        images = self.compute_images_client.list_images(**params)['images']
+        msg = ('After unshelve, shelved image is not deleted.')
+        self.assertEmpty(images, msg)
+
     @decorators.idempotent_id('af8eafd4-38a7-4a4b-bdbc-75145a580560')
     def test_stop_start_server(self):
         self.client.stop_server(self.server_id)
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index 92b1ff1..022ceba 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -48,9 +48,9 @@
 
         # We do not know the exact network configuration, but an instance
         # should at least have a single public or private address
-        self.assertGreaterEqual(len(addresses), 1)
+        self.assertNotEmpty(addresses)
         for network_addresses in addresses.values():
-            self.assertGreaterEqual(len(network_addresses), 1)
+            self.assertNotEmpty(network_addresses)
             for address in network_addresses:
                 self.assertTrue(address['addr'])
                 self.assertTrue(address['version'])
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 83151b3..b0ef3bc 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -65,6 +65,8 @@
     @decorators.idempotent_id('4842e0cf-e87d-4d9d-b61f-f4791da3cacc')
     @testtools.skipUnless(CONF.network.public_network_id,
                           'The public_network_id option must be specified.')
+    @testtools.skipUnless(CONF.network_feature_enabled.floating_ips,
+                          "Floating ips are not available")
     def test_rescued_vm_associate_dissociate_floating_ip(self):
         # Association of floating IP to a rescued vm
         floating_ip_body = self.floating_ips_client.create_floating_ip(
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index 11f236b..ea4c141 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -102,14 +102,10 @@
         prefix_name = u'\u00CD\u00F1st\u00E1\u00F1c\u00E9'
         self._update_server_name(server['id'], 'ACTIVE', prefix_name)
 
-    @decorators.idempotent_id('6ac19cb1-27a3-40ec-b350-810bdc04c08e')
-    def test_update_server_name_in_stop_state(self):
-        # The server name should be changed to the provided value
-        server = self.create_test_server(wait_until='ACTIVE')
+        # stop server and check server name update again
         self.client.stop_server(server['id'])
         waiters.wait_for_server_status(self.client, server['id'], 'SHUTOFF')
         # Update instance name with non-ASCII characters
-        prefix_name = u'\u00CD\u00F1st\u00E1\u00F1c\u00E9'
         updated_server = self._update_server_name(server['id'],
                                                   'SHUTOFF',
                                                   prefix_name)
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 610121b..6b625d9 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -58,7 +58,7 @@
             output = self.client.list_virtual_interfaces(self.server['id'])
             self.assertIsNotNone(output)
             virt_ifaces = output
-            self.assertNotEqual(0, len(virt_ifaces['virtual_interfaces']),
+            self.assertNotEmpty(virt_ifaces['virtual_interfaces'],
                                 'Expected virtual interfaces, got 0 '
                                 'interfaces.')
             for virt_iface in virt_ifaces['virtual_interfaces']:
diff --git a/tempest/api/compute/volumes/test_volume_snapshots.py b/tempest/api/compute/volumes/test_volume_snapshots.py
index 2f3a06e..0f436eb 100644
--- a/tempest/api/compute/volumes/test_volume_snapshots.py
+++ b/tempest/api/compute/volumes/test_volume_snapshots.py
@@ -27,6 +27,11 @@
 
 class VolumesSnapshotsTestJSON(base.BaseV2ComputeTest):
 
+    # These tests will fail with a 404 starting from microversion 2.36. For
+    # more information, see:
+    # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated
+    max_microversion = '2.35'
+
     @classmethod
     def skip_checks(cls):
         super(VolumesSnapshotsTestJSON, cls).skip_checks()
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
index 43c837a..01cfb5f 100644
--- a/tempest/api/compute/volumes/test_volumes_get.py
+++ b/tempest/api/compute/volumes/test_volumes_get.py
@@ -16,7 +16,6 @@
 from testtools import matchers
 
 from tempest.api.compute import base
-from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
@@ -27,6 +26,11 @@
 
 class VolumesGetTestJSON(base.BaseV2ComputeTest):
 
+    # These tests will fail with a 404 starting from microversion 2.36. For
+    # more information, see:
+    # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated
+    max_microversion = '2.35'
+
     @classmethod
     def skip_checks(cls):
         super(VolumesGetTestJSON, cls).skip_checks()
@@ -37,7 +41,7 @@
     @classmethod
     def setup_clients(cls):
         super(VolumesGetTestJSON, cls).setup_clients()
-        cls.client = cls.volumes_extensions_client
+        cls.volumes_client = cls.volumes_extensions_client
 
     @decorators.idempotent_id('f10f25eb-9775-4d9d-9cbe-1cf54dae9d5f')
     def test_volume_create_get_delete(self):
@@ -45,22 +49,19 @@
         v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
         metadata = {'Type': 'work'}
         # Create volume
-        volume = self.client.create_volume(size=CONF.volume.volume_size,
-                                           display_name=v_name,
-                                           metadata=metadata)['volume']
+        volume = self.create_volume(size=CONF.volume.volume_size,
+                                    display_name=v_name,
+                                    metadata=metadata)
         self.assertIn('id', volume)
-        self.addCleanup(self.delete_volume, volume['id'])
         self.assertIn('displayName', volume)
         self.assertEqual(volume['displayName'], v_name,
                          "The created volume name is not equal "
                          "to the requested name")
         self.assertIsNotNone(volume['id'],
                              "Field volume id is empty or not found.")
-        # Wait for Volume status to become ACTIVE
-        waiters.wait_for_volume_resource_status(self.client, volume['id'],
-                                                'available')
         # GET Volume
-        fetched_volume = self.client.show_volume(volume['id'])['volume']
+        fetched_volume = self.volumes_client.show_volume(
+            volume['id'])['volume']
         # Verification of details of fetched Volume
         self.assertEqual(v_name,
                          fetched_volume['displayName'],
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index 0d8214f..b2aebe7 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -27,6 +27,11 @@
     # If you are running a Devstack environment, ensure that the
     # VOLUME_BACKING_FILE_SIZE is at least 4G in your localrc
 
+    # These tests will fail with a 404 starting from microversion 2.36. For
+    # more information, see:
+    # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated
+    max_microversion = '2.35'
+
     @classmethod
     def skip_checks(cls):
         super(VolumesTestJSON, cls).skip_checks()
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
index 80db1be..87f7d8a 100644
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -24,6 +24,11 @@
 
 class VolumesNegativeTest(base.BaseV2ComputeTest):
 
+    # These tests will fail with a 404 starting from microversion 2.36. For
+    # more information, see:
+    # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated
+    max_microversion = '2.35'
+
     @classmethod
     def skip_checks(cls):
         super(VolumesNegativeTest, cls).skip_checks()
diff --git a/tempest/api/identity/admin/v2/test_endpoints.py b/tempest/api/identity/admin/v2/test_endpoints.py
index db32f5a..59fc4d8 100644
--- a/tempest/api/identity/admin/v2/test_endpoints.py
+++ b/tempest/api/identity/admin/v2/test_endpoints.py
@@ -62,7 +62,7 @@
         # Asserting LIST endpoints
         missing_endpoints =\
             [e for e in self.setup_endpoints if e not in fetched_endpoints]
-        self.assertEqual(0, len(missing_endpoints),
+        self.assertEmpty(missing_endpoints,
                          "Failed to find endpoint %s in fetched list" %
                          ', '.join(str(e) for e in missing_endpoints))
 
diff --git a/tempest/api/identity/admin/v2/test_roles_negative.py b/tempest/api/identity/admin/v2/test_roles_negative.py
index 86d06e2..f3b7494 100644
--- a/tempest/api/identity/admin/v2/test_roles_negative.py
+++ b/tempest/api/identity/admin/v2/test_roles_negative.py
@@ -143,7 +143,7 @@
     @decorators.idempotent_id('99b297f6-2b5d-47c7-97a9-8b6bb4f91042')
     def test_assign_user_role_for_non_existent_role(self):
         # Attempt to assign a non existent role to user should fail
-        (user, tenant, role) = self._get_role_params()
+        (user, tenant, _) = self._get_role_params()
         non_existent_role = data_utils.rand_uuid_hex()
         self.assertRaises(lib_exc.NotFound,
                           self.roles_client.create_user_role_on_project,
@@ -153,7 +153,7 @@
     @decorators.idempotent_id('b2285aaa-9e76-4704-93a9-7a8acd0a6c8f')
     def test_assign_user_role_for_non_existent_tenant(self):
         # Attempt to assign a role on a non existent tenant should fail
-        (user, tenant, role) = self._get_role_params()
+        (user, _, role) = self._get_role_params()
         non_existent_tenant = data_utils.rand_uuid_hex()
         self.assertRaises(lib_exc.NotFound,
                           self.roles_client.create_user_role_on_project,
@@ -244,7 +244,7 @@
     @decorators.idempotent_id('682adfb2-fd5f-4b0a-a9ca-322e9bebb907')
     def test_list_user_roles_request_without_token(self):
         # Request to list user's roles without a valid token should fail
-        (user, tenant, role) = self._get_role_params()
+        (user, tenant, _) = self._get_role_params()
         token = self.client.auth_provider.get_token()
         self.client.delete_token(token)
         try:
diff --git a/tempest/api/identity/admin/v2/test_users.py b/tempest/api/identity/admin/v2/test_users.py
index 2711a2d..0d98af5 100644
--- a/tempest/api/identity/admin/v2/test_users.py
+++ b/tempest/api/identity/admin/v2/test_users.py
@@ -141,7 +141,7 @@
         # verifying the user Id in the list
         missing_users =\
             [user for user in user_ids if user not in fetched_user_ids]
-        self.assertEqual(0, len(missing_users),
+        self.assertEmpty(missing_users,
                          "Failed to find user %s in fetched list" %
                          ', '.join(m_user for m_user in missing_users))
 
@@ -169,7 +169,7 @@
         # verifying the user Id in the list
         missing_users = [missing_user for missing_user in user_ids
                          if missing_user not in fetched_user_ids]
-        self.assertEqual(0, len(missing_users),
+        self.assertEmpty(missing_users,
                          "Failed to find user %s in fetched list" %
                          ', '.join(m_user for m_user in missing_users))
 
diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py
index 75e877a..15b2008 100644
--- a/tempest/api/identity/admin/v3/test_credentials.py
+++ b/tempest/api/identity/admin/v3/test_credentials.py
@@ -107,6 +107,6 @@
             fetched_cred_ids.append(i['id'])
         missing_creds = [c for c in created_cred_ids
                          if c not in fetched_cred_ids]
-        self.assertEqual(0, len(missing_creds),
+        self.assertEmpty(missing_creds,
                          "Failed to find cred %s in fetched list" %
                          ', '.join(m_cred for m_cred in missing_creds))
diff --git a/tempest/api/identity/admin/v3/test_default_project_id.py b/tempest/api/identity/admin/v3/test_default_project_id.py
index ac2faa9..302a0e5 100644
--- a/tempest/api/identity/admin/v3/test_default_project_id.py
+++ b/tempest/api/identity/admin/v3/test_default_project_id.py
@@ -79,7 +79,7 @@
         admin_client = clients.Manager(credentials=creds)
 
         # verify the user's token and see that it is scoped to the project
-        token, auth_data = admin_client.auth_provider.get_auth()
+        token, _ = admin_client.auth_provider.get_auth()
         result = admin_client.identity_v3_client.show_token(token)['token']
         self.assertEqual(result['project']['domain']['id'], dom_id)
         self.assertEqual(result['project']['id'], proj_id)
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index cddba53..9fe978c 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -57,7 +57,7 @@
             fetched_ids.append(d['id'])
         missing_doms = [d for d in self.setup_domains
                         if d['id'] not in fetched_ids]
-        self.assertEqual(0, len(missing_doms))
+        self.assertEmpty(missing_doms)
 
     @decorators.idempotent_id('c6aee07b-4981-440c-bb0b-eb598f58ffe9')
     def test_list_domains_filter_by_name(self):
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index 09f92e2..b1ae2aa 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -64,7 +64,7 @@
         # Asserting LIST endpoints
         missing_endpoints =\
             [e for e in self.setup_endpoints if e not in fetched_endpoints]
-        self.assertEqual(0, len(missing_endpoints),
+        self.assertEmpty(missing_endpoints,
                          "Failed to find endpoint %s in fetched list" %
                          ', '.join(str(e) for e in missing_endpoints))
 
diff --git a/tempest/api/identity/admin/v3/test_list_users.py b/tempest/api/identity/admin/v3/test_list_users.py
index bcbf6b6..47a3580 100644
--- a/tempest/api/identity/admin/v3/test_list_users.py
+++ b/tempest/api/identity/admin/v3/test_list_users.py
@@ -93,7 +93,7 @@
         fetched_ids = [u['id'] for u in body]
         missing_users = [u['id'] for u in self.users
                          if u['id'] not in fetched_ids]
-        self.assertEqual(0, len(missing_users),
+        self.assertEmpty(missing_users,
                          "Failed to find user %s in fetched list" %
                          ', '.join(m_user for m_user in missing_users))
 
diff --git a/tempest/api/identity/admin/v3/test_oauth_consumers.py b/tempest/api/identity/admin/v3/test_oauth_consumers.py
index f06fb8f..970ead3 100644
--- a/tempest/api/identity/admin/v3/test_oauth_consumers.py
+++ b/tempest/api/identity/admin/v3/test_oauth_consumers.py
@@ -14,7 +14,7 @@
 #    under the License.
 
 from tempest.api.identity import base
-from tempest.common.utils import data_utils
+from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as exceptions
diff --git a/tempest/api/identity/admin/v3/test_policies.py b/tempest/api/identity/admin/v3/test_policies.py
index 730d469..960e2cb 100644
--- a/tempest/api/identity/admin/v3/test_policies.py
+++ b/tempest/api/identity/admin/v3/test_policies.py
@@ -41,7 +41,7 @@
         for p in body:
             fetched_ids.append(p['id'])
         missing_pols = [p for p in policy_ids if p not in fetched_ids]
-        self.assertEqual(0, len(missing_pols))
+        self.assertEmpty(missing_pols)
 
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('e544703a-2f03-4cf2-9b0f-350782fdb0d3')
diff --git a/tempest/api/identity/admin/v3/test_regions.py b/tempest/api/identity/admin/v3/test_regions.py
index ac550a7..d00e408 100644
--- a/tempest/api/identity/admin/v3/test_regions.py
+++ b/tempest/api/identity/admin/v3/test_regions.py
@@ -98,7 +98,7 @@
         missing_regions =\
             [e for e in self.setup_regions if e not in fetched_regions]
         # Asserting List Regions response
-        self.assertEqual(0, len(missing_regions),
+        self.assertEmpty(missing_regions,
                          "Failed to find region %s in fetched list" %
                          ', '.join(str(e) for e in missing_regions))
 
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index 8c5e63b..1acc67d 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -145,7 +145,7 @@
 
     @decorators.idempotent_id('08ed85ce-2ba8-4864-b442-bcc61f16ae89')
     def test_get_available_project_scopes(self):
-        manager_project_id = self.manager.credentials.project_id
+        manager_project_id = self.os_primary.credentials.project_id
         admin_user_id = self.os_admin.credentials.user_id
         admin_role_id = self.get_role_by_name(CONF.identity.admin_role)['id']
 
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index 751962f..409d4f8 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -131,7 +131,7 @@
         missing_projects =\
             [p for p in assigned_project_ids
              if p not in fetched_project_ids]
-        self.assertEqual(0, len(missing_projects),
+        self.assertEmpty(missing_projects,
                          "Failed to find project %s in fetched list" %
                          ', '.join(m_project for m_project
                                    in missing_projects))
diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py
index c9d7a4d..042c821 100644
--- a/tempest/api/identity/v3/test_tokens.py
+++ b/tempest/api/identity/v3/test_tokens.py
@@ -54,15 +54,13 @@
             self.assertEqual(subject_id, user_id)
         else:
             # Expect a user ID, but don't know what it will be.
-            self.assertGreaterEqual(len(subject_id), 0,
-                                    'Expected user ID in token.')
+            self.assertIsNotNone(subject_id, 'Expected user ID in token.')
 
         subject_name = resp['user']['name']
         if username:
             self.assertEqual(subject_name, username)
         else:
             # Expect a user name, but don't know what it will be.
-            self.assertGreaterEqual(len(subject_name), 0,
-                                    'Expected user name in token.')
+            self.assertIsNotNone(subject_name, 'Expected user name in token.')
 
         self.assertEqual(resp['methods'][0], 'password')
diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py
index 4902316..bf2e510 100644
--- a/tempest/api/image/v1/test_image_members.py
+++ b/tempest/api/image/v1/test_image_members.py
@@ -54,6 +54,6 @@
                                                      self.alt_tenant_id)
         body = self.image_member_client.list_image_members(image_id)
         members = body['members']
-        self.assertEqual(0, len(members), str(members))
+        self.assertEmpty(members)
         self.assertRaises(
             lib_exc.NotFound, self.alt_img_cli.show_image, image_id)
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index b341ab7..76723f4 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -43,7 +43,8 @@
         else:
             msg = ("The container format and the disk format don't match. "
                    "Container format: %(container)s, Disk format: %(disk)s." %
-                   {'container': container_format, 'disk': disk_format})
+                   {'container': container_format, 'disk':
+                       CONF.image.disk_formats})
             raise exceptions.InvalidConfiguration(msg)
     else:
         disk_format = CONF.image.disk_formats[0]
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
index 6389489..7304db9 100644
--- a/tempest/api/network/admin/test_agent_management.py
+++ b/tempest/api/network/admin/test_agent_management.py
@@ -49,7 +49,7 @@
     @decorators.idempotent_id('e335be47-b9a1-46fd-be30-0874c0b751e6')
     def test_list_agents_non_admin(self):
         body = self.agents_client.list_agents()
-        self.assertEqual(len(body["agents"]), 0)
+        self.assertEmpty(body["agents"])
 
     @decorators.idempotent_id('869bc8e8-0fda-4a30-9b71-f8a7cf58ca9f')
     def test_show_agent(self):
diff --git a/tempest/api/network/admin/test_external_network_extension.py b/tempest/api/network/admin/test_external_network_extension.py
index c83dd7f..4d41e33 100644
--- a/tempest/api/network/admin/test_external_network_extension.py
+++ b/tempest/api/network/admin/test_external_network_extension.py
@@ -10,11 +10,16 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 from tempest.api.network import base
+from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
+CONF = config.CONF
+
 
 class ExternalNetworksTestJSON(base.BaseAdminNetworkTest):
 
@@ -91,6 +96,8 @@
         self.assertFalse(show_net['router:external'])
 
     @decorators.idempotent_id('82068503-2cf2-4ed4-b3be-ecb89432e4bb')
+    @testtools.skipUnless(CONF.network_feature_enabled.floating_ips,
+                          'Floating ips are not availabled')
     def test_delete_external_networks_with_floating_ip(self):
         # Verifies external network can be deleted while still holding
         # (unassociated) floating IPs
diff --git a/tempest/api/network/admin/test_floating_ips_admin_actions.py b/tempest/api/network/admin/test_floating_ips_admin_actions.py
index 11f520a..7ee819e 100644
--- a/tempest/api/network/admin/test_floating_ips_admin_actions.py
+++ b/tempest/api/network/admin/test_floating_ips_admin_actions.py
@@ -34,6 +34,8 @@
         if not CONF.network.public_network_id:
             msg = "The public_network_id option must be specified."
             raise cls.skipException(msg)
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
 
     @classmethod
     def setup_clients(cls):
diff --git a/tempest/api/network/admin/test_metering_extensions.py b/tempest/api/network/admin/test_metering_extensions.py
index 3f94868..21a7ab4 100644
--- a/tempest/api/network/admin/test_metering_extensions.py
+++ b/tempest/api/network/admin/test_metering_extensions.py
@@ -74,7 +74,7 @@
         # Asserting that the label is not found in list after deletion
         labels = self.admin_metering_labels_client.list_metering_labels(
             id=metering_label_id)
-        self.assertEqual(len(labels['metering_labels']), 0)
+        self.assertEmpty(labels['metering_labels'])
 
     def _delete_metering_label_rule(self, metering_label_rule_id):
         client = self.admin_metering_label_rules_client
@@ -89,7 +89,7 @@
         # Verify label filtering
         body = self.admin_metering_labels_client.list_metering_labels(id=33)
         metering_labels = body['metering_labels']
-        self.assertEqual(0, len(metering_labels))
+        self.assertEmpty(metering_labels)
 
     @decorators.idempotent_id('ec8e15ff-95d0-433b-b8a6-b466bddb1e50')
     def test_create_delete_metering_label_with_filters(self):
@@ -126,7 +126,7 @@
         # Verify rule filtering
         body = client.list_metering_label_rules(id=33)
         metering_label_rules = body['metering_label_rules']
-        self.assertEqual(0, len(metering_label_rules))
+        self.assertEmpty(metering_label_rules)
 
     @decorators.idempotent_id('f4d547cd-3aee-408f-bf36-454f8825e045')
     def test_create_delete_metering_label_rule_with_filters(self):
diff --git a/tempest/api/network/admin/test_routers.py b/tempest/api/network/admin/test_routers.py
new file mode 100644
index 0000000..07c4157
--- /dev/null
+++ b/tempest/api/network/admin/test_routers.py
@@ -0,0 +1,231 @@
+# Copyright 2013 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import testtools
+
+from tempest.api.network import base
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest import test
+
+CONF = config.CONF
+
+
+class RoutersAdminTest(base.BaseAdminNetworkTest):
+    # NOTE(salv-orlando): This class inherits from BaseAdminNetworkTest
+    # as some router operations, such as enabling or disabling SNAT
+    # require admin credentials by default
+
+    def _cleanup_router(self, router):
+        self.delete_router(router)
+        self.routers.remove(router)
+
+    def _create_router(self, name=None, 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 _add_router_interface_with_subnet_id(self, router_id, subnet_id):
+        interface = self.routers_client.add_router_interface(
+            router_id, subnet_id=subnet_id)
+        self.addCleanup(self._remove_router_interface_with_subnet_id,
+                        router_id, subnet_id)
+        self.assertEqual(subnet_id, interface['subnet_id'])
+        return interface
+
+    def _remove_router_interface_with_subnet_id(self, router_id, subnet_id):
+        body = self.routers_client.remove_router_interface(router_id,
+                                                           subnet_id=subnet_id)
+        self.assertEqual(subnet_id, body['subnet_id'])
+
+    @classmethod
+    def skip_checks(cls):
+        super(RoutersAdminTest, cls).skip_checks()
+        if not test.is_extension_enabled('router', 'network'):
+            msg = "router extension not enabled."
+            raise cls.skipException(msg)
+
+    @classmethod
+    def resource_setup(cls):
+        super(RoutersAdminTest, cls).resource_setup()
+        cls.tenant_cidr = (CONF.network.project_network_cidr
+                           if cls._ip_version == 4 else
+                           CONF.network.project_network_v6_cidr)
+
+    @decorators.idempotent_id('e54dd3a3-4352-4921-b09d-44369ae17397')
+    def test_create_router_setting_project_id(self):
+        # Test creating router from admin user setting project_id.
+        project = data_utils.rand_name('test_tenant_')
+        description = data_utils.rand_name('desc_')
+        project = self.identity_utils.create_project(name=project,
+                                                     description=description)
+        project_id = project['id']
+        self.addCleanup(self.identity_utils.delete_project, project_id)
+
+        name = data_utils.rand_name('router-')
+        create_body = self.admin_routers_client.create_router(
+            name=name, tenant_id=project_id)
+        self.addCleanup(self.admin_routers_client.delete_router,
+                        create_body['router']['id'])
+        self.assertEqual(project_id, create_body['router']['tenant_id'])
+
+    @decorators.idempotent_id('847257cc-6afd-4154-b8fb-af49f5670ce8')
+    @test.requires_ext(extension='ext-gw-mode', service='network')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
+    def test_create_router_with_default_snat_value(self):
+        # Create a router with default snat rule
+        router = self._create_router(
+            external_network_id=CONF.network.public_network_id)
+        self._verify_router_gateway(
+            router['id'], {'network_id': CONF.network.public_network_id,
+                           'enable_snat': True})
+
+    @decorators.idempotent_id('ea74068d-09e9-4fd7-8995-9b6a1ace920f')
+    @test.requires_ext(extension='ext-gw-mode', service='network')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
+    def test_create_router_with_snat_explicit(self):
+        name = data_utils.rand_name('snat-router')
+        # Create a router enabling snat attributes
+        enable_snat_states = [False, True]
+        for enable_snat in enable_snat_states:
+            external_gateway_info = {
+                'network_id': CONF.network.public_network_id,
+                'enable_snat': enable_snat}
+            create_body = self.admin_routers_client.create_router(
+                name=name, external_gateway_info=external_gateway_info)
+            self.addCleanup(self.admin_routers_client.delete_router,
+                            create_body['router']['id'])
+            # Verify snat attributes after router creation
+            self._verify_router_gateway(create_body['router']['id'],
+                                        exp_ext_gw_info=external_gateway_info)
+
+    def _verify_router_gateway(self, router_id, exp_ext_gw_info=None):
+        show_body = self.admin_routers_client.show_router(router_id)
+        actual_ext_gw_info = show_body['router']['external_gateway_info']
+        if exp_ext_gw_info is None:
+            self.assertIsNone(actual_ext_gw_info)
+            return
+        # Verify only keys passed in exp_ext_gw_info
+        for k, v in exp_ext_gw_info.items():
+            self.assertEqual(v, actual_ext_gw_info[k])
+
+    def _verify_gateway_port(self, router_id):
+        list_body = self.admin_ports_client.list_ports(
+            network_id=CONF.network.public_network_id,
+            device_id=router_id)
+        self.assertEqual(len(list_body['ports']), 1)
+        gw_port = list_body['ports'][0]
+        fixed_ips = gw_port['fixed_ips']
+        self.assertNotEmpty(fixed_ips)
+        # Assert that all of the IPs from the router gateway port
+        # are allocated from a valid public subnet.
+        public_net_body = self.admin_networks_client.show_network(
+            CONF.network.public_network_id)
+        public_subnet_ids = public_net_body['network']['subnets']
+        for fixed_ip in fixed_ips:
+            subnet_id = fixed_ip['subnet_id']
+            self.assertIn(subnet_id, public_subnet_ids)
+
+    @decorators.idempotent_id('6cc285d8-46bf-4f36-9b1a-783e3008ba79')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
+    def test_update_router_set_gateway(self):
+        router = self._create_router()
+        self.routers_client.update_router(
+            router['id'],
+            external_gateway_info={
+                'network_id': CONF.network.public_network_id})
+        # Verify operation - router
+        self._verify_router_gateway(
+            router['id'],
+            {'network_id': CONF.network.public_network_id})
+        self._verify_gateway_port(router['id'])
+
+    @decorators.idempotent_id('b386c111-3b21-466d-880c-5e72b01e1a33')
+    @test.requires_ext(extension='ext-gw-mode', service='network')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
+    def test_update_router_set_gateway_with_snat_explicit(self):
+        router = self._create_router()
+        self.admin_routers_client.update_router(
+            router['id'],
+            external_gateway_info={
+                'network_id': CONF.network.public_network_id,
+                'enable_snat': True})
+        self._verify_router_gateway(
+            router['id'],
+            {'network_id': CONF.network.public_network_id,
+             'enable_snat': True})
+        self._verify_gateway_port(router['id'])
+
+    @decorators.idempotent_id('96536bc7-8262-4fb2-9967-5c46940fa279')
+    @test.requires_ext(extension='ext-gw-mode', service='network')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
+    def test_update_router_set_gateway_without_snat(self):
+        router = self._create_router()
+        self.admin_routers_client.update_router(
+            router['id'],
+            external_gateway_info={
+                'network_id': CONF.network.public_network_id,
+                'enable_snat': False})
+        self._verify_router_gateway(
+            router['id'],
+            {'network_id': CONF.network.public_network_id,
+             'enable_snat': False})
+        self._verify_gateway_port(router['id'])
+
+    @decorators.idempotent_id('ad81b7ee-4f81-407b-a19c-17e623f763e8')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
+    def test_update_router_unset_gateway(self):
+        router = self._create_router(
+            external_network_id=CONF.network.public_network_id)
+        self.routers_client.update_router(router['id'],
+                                          external_gateway_info={})
+        self._verify_router_gateway(router['id'])
+        # No gateway port expected
+        list_body = self.admin_ports_client.list_ports(
+            network_id=CONF.network.public_network_id,
+            device_id=router['id'])
+        self.assertFalse(list_body['ports'])
+
+    @decorators.idempotent_id('f2faf994-97f4-410b-a831-9bc977b64374')
+    @test.requires_ext(extension='ext-gw-mode', service='network')
+    @testtools.skipUnless(CONF.network.public_network_id,
+                          'The public_network_id option must be specified.')
+    def test_update_router_reset_gateway_without_snat(self):
+        router = self._create_router(
+            external_network_id=CONF.network.public_network_id)
+        self.admin_routers_client.update_router(
+            router['id'],
+            external_gateway_info={
+                'network_id': CONF.network.public_network_id,
+                'enable_snat': False})
+        self._verify_router_gateway(
+            router['id'],
+            {'network_id': CONF.network.public_network_id,
+             'enable_snat': False})
+        self._verify_gateway_port(router['id'])
+
+
+class RoutersIpV6AdminTest(RoutersAdminTest):
+    _ip_version = 6
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 8775495..6bec0d7 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -83,6 +83,7 @@
             cls.os_primary.security_group_rules_client)
         cls.network_versions_client = cls.os_primary.network_versions_client
         cls.service_providers_client = cls.os_primary.service_providers_client
+        cls.tags_client = cls.os_primary.tags_client
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index f0f92ac..c799b15 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -49,6 +49,8 @@
         if not CONF.network.public_network_id:
             msg = "The public_network_id option must be specified."
             raise cls.skipException(msg)
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/api/network/test_floating_ips_negative.py b/tempest/api/network/test_floating_ips_negative.py
index f5830ab..5ca17fe 100644
--- a/tempest/api/network/test_floating_ips_negative.py
+++ b/tempest/api/network/test_floating_ips_negative.py
@@ -40,6 +40,8 @@
         if not CONF.network.public_network_id:
             msg = "The public_network_id option must be specified."
             raise cls.skipException(msg)
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 0466d3a..128544b 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -25,10 +25,7 @@
 CONF = config.CONF
 
 
-class RoutersTest(base.BaseAdminNetworkTest):
-    # NOTE(salv-orlando): This class inherits from BaseAdminNetworkTest
-    # as some router operations, such as enabling or disabling SNAT
-    # require admin credentials by default
+class RoutersTest(base.BaseNetworkTest):
 
     def _cleanup_router(self, router):
         self.delete_router(router)
@@ -101,55 +98,6 @@
             router['id'])['router']
         self.assertEqual(router_show['name'], updated_name)
 
-    @decorators.idempotent_id('e54dd3a3-4352-4921-b09d-44369ae17397')
-    def test_create_router_setting_project_id(self):
-        # Test creating router from admin user setting project_id.
-        project = data_utils.rand_name('test_tenant_')
-        description = data_utils.rand_name('desc_')
-        project = self.identity_utils.create_project(name=project,
-                                                     description=description)
-        project_id = project['id']
-        self.addCleanup(self.identity_utils.delete_project, project_id)
-
-        name = data_utils.rand_name('router-')
-        create_body = self.admin_routers_client.create_router(
-            name=name, tenant_id=project_id)
-        self.addCleanup(self.admin_routers_client.delete_router,
-                        create_body['router']['id'])
-        self.assertEqual(project_id, create_body['router']['tenant_id'])
-
-    @decorators.idempotent_id('847257cc-6afd-4154-b8fb-af49f5670ce8')
-    @test.requires_ext(extension='ext-gw-mode', service='network')
-    @testtools.skipUnless(CONF.network.public_network_id,
-                          'The public_network_id option must be specified.')
-    def test_create_router_with_default_snat_value(self):
-        # Create a router with default snat rule
-        router = self._create_router(
-            external_network_id=CONF.network.public_network_id)
-        self._verify_router_gateway(
-            router['id'], {'network_id': CONF.network.public_network_id,
-                           'enable_snat': True})
-
-    @decorators.idempotent_id('ea74068d-09e9-4fd7-8995-9b6a1ace920f')
-    @test.requires_ext(extension='ext-gw-mode', service='network')
-    @testtools.skipUnless(CONF.network.public_network_id,
-                          'The public_network_id option must be specified.')
-    def test_create_router_with_snat_explicit(self):
-        name = data_utils.rand_name('snat-router')
-        # Create a router enabling snat attributes
-        enable_snat_states = [False, True]
-        for enable_snat in enable_snat_states:
-            external_gateway_info = {
-                'network_id': CONF.network.public_network_id,
-                'enable_snat': enable_snat}
-            create_body = self.admin_routers_client.create_router(
-                name=name, external_gateway_info=external_gateway_info)
-            self.addCleanup(self.admin_routers_client.delete_router,
-                            create_body['router']['id'])
-            # Verify snat attributes after router creation
-            self._verify_router_gateway(create_body['router']['id'],
-                                        exp_ext_gw_info=external_gateway_info)
-
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('b42e6e39-2e37-49cc-a6f4-8467e940900a')
     def test_add_remove_router_interface_with_subnet_id(self):
@@ -208,7 +156,7 @@
         self.assertEqual(len(list_body['ports']), 1)
         gw_port = list_body['ports'][0]
         fixed_ips = gw_port['fixed_ips']
-        self.assertGreaterEqual(len(fixed_ips), 1)
+        self.assertNotEmpty(fixed_ips)
         # Assert that all of the IPs from the router gateway port
         # are allocated from a valid public subnet.
         public_net_body = self.admin_networks_client.show_network(
@@ -218,55 +166,6 @@
             subnet_id = fixed_ip['subnet_id']
             self.assertIn(subnet_id, public_subnet_ids)
 
-    @decorators.idempotent_id('6cc285d8-46bf-4f36-9b1a-783e3008ba79')
-    @testtools.skipUnless(CONF.network.public_network_id,
-                          'The public_network_id option must be specified.')
-    def test_update_router_set_gateway(self):
-        router = self._create_router()
-        self.routers_client.update_router(
-            router['id'],
-            external_gateway_info={
-                'network_id': CONF.network.public_network_id})
-        # Verify operation - router
-        self._verify_router_gateway(
-            router['id'],
-            {'network_id': CONF.network.public_network_id})
-        self._verify_gateway_port(router['id'])
-
-    @decorators.idempotent_id('b386c111-3b21-466d-880c-5e72b01e1a33')
-    @test.requires_ext(extension='ext-gw-mode', service='network')
-    @testtools.skipUnless(CONF.network.public_network_id,
-                          'The public_network_id option must be specified.')
-    def test_update_router_set_gateway_with_snat_explicit(self):
-        router = self._create_router()
-        self.admin_routers_client.update_router(
-            router['id'],
-            external_gateway_info={
-                'network_id': CONF.network.public_network_id,
-                'enable_snat': True})
-        self._verify_router_gateway(
-            router['id'],
-            {'network_id': CONF.network.public_network_id,
-             'enable_snat': True})
-        self._verify_gateway_port(router['id'])
-
-    @decorators.idempotent_id('96536bc7-8262-4fb2-9967-5c46940fa279')
-    @test.requires_ext(extension='ext-gw-mode', service='network')
-    @testtools.skipUnless(CONF.network.public_network_id,
-                          'The public_network_id option must be specified.')
-    def test_update_router_set_gateway_without_snat(self):
-        router = self._create_router()
-        self.admin_routers_client.update_router(
-            router['id'],
-            external_gateway_info={
-                'network_id': CONF.network.public_network_id,
-                'enable_snat': False})
-        self._verify_router_gateway(
-            router['id'],
-            {'network_id': CONF.network.public_network_id,
-             'enable_snat': False})
-        self._verify_gateway_port(router['id'])
-
     @decorators.idempotent_id('cbe42f84-04c2-11e7-8adb-fa163e4fa634')
     @test.requires_ext(extension='ext-gw-mode', service='network')
     @testtools.skipUnless(CONF.network.public_network_id,
@@ -298,39 +197,6 @@
                          'external_fixed_ips'][0]['ip_address'],
                          fixed_ip['ip_address'])
 
-    @decorators.idempotent_id('ad81b7ee-4f81-407b-a19c-17e623f763e8')
-    @testtools.skipUnless(CONF.network.public_network_id,
-                          'The public_network_id option must be specified.')
-    def test_update_router_unset_gateway(self):
-        router = self._create_router(
-            external_network_id=CONF.network.public_network_id)
-        self.routers_client.update_router(router['id'],
-                                          external_gateway_info={})
-        self._verify_router_gateway(router['id'])
-        # No gateway port expected
-        list_body = self.admin_ports_client.list_ports(
-            network_id=CONF.network.public_network_id,
-            device_id=router['id'])
-        self.assertFalse(list_body['ports'])
-
-    @decorators.idempotent_id('f2faf994-97f4-410b-a831-9bc977b64374')
-    @test.requires_ext(extension='ext-gw-mode', service='network')
-    @testtools.skipUnless(CONF.network.public_network_id,
-                          'The public_network_id option must be specified.')
-    def test_update_router_reset_gateway_without_snat(self):
-        router = self._create_router(
-            external_network_id=CONF.network.public_network_id)
-        self.admin_routers_client.update_router(
-            router['id'],
-            external_gateway_info={
-                'network_id': CONF.network.public_network_id,
-                'enable_snat': False})
-        self._verify_router_gateway(
-            router['id'],
-            {'network_id': CONF.network.public_network_id,
-             'enable_snat': False})
-        self._verify_gateway_port(router['id'])
-
     @decorators.idempotent_id('c86ac3a8-50bd-4b00-a6b8-62af84a0765c')
     @test.requires_ext(extension='extraroute', service='network')
     def test_update_delete_extra_route(self):
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 0d5e230..a121864 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -83,7 +83,7 @@
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('bfd128e5-3c92-44b6-9d66-7fe29d22c802')
     def test_create_list_update_show_delete_security_group(self):
-        group_create_body, name = self._create_security_group()
+        group_create_body, _ = self._create_security_group()
 
         # List security groups and verify if created group is there in response
         list_body = self.security_groups_client.list_security_groups()
diff --git a/tempest/api/network/test_tags.py b/tempest/api/network/test_tags.py
new file mode 100644
index 0000000..1f3a7c4
--- /dev/null
+++ b/tempest/api/network/test_tags.py
@@ -0,0 +1,90 @@
+# Copyright 2017 AT&T 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.
+
+from tempest.api.network import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from tempest import test
+
+
+class TagsTest(base.BaseNetworkTest):
+    """Tests the following operations in the tags API:
+
+        Update all tags.
+        Delete all tags.
+        Check tag existence.
+        Create a tag.
+        List tags.
+        Remove a tag.
+
+    v2.0 of the Neutron API is assumed. The tag extension allows users to set
+    tags on their networks. The extension supports networks only.
+    """
+
+    @classmethod
+    def skip_checks(cls):
+        super(TagsTest, cls).skip_checks()
+        if not test.is_extension_enabled('tag', 'network'):
+            msg = "tag extension not enabled."
+            raise cls.skipException(msg)
+
+    @classmethod
+    def resource_setup(cls):
+        super(TagsTest, cls).resource_setup()
+        cls.network = cls.create_network()
+
+    @decorators.idempotent_id('ee76bfaf-ac94-4d74-9ecc-4bbd4c583cb1')
+    def test_create_list_show_update_delete_tags(self):
+        # Validate that creating a tag on a network resource works.
+        tag_name = data_utils.rand_name(self.__class__.__name__ + '-Tag')
+        self.tags_client.create_tag('networks', self.network['id'], tag_name)
+        self.addCleanup(self.tags_client.delete_all_tags, 'networks',
+                        self.network['id'])
+        self.tags_client.check_tag_existence('networks', self.network['id'],
+                                             tag_name)
+
+        # Validate that listing tags on a network resource works.
+        retrieved_tags = self.tags_client.list_tags(
+            'networks', self.network['id'])['tags']
+        self.assertEqual([tag_name], retrieved_tags)
+
+        # Generate 3 new tag names.
+        replace_tags = [data_utils.rand_name(
+            self.__class__.__name__ + '-Tag') for _ in range(3)]
+
+        # Replace the current tag with the 3 new tags and validate that the
+        # network resource has the 3 new tags.
+        updated_tags = self.tags_client.update_all_tags(
+            'networks', self.network['id'], replace_tags)['tags']
+        self.assertEqual(3, len(updated_tags))
+        self.assertEqual(set(replace_tags), set(updated_tags))
+
+        # Delete the first tag and check that it has been removed.
+        self.tags_client.delete_tag(
+            'networks', self.network['id'], replace_tags[0])
+        self.assertRaises(lib_exc.NotFound,
+                          self.tags_client.check_tag_existence, 'networks',
+                          self.network['id'], replace_tags[0])
+        for i in range(1, 3):
+            self.tags_client.check_tag_existence(
+                'networks', self.network['id'], replace_tags[i])
+
+        # Delete all the remaining tags and check that they have been removed.
+        self.tags_client.delete_all_tags('networks', self.network['id'])
+        for i in range(1, 3):
+            self.assertRaises(lib_exc.NotFound,
+                              self.tags_client.check_tag_existence, 'networks',
+                              self.network['id'], replace_tags[i])
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 2bac8d3..13614cb 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -43,8 +43,7 @@
     for cont in containers:
         try:
             params = {'limit': 9999, 'format': 'json'}
-            resp, objlist = container_client.list_container_contents(
-                cont, params)
+            _, objlist = container_client.list_container_contents(cont, params)
             # delete every object in the container
             for obj in objlist:
                 test_utils.call_and_ignore_notfound_exc(
diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py
index 0a72d75..e765414 100644
--- a/tempest/api/object_storage/test_account_bulk.py
+++ b/tempest/api/object_storage/test_account_bulk.py
@@ -112,7 +112,7 @@
         self._upload_archive(filepath)
 
         data = '%s/%s\n%s' % (container_name, object_name, container_name)
-        resp, body = self.bulk_client.delete_bulk_data(data=data)
+        resp, _ = self.bulk_client.delete_bulk_data(data=data)
 
         # When deleting multiple files using the bulk operation, the response
         # does not contain 'content-length' header. This is the special case,
@@ -138,7 +138,7 @@
 
         data = '%s/%s\n%s' % (container_name, object_name, container_name)
 
-        resp, body = self.bulk_client.delete_bulk_data_with_post(data=data)
+        resp, _ = self.bulk_client.delete_bulk_data_with_post(data=data)
 
         # When deleting multiple files using the bulk operation, the response
         # does not contain 'content-length' header. This is the special case,
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index e54b6e7..9e62046 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -101,7 +101,7 @@
         # Check only the format of common headers with custom matcher
         self.assertThat(resp, custom_matchers.AreAllWellFormatted())
 
-        self.assertEqual(len(container_list), 0)
+        self.assertEmpty(container_list)
 
     @decorators.idempotent_id('1c7efa35-e8a2-4b0b-b5ff-862c7fd83704')
     def test_list_containers_with_format_json(self):
@@ -135,7 +135,7 @@
         not CONF.object_storage_feature_enabled.discoverability,
         'Discoverability function is disabled')
     def test_list_extensions(self):
-        resp, extensions = self.capabilities_client.list_capabilities()
+        resp, _ = self.capabilities_client.list_capabilities()
 
         self.assertThat(resp, custom_matchers.AreAllWellFormatted())
 
@@ -162,7 +162,7 @@
             self.account_client.list_account_containers(params=params)
         self.assertHeaders(resp, 'Account', 'GET')
 
-        self.assertEqual(len(container_list), 0)
+        self.assertEmpty(container_list)
 
         params = {'marker': self.containers[self.containers_count // 2]}
         resp, container_list = \
@@ -182,7 +182,7 @@
         resp, container_list = \
             self.account_client.list_account_containers(params=params)
         self.assertHeaders(resp, 'Account', 'GET')
-        self.assertEqual(len(container_list), 0)
+        self.assertEmpty(container_list)
 
         params = {'end_marker': self.containers[self.containers_count // 2]}
         resp, container_list = \
@@ -297,7 +297,7 @@
             create_update_metadata=metadata)
         self.assertHeaders(resp, 'Account', 'POST')
 
-        resp, body = self.account_client.list_account_metadata()
+        resp, _ = self.account_client.list_account_metadata()
         self.assertIn('x-account-meta-test-account-meta1', resp)
         self.assertEqual(resp['x-account-meta-test-account-meta1'],
                          metadata['test-account-meta1'])
@@ -352,7 +352,7 @@
         self.account_client.create_update_or_delete_account_metadata(
             create_update_metadata=metadata_1)
         metadata_2 = {'test-account-meta2': 'Meta2'}
-        resp, body = (
+        resp, _ = (
             self.account_client.create_update_or_delete_account_metadata(
                 create_update_metadata=metadata_2,
                 delete_metadata=metadata_1))
diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py
index d4e5ec5..4b66ebf 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -41,10 +41,10 @@
         tenant_name = self.os_roles_operator_alt.credentials.tenant_name
         username = self.os_roles_operator_alt.credentials.username
         cont_headers = {'X-Container-Read': tenant_name + ':' + username}
-        resp_meta, body = self.os_roles_operator.container_client.\
-            update_container_metadata(
+        resp_meta, _ = (
+            self.os_roles_operator.container_client.update_container_metadata(
                 self.container_name, metadata=cont_headers,
-                metadata_prefix='')
+                metadata_prefix=''))
         self.assertHeaders(resp_meta, 'Container', 'POST')
         # create object
         object_name = data_utils.rand_name(name='Object')
@@ -68,10 +68,10 @@
         tenant_name = self.os_roles_operator_alt.credentials.tenant_name
         username = self.os_roles_operator_alt.credentials.username
         cont_headers = {'X-Container-Write': tenant_name + ':' + username}
-        resp_meta, body = self.os_roles_operator.container_client.\
-            update_container_metadata(self.container_name,
-                                      metadata=cont_headers,
-                                      metadata_prefix='')
+        resp_meta, _ = (
+            self.os_roles_operator.container_client.update_container_metadata(
+                self.container_name, metadata=cont_headers,
+                metadata_prefix=''))
         self.assertHeaders(resp_meta, 'Container', 'POST')
         # set alternative authentication data; cannot simply use the
         # other object client.
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index 9c9d821..655626c 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -65,8 +65,8 @@
     def test_delete_object_without_using_creds(self):
         # create object
         object_name = data_utils.rand_name(name='Object')
-        resp, _ = self.object_client.create_object(self.container_name,
-                                                   object_name, 'data')
+        self.object_client.create_object(self.container_name, object_name,
+                                         'data')
         # trying to delete object with empty headers
         # X-Auth-Token is not provided
         self.object_client.auth_provider.set_alt_auth_data(
@@ -134,7 +134,7 @@
         # attempt to read object using non-authorized user
         # update X-Container-Read metadata ACL
         cont_headers = {'X-Container-Read': 'badtenant:baduser'}
-        resp_meta, body = self.container_client.update_container_metadata(
+        resp_meta, _ = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
         self.assertHeaders(resp_meta, 'Container', 'POST')
@@ -158,7 +158,7 @@
         # attempt to write object using non-authorized user
         # update X-Container-Write metadata ACL
         cont_headers = {'X-Container-Write': 'badtenant:baduser'}
-        resp_meta, body = self.container_client.update_container_metadata(
+        resp_meta, _ = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
         self.assertHeaders(resp_meta, 'Container', 'POST')
@@ -183,7 +183,7 @@
         cont_headers = {'X-Container-Read':
                         tenant_name + ':' + username,
                         'X-Container-Write': ''}
-        resp_meta, body = self.container_client.update_container_metadata(
+        resp_meta, _ = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
         self.assertHeaders(resp_meta, 'Container', 'POST')
@@ -208,7 +208,7 @@
         cont_headers = {'X-Container-Read':
                         tenant_name + ':' + username,
                         'X-Container-Write': ''}
-        resp_meta, body = self.container_client.update_container_metadata(
+        resp_meta, _ = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
         self.assertHeaders(resp_meta, 'Container', 'POST')
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 2b5692d..76fe8d4 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -27,7 +27,7 @@
     @decorators.idempotent_id('92139d73-7819-4db1-85f8-3f2f22a8d91f')
     def test_create_container(self):
         container_name = data_utils.rand_name(name='TestContainer')
-        resp, body = self.container_client.create_container(container_name)
+        resp, _ = self.container_client.create_container(container_name)
         self.containers.append(container_name)
         self.assertHeaders(resp, 'Container', 'PUT')
 
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 9e01c26..378061a 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -124,9 +124,8 @@
 
         # test GET on http://account_url/container_name
         # we should retrieve a listing of objects
-        resp, body = self.account_client.request("GET",
-                                                 self.container_name,
-                                                 headers={})
+        _, body = self.account_client.request("GET", self.container_name,
+                                              headers={})
         self.assertIn(self.object_name, body.decode())
         css = '<link rel="stylesheet" type="text/css" href="listings.css" />'
         self.assertIn(css, body.decode())
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index 3c11a51..4cb1914 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -90,8 +90,7 @@
             cont_client = [self.clients[c][0] for c in cont]
             obj_client = [self.clients[c][1] for c in cont]
             headers = make_headers(cont[1], cont_client[1])
-            resp, body = \
-                cont_client[0].put(str(cont[0]), body=None, headers=headers)
+            cont_client[0].put(str(cont[0]), body=None, headers=headers)
             # create object in container
             object_name = data_utils.rand_name(name='TestSyncObject')
             data = object_name[::-1].encode()  # Raw data, we need bytes
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index 7768d23..ed1be90 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -54,8 +54,8 @@
         # actually expire, so figure out how many secs in the future that is.
         sleepy_time = int(resp['x-delete-at']) - int(time.time())
         sleepy_time = sleepy_time if sleepy_time > 0 else 0
-        resp, body = self.object_client.get_object(self.container_name,
-                                                   self.object_name)
+        resp, _ = self.object_client.get_object(self.container_name,
+                                                self.object_name)
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertIn('x-delete-at', resp)
 
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 21ea6ae..b29a77f 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -48,7 +48,7 @@
         data_segments = [data + str(i) for i in range(segments)]
         # uploading segments
         for i in range(segments):
-            resp, _ = self.object_client.create_object_segments(
+            self.object_client.create_object_segments(
                 self.container_name, object_name, i, data_segments[i])
 
         return object_name, data_segments
@@ -184,7 +184,7 @@
         # create object with transfer_encoding
         object_name = data_utils.rand_name(name='TestObject')
         data = data_utils.random_bytes(1024)
-        status, _, resp_headers = self.object_client.put_object_with_chunk(
+        _, _, resp_headers = self.object_client.put_object_with_chunk(
             container=self.container_name,
             name=object_name,
             contents=data_utils.chunkify(data, 512)
@@ -394,7 +394,7 @@
         # update object metadata with x_object_manifest
 
         # uploading segments
-        object_name, data_segments = self._upload_segments()
+        object_name, _ = self._upload_segments()
         # creating a manifest file
         data_empty = ''
         self.object_client.create_object(self.container_name,
@@ -414,7 +414,7 @@
             self.container_name,
             object_name)
         self.assertIn('x-object-manifest', resp)
-        self.assertNotEqual(len(resp['x-object-manifest']), 0)
+        self.assertNotEmpty(resp['x-object-manifest'])
 
     @decorators.idempotent_id('0dbbe89c-6811-4d84-a2df-eca2bdd40c0e')
     def test_update_object_metadata_with_x_object_metakey(self):
@@ -494,7 +494,7 @@
         # get object metadata with x_object_manifest
 
         # uploading segments
-        object_name, data_segments = self._upload_segments()
+        object_name, _ = self._upload_segments()
         # creating a manifest file
         object_prefix = '%s/%s' % (self.container_name, object_name)
         metadata = {'X-Object-Manifest': object_prefix}
@@ -520,11 +520,11 @@
         self.assertTrue(resp['etag'].startswith('\"'))
         self.assertTrue(resp['etag'].endswith('\"'))
         self.assertTrue(resp['etag'].strip('\"').isalnum())
-        self.assertTrue(re.match("^\d+\.?\d*\Z", resp['x-timestamp']))
-        self.assertNotEqual(len(resp['content-type']), 0)
+        self.assertTrue(re.match(r"^\d+\.?\d*\Z", resp['x-timestamp']))
+        self.assertNotEmpty(resp['content-type'])
         self.assertTrue(re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*",
                                  resp['x-trans-id']))
-        self.assertNotEqual(len(resp['date']), 0)
+        self.assertNotEmpty(resp['date'])
         self.assertEqual(resp['accept-ranges'], 'bytes')
         self.assertEqual(resp['x-object-manifest'],
                          '%s/%s' % (self.container_name, object_name))
@@ -612,11 +612,11 @@
         self.assertTrue(resp['etag'].startswith('\"'))
         self.assertTrue(resp['etag'].endswith('\"'))
         self.assertTrue(resp['etag'].strip('\"').isalnum())
-        self.assertTrue(re.match("^\d+\.?\d*\Z", resp['x-timestamp']))
-        self.assertNotEqual(len(resp['content-type']), 0)
+        self.assertTrue(re.match(r"^\d+\.?\d*\Z", resp['x-timestamp']))
+        self.assertNotEmpty(resp['content-type'])
         self.assertTrue(re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*",
                                  resp['x-trans-id']))
-        self.assertNotEqual(len(resp['date']), 0)
+        self.assertNotEmpty(resp['date'])
         self.assertEqual(resp['accept-ranges'], 'bytes')
         self.assertEqual(resp['x-object-manifest'],
                          '%s/%s' % (self.container_name, object_name))
@@ -955,7 +955,7 @@
         local_data = "something different"
         md5 = hashlib.md5(local_data.encode()).hexdigest()
         headers = {'If-None-Match': md5}
-        resp, body = self.object_client.get(url, headers=headers)
+        resp, _ = self.object_client.get(url, headers=headers)
         self.assertHeaders(resp, 'Object', 'GET')
 
 
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index 085ad13..894e42d 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -127,7 +127,7 @@
         # list static large object metadata using multipart manifest
         object_name = self._create_large_object()
 
-        resp, body = self.object_client.list_object_metadata(
+        resp, _ = self.object_client.list_object_metadata(
             self.container_name,
             object_name)
 
@@ -155,7 +155,7 @@
         object_name = self._create_large_object()
 
         params_del = {'multipart-manifest': 'delete'}
-        resp, body = self.object_client.delete_object(
+        resp, _ = self.object_client.delete_object(
             self.container_name,
             object_name,
             params=params_del)
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index 4b506f8..91bc677 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -128,7 +128,7 @@
         url = self._get_temp_url(self.container_name,
                                  self.object_name, "GET",
                                  expires, key2)
-        resp, body = self.object_client.get(url)
+        _, body = self.object_client.get(url)
         self.assertEqual(body, self.content)
 
     @decorators.idempotent_id('9b08dade-3571-4152-8a4f-a4f2a873a735')
@@ -168,7 +168,7 @@
                                  expires, self.key)
 
         # Testing a HEAD on this Temp URL
-        resp, body = self.object_client.head(url)
+        resp, _ = self.object_client.head(url)
         self.assertHeaders(resp, 'Object', 'HEAD')
 
     @decorators.idempotent_id('9d9cfd90-708b-465d-802c-e4a8090b823d')
diff --git a/tempest/api/object_storage/test_object_temp_url_negative.py b/tempest/api/object_storage/test_object_temp_url_negative.py
index f4d63fd..3edaa86 100644
--- a/tempest/api/object_storage/test_object_temp_url_negative.py
+++ b/tempest/api/object_storage/test_object_temp_url_negative.py
@@ -46,7 +46,7 @@
 
     @classmethod
     def resource_cleanup(cls):
-        resp, _ = cls.account_client.create_update_or_delete_account_metadata(
+        cls.account_client.create_update_or_delete_account_metadata(
             delete_metadata=cls.metadata)
 
         cls.delete_containers()
diff --git a/tempest/api/volume/admin/test_snapshot_manage.py b/tempest/api/volume/admin/test_snapshot_manage.py
index a2d5fb1..6c09042 100644
--- a/tempest/api/volume/admin/test_snapshot_manage.py
+++ b/tempest/api/volume/admin/test_snapshot_manage.py
@@ -13,11 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.api.volume import base
 from tempest.common import waiters
 from tempest import config
+from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
 CONF = config.CONF
@@ -31,9 +30,18 @@
      managed by Cinder from a storage back end to Cinder
     """
 
+    @classmethod
+    def skip_checks(cls):
+        super(SnapshotManageAdminTest, cls).skip_checks()
+
+        if not CONF.volume_feature_enabled.manage_snapshot:
+            raise cls.skipException("Manage snapshot tests are disabled")
+
+        if len(CONF.volume.manage_snapshot_ref) != 2:
+            raise cls.skipException("Manage snapshot ref is not correctly "
+                                    "configured")
+
     @decorators.idempotent_id('0132f42d-0147-4b45-8501-cc504bbf7810')
-    @testtools.skipUnless(CONF.volume_feature_enabled.manage_snapshot,
-                          "Manage snapshot tests are disabled")
     def test_unmanage_manage_snapshot(self):
         # Create a volume
         volume = self.create_volume()
@@ -47,20 +55,30 @@
         self.admin_snapshots_client.unmanage_snapshot(snapshot['id'])
         self.admin_snapshots_client.wait_for_resource_deletion(snapshot['id'])
 
-        # Fetch snapshot ids
-        snapshot_list = [
-            snap['id'] for snap in
-            self.snapshots_client.list_snapshots()['snapshots']
-        ]
-
-        # Verify snapshot does not exist in snapshot list
-        self.assertNotIn(snapshot['id'], snapshot_list)
+        # Verify the original snapshot does not exist in snapshot list
+        params = {'all_tenants': 1}
+        all_snapshots = self.admin_snapshots_client.list_snapshots(
+            detail=True, params=params)['snapshots']
+        self.assertNotIn(snapshot['id'], [v['id'] for v in all_snapshots])
 
         # Manage the snapshot
-        snapshot_ref = '_snapshot-%s' % snapshot['id']
+        name = data_utils.rand_name(self.__class__.__name__ +
+                                    '-Managed-Snapshot')
+        description = data_utils.rand_name(self.__class__.__name__ +
+                                           '-Managed-Snapshot-Description')
+        metadata = {"manage-snap-meta1": "value1",
+                    "manage-snap-meta2": "value2",
+                    "manage-snap-meta3": "value3"}
+        snapshot_ref = {
+            'volume_id': volume['id'],
+            'ref': {CONF.volume.manage_snapshot_ref[0]:
+                    CONF.volume.manage_snapshot_ref[1] % snapshot['id']},
+            'name': name,
+            'description': description,
+            'metadata': metadata
+        }
         new_snapshot = self.admin_snapshot_manage_client.manage_snapshot(
-            volume_id=volume['id'],
-            ref={'source-name': snapshot_ref})['snapshot']
+            **snapshot_ref)['snapshot']
         self.addCleanup(self.delete_snapshot, new_snapshot['id'],
                         self.admin_snapshots_client)
 
@@ -70,4 +88,9 @@
                                                 'available')
 
         # Verify the managed snapshot has the expected parent volume
-        self.assertEqual(new_snapshot['volume_id'], volume['id'])
+        # and the expected field values.
+        new_snapshot_info = self.admin_snapshots_client.show_snapshot(
+            new_snapshot['id'])['snapshot']
+        self.assertEqual(snapshot['size'], new_snapshot_info['size'])
+        for key in ['volume_id', 'name', 'description', 'metadata']:
+            self.assertEqual(snapshot_ref[key], new_snapshot_info[key])
diff --git a/tempest/api/volume/admin/test_volume_pools.py b/tempest/api/volume/admin/test_volume_pools.py
index 60a3bda..d389c26 100644
--- a/tempest/api/volume/admin/test_volume_pools.py
+++ b/tempest/api/volume/admin/test_volume_pools.py
@@ -22,7 +22,7 @@
 
 class VolumePoolsAdminTestsJSON(base.BaseVolumeAdminTest):
     def _assert_pools(self, with_detail=False):
-        cinder_pools = self.admin_volume_client.show_pools(
+        cinder_pools = self.admin_scheduler_stats_client.list_pools(
             detail=with_detail)['pools']
         self.assertIn('name', cinder_pools[0])
         if with_detail:
diff --git a/tempest/api/volume/admin/test_volume_quota_classes.py b/tempest/api/volume/admin/test_volume_quota_classes.py
index 016d87a..f551575 100644
--- a/tempest/api/volume/admin/test_volume_quota_classes.py
+++ b/tempest/api/volume/admin/test_volume_quota_classes.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import random
+
 from oslo_log import log as logging
 from testtools import matchers
 
@@ -53,31 +55,41 @@
         LOG.debug("Get the current default quota class values")
         body = self.admin_quota_classes_client.show_quota_class_set(
             'default')['quota_class_set']
-        body.pop('id')
 
-        # Restore the defaults when the test is done
-        self.addCleanup(self._restore_default_quotas, body.copy())
+        # Note(jeremyZ) Only include specified quota keys to avoid the conflict
+        # that other tests may create/delete volume types or update volume
+        # type's default quotas in concurrency running.
+        update_kwargs = {key: body[key] for key in body if key in QUOTA_KEYS}
 
-        # Increment some of the values for updating the default quota class.
-        # For safety, only items with value >= 0 will be updated, and items
-        # with value < 0 (-1 means unlimited) will be ignored.
-        for quota, default in body.items():
+        # Restore the defaults when the test is done.
+        self.addCleanup(self._restore_default_quotas, update_kwargs.copy())
+
+        # Note(jeremyZ) Increment some of the values for updating the default
+        # quota class. For safety, only items with value >= 0 will be updated,
+        # and items with value < 0 (-1 means unlimited) will be ignored.
+        for quota, default in update_kwargs.items():
             if default >= 0:
-                body[quota] = default + 1
+                update_kwargs[quota] = default + 1
+
+        # Create a volume type for updating default quotas class.
+        volume_type_name = self.create_volume_type()['name']
+        for key in ['volumes', 'snapshots', 'gigabytes']:
+            update_kwargs['%s_%s' % (key, volume_type_name)] = \
+                random.randint(1, 10)
 
         LOG.debug("Update limits for the default quota class set")
         update_body = self.admin_quota_classes_client.update_quota_class_set(
-            'default', **body)['quota_class_set']
+            'default', **update_kwargs)['quota_class_set']
         self.assertThat(update_body.items(),
-                        matchers.ContainsAll(body.items()))
+                        matchers.ContainsAll(update_kwargs.items()))
 
-        # Verify current project's default quotas
+        # Verify current project's default quotas.
         default_quotas = self.admin_quotas_client.show_default_quota_set(
-            self.os_adm.credentials.tenant_id)['quota_set']
+            self.os_admin.credentials.tenant_id)['quota_set']
         self.assertThat(default_quotas.items(),
-                        matchers.ContainsAll(body.items()))
+                        matchers.ContainsAll(update_kwargs.items()))
 
-        # Verify a new project's default quotas
+        # Verify a new project's default quotas.
         project_name = data_utils.rand_name('quota_class_tenant')
         description = data_utils.rand_name('desc_')
         project_id = self.identity_utils.create_project(
@@ -86,4 +98,4 @@
         default_quotas = self.admin_quotas_client.show_default_quota_set(
             project_id)['quota_set']
         self.assertThat(default_quotas.items(),
-                        matchers.ContainsAll(body.items()))
+                        matchers.ContainsAll(update_kwargs.items()))
diff --git a/tempest/api/volume/admin/test_volume_services.py b/tempest/api/volume/admin/test_volume_services.py
index 4aab9c1..293af81 100644
--- a/tempest/api/volume/admin/test_volume_services.py
+++ b/tempest/api/volume/admin/test_volume_services.py
@@ -41,13 +41,13 @@
     def test_list_services(self):
         services = (self.admin_volume_services_client.list_services()
                     ['services'])
-        self.assertNotEqual(0, len(services))
+        self.assertNotEmpty(services)
 
     @decorators.idempotent_id('63a3e1ca-37ee-4983-826d-83276a370d25')
     def test_get_service_by_service_binary_name(self):
         services = (self.admin_volume_services_client.list_services(
             binary=self.binary_name)['services'])
-        self.assertNotEqual(0, len(services))
+        self.assertNotEmpty(services)
         for service in services:
             self.assertEqual(self.binary_name, service['binary'])
 
@@ -76,7 +76,7 @@
         services = (self.admin_volume_services_client.list_services(
             host=hostname, binary='cinder-volume')['services'])
 
-        self.assertNotEqual(0, len(services),
+        self.assertNotEmpty(services,
                             'cinder-volume not found on host %s' % hostname)
         self.assertEqual(hostname, _get_host(services[0]['host']))
         self.assertEqual('cinder-volume', services[0]['binary'])
@@ -87,6 +87,6 @@
         services = (self.admin_volume_services_client.list_services(
             host=self.host_name, binary=self.binary_name))['services']
 
-        self.assertNotEqual(0, len(services))
+        self.assertNotEmpty(services)
         self.assertEqual(self.host_name, _get_host(services[0]['host']))
         self.assertEqual(self.binary_name, services[0]['binary'])
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index ac717f8..af1024c 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -57,8 +57,6 @@
                          "to the requested name")
         self.assertIsNotNone(volume['id'],
                              "Field volume id is empty or not found.")
-        waiters.wait_for_volume_resource_status(self.volumes_client,
-                                                volume['id'], 'available')
 
         # Update volume with new volume_type
         self.volumes_client.retype_volume(volume['id'],
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index acff7cd..b81a477 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -70,7 +70,7 @@
     @test.services('compute')
     def test_force_detach_volume(self):
         # Create a server and a volume
-        server_id = self.create_server(wait_until='ACTIVE')['id']
+        server_id = self.create_server()['id']
         volume_id = self.create_volume()['id']
 
         # Attach volume
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 3f33c7b..8d66156 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -217,16 +217,17 @@
                 cls.snapshots_client.wait_for_resource_deletion,
                 snapshot)
 
-    def create_server(self, **kwargs):
+    def create_server(self, wait_until='ACTIVE', **kwargs):
         name = kwargs.pop(
             'name',
             data_utils.rand_name(self.__class__.__name__ + '-instance'))
 
         tenant_network = self.get_tenant_network()
         body, _ = compute.create_test_server(
-            self.os,
+            self.os_primary,
             tenant_network=tenant_network,
             name=name,
+            wait_until=wait_until,
             **kwargs)
 
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
diff --git a/tempest/api/volume/test_availability_zone.py b/tempest/api/volume/test_availability_zone.py
index 666efdf..d0a87db 100644
--- a/tempest/api/volume/test_availability_zone.py
+++ b/tempest/api/volume/test_availability_zone.py
@@ -30,4 +30,4 @@
         # List of availability zone
         availability_zone = (self.client.list_availability_zones()
                              ['availabilityZoneInfo'])
-        self.assertGreater(len(availability_zone), 0)
+        self.assertNotEmpty(availability_zone)
diff --git a/tempest/api/volume/test_volume_absolute_limits.py b/tempest/api/volume/test_volume_absolute_limits.py
index 870b9f0..4018468 100644
--- a/tempest/api/volume/test_volume_absolute_limits.py
+++ b/tempest/api/volume/test_volume_absolute_limits.py
@@ -24,7 +24,7 @@
 # NOTE(zhufl): This inherits from BaseVolumeAdminTest because
 # it requires force_tenant_isolation=True, which need admin
 # credentials to create non-admin users for the tests.
-class AbsoluteLimitsTests(base.BaseVolumeAdminTest):
+class AbsoluteLimitsTests(base.BaseVolumeAdminTest):  # noqa
 
     # avoid existing volumes of pre-defined tenant
     force_tenant_isolation = True
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index 5a192ac..2c13a3c 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from testtools import matchers
-
 from tempest.api.volume import base
 from tempest.common import waiters
 from tempest.lib import decorators
@@ -56,7 +54,7 @@
         # List volume transfers, the result should be greater than
         # or equal to 1
         body = self.client.list_volume_transfers()['transfers']
-        self.assertThat(len(body), matchers.GreaterThan(0))
+        self.assertNotEmpty(body)
 
         # Accept a volume transfer by alt_tenant
         body = self.alt_client.accept_volume_transfer(
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 0e7f1e9..8541c6d 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -38,7 +38,7 @@
     @test.services('compute')
     def test_attach_detach_volume_to_instance(self):
         # Create a server
-        server = self.create_server(wait_until='ACTIVE')
+        server = self.create_server()
         # Volume is attached and detached successfully from an instance
         self.volumes_client.attach_volume(self.volume['id'],
                                           instance_uuid=server['id'],
@@ -69,7 +69,7 @@
     @test.services('compute')
     def test_get_volume_attachment(self):
         # Create a server
-        server = self.create_server(wait_until='ACTIVE')
+        server = self.create_server()
         # Verify that a volume's attachment information is retrieved
         self.volumes_client.attach_volume(self.volume['id'],
                                           instance_uuid=server['id'],
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 5ad209c..4b4aeec 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -108,7 +108,7 @@
         volume = self.create_volume()
         self.addCleanup(self.volumes_client.delete_volume,
                         volume['id'])
-        server = self.create_server(wait_until='ACTIVE')
+        server = self.create_server()
         # Attach volume to instance
         self.attach_volume(server['id'], volume['id'])
         # Create backup using force flag
@@ -118,9 +118,8 @@
                                     name=backup_name, force=True)
         self.assertEqual(backup_name, backup['name'])
 
-    @testtools.skipUnless(CONF.service_available.glance,
-                          "Glance is not available")
     @decorators.idempotent_id('2a8ba340-dff2-4511-9db7-646f07156b15')
+    @test.services('image')
     def test_bootable_volume_backup_and_restore(self):
         # Create volume from image
         img_uuid = CONF.compute.image_ref
diff --git a/tempest/api/volume/test_volumes_clone.py b/tempest/api/volume/test_volumes_clone.py
index a6bbb0a..4c13375 100644
--- a/tempest/api/volume/test_volumes_clone.py
+++ b/tempest/api/volume/test_volumes_clone.py
@@ -13,11 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.api.volume import base
 from tempest import config
 from tempest.lib import decorators
+from tempest import test
 
 
 CONF = config.CONF
@@ -47,9 +46,8 @@
         self.assertEqual(volume['source_volid'], src_vol['id'])
         self.assertEqual(volume['size'], src_size + 1)
 
-    @testtools.skipUnless(CONF.service_available.glance,
-                          "Glance is not available")
     @decorators.idempotent_id('cbbcd7c6-5a6c-481a-97ac-ca55ab715d16')
+    @test.services('image')
     def test_create_from_bootable_volume(self):
         # Create volume from image
         img_uuid = CONF.compute.image_ref
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index fc3bcab..4e19e62 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -170,7 +170,7 @@
     @decorators.idempotent_id('f5e56b0a-5d02-43c1-a2a7-c9b792c2e3f6')
     @test.services('compute')
     def test_attach_volumes_with_nonexistent_volume_id(self):
-        server = self.create_server(wait_until='ACTIVE')
+        server = self.create_server()
 
         self.assertRaises(lib_exc.NotFound,
                           self.volumes_client.attach_volume,
@@ -261,7 +261,7 @@
         params = {'name': v_name}
         fetched_volume = self.volumes_client.list_volumes(
             params=params)['volumes']
-        self.assertEqual(0, len(fetched_volume))
+        self.assertEmpty(fetched_volume)
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('9ca17820-a0e7-4cbd-a7fa-f4468735e359')
@@ -271,7 +271,7 @@
         fetched_volume = \
             self.volumes_client.list_volumes(
                 detail=True, params=params)['volumes']
-        self.assertEqual(0, len(fetched_volume))
+        self.assertEmpty(fetched_volume)
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('143b279b-7522-466b-81be-34a87d564a7c')
@@ -279,7 +279,7 @@
         params = {'status': 'null'}
         fetched_volume = self.volumes_client.list_volumes(
             params=params)['volumes']
-        self.assertEqual(0, len(fetched_volume))
+        self.assertEmpty(fetched_volume)
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('ba94b27b-be3f-496c-a00e-0283b373fa75')
@@ -288,7 +288,7 @@
         fetched_volume = \
             self.volumes_client.list_volumes(detail=True,
                                              params=params)['volumes']
-        self.assertEqual(0, len(fetched_volume))
+        self.assertEmpty(fetched_volume)
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('5b810c91-0ad1-47ce-aee8-615f789be78f')
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 99918eb..44c1def 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -39,7 +39,7 @@
     @test.services('compute')
     def test_snapshot_create_delete_with_volume_in_use(self):
         # Create a test instance
-        server = self.create_server(wait_until='ACTIVE')
+        server = self.create_server()
         self.attach_volume(server['id'], self.volume_origin['id'])
 
         # Snapshot a volume which attached to an instance with force=False
@@ -65,7 +65,7 @@
         snapshot1 = self.create_snapshot(self.volume_origin['id'])
 
         # Create a server and attach it
-        server = self.create_server(wait_until='ACTIVE')
+        server = self.create_server()
         self.attach_volume(server['id'], self.volume_origin['id'])
 
         # Now that the volume is attached, create another snapshots
diff --git a/tempest/clients.py b/tempest/clients.py
index 4baa31d..a941301 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -41,8 +41,7 @@
         _, identity_uri = get_auth_provider_class(credentials)
         super(Manager, self).__init__(
             credentials=credentials, identity_uri=identity_uri, scope=scope,
-            region=CONF.identity.region,
-            client_parameters=self._prepare_configuration())
+            region=CONF.identity.region)
         # TODO(andreaf) When clients are initialised without the right
         # parameters available, the calls below will trigger a KeyError.
         # We should catch that and raise a better error.
@@ -62,35 +61,6 @@
             build_timeout=CONF.orchestration.build_timeout,
             **self.default_params)
 
-    def _prepare_configuration(self):
-        """Map values from CONF into Manager parameters
-
-        This uses `config.service_client_config` for all services to collect
-        most configuration items needed to init the clients.
-        """
-        # NOTE(andreaf) Once all service clients in Tempest are migrated
-        # to tempest.lib, their configuration will be picked up from the
-        # registry, and this method will become redundant.
-
-        configuration = {}
-
-        # Setup the parameters for all Tempest services which are not in lib.
-        # NOTE(andreaf) Since client.py is an internal module of Tempest,
-        # it doesn't have to consider plugin configuration.
-        for service in clients._tempest_internal_modules():
-            try:
-                # NOTE(andreaf) Use the unversioned service name to fetch
-                # the configuration since configuration is not versioned.
-                service_for_config = service.split('.')[0]
-                if service_for_config not in configuration:
-                    configuration[service_for_config] = (
-                        config.service_client_config(service_for_config))
-            except lib_exc.UnknownServiceClient:
-                LOG.warning(
-                    'Could not load configuration for service %s', service)
-
-        return configuration
-
     def _set_network_clients(self):
         self.network_agents_client = self.network.AgentsClient()
         self.network_extensions_client = self.network.ExtensionsClient()
@@ -109,6 +79,7 @@
         self.security_groups_client = self.network.SecurityGroupsClient()
         self.network_versions_client = self.network.NetworkVersionsClient()
         self.service_providers_client = self.network.ServiceProvidersClient()
+        self.tags_client = self.network.TagsClient()
 
     def _set_image_clients(self):
         if CONF.service_available.glance:
@@ -296,8 +267,10 @@
             self.volume_v2.TransfersClient()
 
     def _set_object_storage_clients(self):
-        # Mandatory parameters (always defined)
-        params = self.parameters['object-storage']
+        # NOTE(andreaf) Load configuration from config. Once object storage
+        # is in lib, configuration will be pulled directly from the registry
+        # and this will not be required anymore.
+        params = config.service_client_config('object-storage')
 
         self.account_client = object_storage.AccountClient(self.auth_provider,
                                                            **params)
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 0a1881c..6b81e0d 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -167,15 +167,13 @@
 def get_extension_client(os, service):
     extensions_client = {
         'nova': os.extensions_client,
-        'cinder': os.volumes_extension_client,
         'neutron': os.network_extensions_client,
         'swift': os.capabilities_client,
+        # NOTE: Cinder v3 API is current and v2 and v1 are deprecated.
+        # V3 extension API is the same as v2, so we reuse the v2 client
+        # for v3 API also.
+        'cinder': os.volumes_v2_extension_client,
     }
-    # NOTE (e0ne): Use Cinder API v2 by default because v1 is deprecated
-    if CONF.volume_feature_enabled.api_v2:
-        extensions_client['cinder'] = os.volumes_v2_extension_client
-    else:
-        extensions_client['cinder'] = os.volumes_extension_client
 
     if service not in extensions_client:
         print('No tempest extensions client for %s' % service)
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 9319d2a..99a628e 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -64,10 +64,14 @@
                 # Show header line too
                 selected.append(l)
             # lsblk lists disk type in a column right-aligned with TYPE
-            elif pos > 0 and l[pos:pos + 4] == "disk":
+            elif pos is not None and pos > 0 and l[pos:pos + 4] == "disk":
                 selected.append(l)
 
-        return "\n".join(selected)
+        if selected:
+            return "\n".join(selected)
+        else:
+            msg = "'TYPE' column is requred but the output doesn't have it: "
+            raise tempest.lib.exceptions.TempestException(msg + output)
 
     def get_boot_time(self):
         cmd = 'cut -f1 -d. /proc/uptime'
@@ -89,12 +93,12 @@
     def get_nic_name_by_mac(self, address):
         cmd = "ip -o link | awk '/%s/ {print $2}'" % address
         nic = self.exec_command(cmd)
-        return nic.strip().strip(":").lower()
+        return nic.strip().strip(":").split('@')[0].lower()
 
     def get_nic_name_by_ip(self, address):
         cmd = "ip -o addr | awk '/%s/ {print $2}'" % address
         nic = self.exec_command(cmd)
-        return nic.strip().strip(":").lower()
+        return nic.strip().strip(":").split('@')[0].lower()
 
     def get_dns_servers(self):
         cmd = 'cat /etc/resolv.conf'
diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py
index b15796f..9e83a07 100644
--- a/tempest/common/validation_resources.py
+++ b/tempest/common/validation_resources.py
@@ -80,10 +80,23 @@
             validation_data['security_group'] = \
                 create_ssh_security_group(os, add_rule)
         if validation_resources['floating_ip']:
-            floating_client = os.compute_floating_ips_client
-            validation_data.update(
-                floating_client.create_floating_ip(
-                    pool=CONF.network.floating_network_name))
+            if CONF.service_available.neutron:
+                floatingip = os.floating_ips_client.create_floatingip(
+                    floating_network_id=CONF.network.public_network_id)
+                # validation_resources['floating_ip'] has historically looked
+                # like a compute API POST /os-floating-ips response, so we need
+                # to mangle it a bit for a Neutron response with different
+                # fields.
+                validation_data['floating_ip'] = floatingip['floatingip']
+                validation_data['floating_ip']['ip'] = (
+                    floatingip['floatingip']['floating_ip_address'])
+            else:
+                # NOTE(mriedem): The os-floating-ips compute API was deprecated
+                # in the 2.36 microversion. Any tests for CRUD operations on
+                # floating IPs using the compute API should be capped at 2.35.
+                validation_data.update(
+                    os.compute_floating_ips_client.create_floating_ip(
+                        pool=CONF.network.floating_network_name))
     return validation_data
 
 
diff --git a/tempest/config.py b/tempest/config.py
index a2e0877..fbe0a1b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -647,6 +647,9 @@
     cfg.BoolOpt('port_security',
                 default=False,
                 help="Does the test environment support port security?"),
+    cfg.BoolOpt('floating_ips',
+                default=True,
+                help='Does the test environment support floating_ips')
 ]
 
 validation_group = cfg.OptGroup(name='validation',
@@ -765,6 +768,12 @@
                      "It contains two elements, the first is ref type "
                      "(like 'source-name', 'source-id', etc), the second is "
                      "volume name template used in storage backend"),
+    cfg.ListOpt('manage_snapshot_ref',
+                default=['source-name', '_snapshot-%s'],
+                help="A reference to existing snapshot for snapshot manage. "
+                     "It contains two elements, the first is ref type "
+                     "(like 'source-name', 'source-id', etc), the second is "
+                     "snapshot name template used in storage backend"),
     cfg.StrOpt('min_microversion',
                default=None,
                help="Lower version of the test target microversion range. "
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 4123ae5..067da09 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -273,6 +273,27 @@
         yield(0, msg)
 
 
+def dont_put_admin_tests_on_nonadmin_path(logical_line, physical_line,
+                                          filename):
+    """Check admin tests should exist under admin path
+
+    T115
+    """
+
+    if 'tempest/api/' not in filename:
+        return
+
+    if pep8.noqa(physical_line):
+        return
+
+    if not re.match('class .*Test.*\(.*Admin.*\):', logical_line):
+        return
+
+    if not re.match('.\/tempest\/api\/.*\/admin\/.*', filename):
+        msg = 'T115: All admin tests should exist under admin path.'
+        yield(0, msg)
+
+
 def factory(register):
     register(import_no_clients_in_api_and_scenario_tests)
     register(scenario_tests_need_service_tags)
@@ -287,3 +308,4 @@
     register(dont_import_local_tempest_into_lib)
     register(dont_use_config_in_tempest_lib)
     register(use_rand_uuid_instead_of_uuid4)
+    register(dont_put_admin_tests_on_nonadmin_path)
diff --git a/tempest/lib/api_schema/response/compute/v2_13/__init__.py b/tempest/lib/api_schema/response/compute/v2_13/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_13/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_13/servers.py b/tempest/lib/api_schema/response/compute/v2_13/servers.py
new file mode 100644
index 0000000..a90f3e4
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_13/servers.py
@@ -0,0 +1,34 @@
+# Copyright 2017 NTT 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.
+
+import copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import servers
+
+
+common_server_group = copy.deepcopy(servers.common_server_group)
+common_server_group['properties']['project_id'] = {'type': 'string'}
+common_server_group['properties']['user_id'] = {'type': 'string'}
+common_server_group['required'].append('project_id')
+common_server_group['required'].append('user_id')
+
+create_show_server_group = copy.deepcopy(servers.create_show_server_group)
+create_show_server_group['response_body']['properties'][
+    'server_group'] = common_server_group
+
+delete_server_group = copy.deepcopy(servers.delete_server_group)
+
+list_server_groups = copy.deepcopy(servers.list_server_groups)
+list_server_groups['response_body']['properties']['server_groups'][
+    'items'] = common_server_group
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index d72b4dd..63cf07f 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -474,7 +474,7 @@
             # Ensure there are not more than one top-level keys
             # NOTE(freerunner): Ensure, that JSON is not nullable to
             # to prevent StopIteration Exception
-            if len(body.keys()) != 1:
+            if not hasattr(body, "keys") or len(body.keys()) != 1:
                 return body
             # Just return the "wrapped" element
             first_key, first_item = six.next(six.iteritems(body))
diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py
index 657c0c1..d4ec6ad 100644
--- a/tempest/lib/common/ssh.py
+++ b/tempest/lib/common/ssh.py
@@ -84,10 +84,6 @@
         ssh.set_missing_host_key_policy(
             paramiko.AutoAddPolicy())
         _start_time = time.time()
-        if self.proxy_client is not None:
-            proxy_chan = self._get_proxy_channel()
-        else:
-            proxy_chan = None
         if self.pkey is not None:
             LOG.info("Creating ssh connection to '%s:%d' as '%s'"
                      " with public key authentication",
@@ -98,6 +94,10 @@
                      self.host, self.port, self.username, str(self.password))
         attempts = 0
         while True:
+            if self.proxy_client is not None:
+                proxy_chan = self._get_proxy_channel()
+            else:
+                proxy_chan = None
             try:
                 ssh.connect(self.host, port=self.port, username=self.username,
                             password=self.password,
diff --git a/tempest/lib/services/compute/server_groups_client.py b/tempest/lib/services/compute/server_groups_client.py
index 3a935b4..03cd645 100644
--- a/tempest/lib/services/compute/server_groups_client.py
+++ b/tempest/lib/services/compute/server_groups_client.py
@@ -17,12 +17,17 @@
 from oslo_serialization import jsonutils as json
 
 from tempest.lib.api_schema.response.compute.v2_1 import servers as schema
+from tempest.lib.api_schema.response.compute.v2_13 import servers as schemav213
 from tempest.lib.common import rest_client
 from tempest.lib.services.compute import base_compute_client
 
 
 class ServerGroupsClient(base_compute_client.BaseComputeClient):
 
+    schema_versions_info = [
+        {'min': None, 'max': '2.12', 'schema': schema},
+        {'min': '2.13', 'max': None, 'schema': schemav213}]
+
     def create_server_group(self, **kwargs):
         """Create the server group.
 
@@ -34,12 +39,14 @@
         resp, body = self.post('os-server-groups', post_body)
 
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.create_show_server_group, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def delete_server_group(self, server_group_id):
         """Delete the given server-group."""
         resp, body = self.delete("os-server-groups/%s" % server_group_id)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.delete_server_group, resp, body)
         return rest_client.ResponseBody(resp, body)
 
@@ -47,6 +54,7 @@
         """List the server-groups."""
         resp, body = self.get("os-server-groups")
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.list_server_groups, resp, body)
         return rest_client.ResponseBody(resp, body)
 
@@ -54,5 +62,6 @@
         """Get the details of given server_group."""
         resp, body = self.get("os-server-groups/%s" % server_group_id)
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.create_show_server_group, resp, body)
         return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/identity/v3/services_client.py b/tempest/lib/services/identity/v3/services_client.py
index 17b0f24..7bbe850 100644
--- a/tempest/lib/services/identity/v3/services_client.py
+++ b/tempest/lib/services/identity/v3/services_client.py
@@ -76,7 +76,7 @@
         url = 'services'
         if params:
             url += '?%s' % urllib.urlencode(params)
-        resp, body = self.get('services')
+        resp, body = self.get(url)
         self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/network/__init__.py b/tempest/lib/services/network/__init__.py
index 19e5463..419e593 100644
--- a/tempest/lib/services/network/__init__.py
+++ b/tempest/lib/services/network/__init__.py
@@ -31,11 +31,12 @@
     ServiceProvidersClient
 from tempest.lib.services.network.subnetpools_client import SubnetpoolsClient
 from tempest.lib.services.network.subnets_client import SubnetsClient
+from tempest.lib.services.network.tags_client import TagsClient
 from tempest.lib.services.network.versions_client import NetworkVersionsClient
 
 __all__ = ['AgentsClient', 'ExtensionsClient', 'FloatingIPsClient',
            'MeteringLabelRulesClient', 'MeteringLabelsClient',
-           'NetworksClient', 'PortsClient', 'QuotasClient', 'RoutersClient',
-           'SecurityGroupRulesClient', 'SecurityGroupsClient',
-           'ServiceProvidersClient', 'SubnetpoolsClient', 'SubnetsClient',
-           'NetworkVersionsClient']
+           'NetworksClient', 'NetworkVersionsClient', 'PortsClient',
+           'QuotasClient', 'RoutersClient', 'SecurityGroupRulesClient',
+           'SecurityGroupsClient', 'ServiceProvidersClient',
+           'SubnetpoolsClient', 'SubnetsClient', 'TagsClient']
diff --git a/tempest/lib/services/network/tags_client.py b/tempest/lib/services/network/tags_client.py
new file mode 100644
index 0000000..20c2c11
--- /dev/null
+++ b/tempest/lib/services/network/tags_client.py
@@ -0,0 +1,88 @@
+# Copyright 2017 AT&T 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.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+from tempest.lib.services.network import base
+
+
+class TagsClient(base.BaseNetworkClient):
+
+    def create_tag(self, resource_type, resource_id, tag):
+        """Adds a tag on the resource.
+
+        For more information, please refer to the official API reference:
+        http://developer.openstack.org/api-ref/networking/v2/index.html#add-a-tag
+        """
+        # NOTE(felipemonteiro): Cannot use ``update_resource`` method because
+        # this API requires self.put but returns 201 instead of 200 expected
+        # by ``update_resource``.
+        uri = '%s/%s/%s/tags/%s' % (
+            self.uri_prefix, resource_type, resource_id, tag)
+        resp, _ = self.put(uri, json.dumps({}))
+        self.expected_success(201, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def check_tag_existence(self, resource_type, resource_id, tag):
+        """Confirm that a given tag is set on the resource.
+
+        For more information, please refer to the official API reference:
+        http://developer.openstack.org/api-ref/networking/v2/index.html#confirm-a-tag
+        """
+        # TODO(felipemonteiro): Use the "check_resource" method in
+        # ``BaseNetworkClient`` once it has been implemented.
+        uri = '%s/%s/%s/tags/%s' % (
+            self.uri_prefix, resource_type, resource_id, tag)
+        resp, _ = self.get(uri)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def update_all_tags(self, resource_type, resource_id, tags):
+        """Replace all tags on the resource.
+
+        For more information, please refer to the official API reference:
+        http://developer.openstack.org/api-ref/networking/v2/index.html#replace-all-tags
+        """
+        uri = '/%s/%s/tags' % (resource_type, resource_id)
+        put_body = {"tags": tags}
+        return self.update_resource(uri, put_body)
+
+    def delete_tag(self, resource_type, resource_id, tag):
+        """Removes a tag on the resource.
+
+        For more information, please refer to the official API reference:
+        http://developer.openstack.org/api-ref/networking/v2/index.html#remove-a-tag
+        """
+        uri = '/%s/%s/tags/%s' % (resource_type, resource_id, tag)
+        return self.delete_resource(uri)
+
+    def delete_all_tags(self, resource_type, resource_id):
+        """Removes all tags on the resource.
+
+        For more information, please refer to the official API reference:
+        http://developer.openstack.org/api-ref/networking/v2/index.html#remove-all-tags
+        """
+        uri = '/%s/%s/tags' % (resource_type, resource_id)
+        return self.delete_resource(uri)
+
+    def list_tags(self, resource_type, resource_id):
+        """Retrieves the tags for a resource.
+
+        For more information, please refer to the official API reference:
+        http://developer.openstack.org/api-ref/networking/v2/index.html#obtain-tag-list
+        """
+        uri = '/%s/%s/tags' % (resource_type, resource_id)
+        return self.list_resources(uri)
diff --git a/tempest/lib/services/volume/v2/types_client.py b/tempest/lib/services/volume/v2/types_client.py
index 5d30615..af4fd8c 100644
--- a/tempest/lib/services/volume/v2/types_client.py
+++ b/tempest/lib/services/volume/v2/types_client.py
@@ -41,7 +41,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#list-volume-types
+        https://developer.openstack.org/api-ref/block-storage/v2/#list-all-volume-types-for-v2
         """
         url = 'types'
         if params:
@@ -57,7 +57,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#show-volume-type-details
+        https://developer.openstack.org/api-ref/block-storage/v2/#show-volume-type-details-for-v2
         """
         url = "types/%s" % volume_type_id
         resp, body = self.get(url)
@@ -70,7 +70,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-type
+        https://developer.openstack.org/api-ref/block-storage/v2/#create-volume-type-for-v2
         """
         post_body = json.dumps({'volume_type': kwargs})
         resp, body = self.post('types', post_body)
diff --git a/tempest/lib/services/volume/v2/volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py
index 8b5c96f..f4e7c6a 100644
--- a/tempest/lib/services/volume/v2/volumes_client.py
+++ b/tempest/lib/services/volume/v2/volumes_client.py
@@ -321,7 +321,7 @@
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    @removals.remove(message="use show_pools from tempest.lib.services."
+    @removals.remove(message="use list_pools from tempest.lib.services."
                              "volume.v2.scheduler_stats_client")
     def show_pools(self, detail=False):
         # List all the volumes pools (hosts)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 67647f0..38e03c7 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -47,40 +47,40 @@
     def setup_clients(cls):
         super(ScenarioTest, cls).setup_clients()
         # Clients (in alphabetical order)
-        cls.flavors_client = cls.manager.flavors_client
+        cls.flavors_client = cls.os_primary.flavors_client
         cls.compute_floating_ips_client = (
-            cls.manager.compute_floating_ips_client)
+            cls.os_primary.compute_floating_ips_client)
         if CONF.service_available.glance:
             # Check if glance v1 is available to determine which client to use.
             if CONF.image_feature_enabled.api_v1:
-                cls.image_client = cls.manager.image_client
+                cls.image_client = cls.os_primary.image_client
             elif CONF.image_feature_enabled.api_v2:
-                cls.image_client = cls.manager.image_client_v2
+                cls.image_client = cls.os_primary.image_client_v2
             else:
                 raise lib_exc.InvalidConfiguration(
                     'Either api_v1 or api_v2 must be True in '
                     '[image-feature-enabled].')
         # Compute image client
-        cls.compute_images_client = cls.manager.compute_images_client
-        cls.keypairs_client = cls.manager.keypairs_client
+        cls.compute_images_client = cls.os_primary.compute_images_client
+        cls.keypairs_client = cls.os_primary.keypairs_client
         # Nova security groups client
         cls.compute_security_groups_client = (
-            cls.manager.compute_security_groups_client)
+            cls.os_primary.compute_security_groups_client)
         cls.compute_security_group_rules_client = (
-            cls.manager.compute_security_group_rules_client)
-        cls.servers_client = cls.manager.servers_client
-        cls.interface_client = cls.manager.interfaces_client
+            cls.os_primary.compute_security_group_rules_client)
+        cls.servers_client = cls.os_primary.servers_client
+        cls.interface_client = cls.os_primary.interfaces_client
         # Neutron network client
-        cls.networks_client = cls.manager.networks_client
-        cls.ports_client = cls.manager.ports_client
-        cls.routers_client = cls.manager.routers_client
-        cls.subnets_client = cls.manager.subnets_client
-        cls.floating_ips_client = cls.manager.floating_ips_client
-        cls.security_groups_client = cls.manager.security_groups_client
+        cls.networks_client = cls.os_primary.networks_client
+        cls.ports_client = cls.os_primary.ports_client
+        cls.routers_client = cls.os_primary.routers_client
+        cls.subnets_client = cls.os_primary.subnets_client
+        cls.floating_ips_client = cls.os_primary.floating_ips_client
+        cls.security_groups_client = cls.os_primary.security_groups_client
         cls.security_group_rules_client = (
-            cls.manager.security_group_rules_client)
-        cls.volumes_client = cls.manager.volumes_v2_client
-        cls.snapshots_client = cls.manager.snapshots_v2_client
+            cls.os_primary.security_group_rules_client)
+        cls.volumes_client = cls.os_primary.volumes_v2_client
+        cls.snapshots_client = cls.os_primary.snapshots_v2_client
 
     # ## Test functions library
     #
@@ -133,7 +133,7 @@
 
         # Needed for the cross_tenant_traffic test:
         if clients is None:
-            clients = self.manager
+            clients = self.os_primary
 
         if name is None:
             name = data_utils.rand_name(self.__class__.__name__ + "-server")
@@ -195,7 +195,7 @@
 
         tenant_network = self.get_tenant_network()
 
-        body, servers = compute.create_test_server(
+        body, _ = compute.create_test_server(
             clients,
             tenant_network=tenant_network,
             wait_until=wait_until,
@@ -731,7 +731,7 @@
             :returns: True if subnet with cidr already exist in tenant
                   False else
             """
-            cidr_in_use = self.admin_manager.subnets_client.list_subnets(
+            cidr_in_use = self.os_admin.subnets_client.list_subnets(
                 tenant_id=tenant_id, cidr=cidr)['subnets']
             return len(cidr_in_use) != 0
 
@@ -780,7 +780,7 @@
         return subnet
 
     def _get_server_port_id_and_ip4(self, server, ip_addr=None):
-        ports = self.admin_manager.ports_client.list_ports(
+        ports = self.os_admin.ports_client.list_ports(
             device_id=server['id'], fixed_ip=ip_addr)['ports']
         # A port can have more than one IP address in some cases.
         # If the network is dual-stack (IPv4 + IPv6), this port is associated
@@ -801,7 +801,7 @@
         if inactive:
             LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
 
-        self.assertNotEqual(0, len(port_map),
+        self.assertNotEmpty(port_map,
                             "No IPv4 addresses found in: %s" % ports)
         self.assertEqual(len(port_map), 1,
                          "Found multiple IPv4 addresses: %s. "
@@ -810,9 +810,9 @@
         return port_map[0]
 
     def _get_network_by_name(self, network_name):
-        net = self.admin_manager.networks_client.list_networks(
+        net = self.os_admin.networks_client.list_networks(
             name=network_name)['networks']
-        self.assertNotEqual(len(net), 0,
+        self.assertNotEmpty(net,
                             "Unable to get network by name: %s" % network_name)
         return net[0]
 
@@ -1019,7 +1019,7 @@
             if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
         ]
         msg = "No default security group for tenant %s." % (tenant_id)
-        self.assertGreater(len(sgs), 0, msg)
+        self.assertNotEmpty(sgs, msg)
         return sgs[0]
 
     def _create_security_group_rule(self, secgroup=None,
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 8408a1e..25227be 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -36,8 +36,8 @@
     def setup_clients(cls):
         super(TestAggregatesBasicOps, cls).setup_clients()
         # Use admin client by default
-        cls.aggregates_client = cls.admin_manager.aggregates_client
-        cls.hosts_client = cls.admin_manager.hosts_client
+        cls.aggregates_client = cls.os_admin.aggregates_client
+        cls.hosts_client = cls.os_admin.hosts_client
 
     def _create_aggregate(self, **kwargs):
         aggregate = (self.aggregates_client.create_aggregate(**kwargs)
@@ -52,7 +52,7 @@
 
     def _get_host_name(self):
         hosts = self.hosts_client.list_hosts()['hosts']
-        self.assertGreaterEqual(len(hosts), 1)
+        self.assertNotEmpty(hosts)
         computes = [x for x in hosts if x['service'] == 'compute']
         return computes[0]['host_name']
 
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 1957164..26a834b 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -103,6 +103,8 @@
     @decorators.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8')
     @testtools.skipUnless(CONF.network.public_network_id,
                           'The public_network_id option must be specified.')
+    @testtools.skipUnless(CONF.network_feature_enabled.floating_ips,
+                          'Floating ips are not available')
     @test.services('compute', 'volume', 'image', 'network')
     def test_minimum_basic_scenario(self):
         image = self.glance_image_create()
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index c2fc1a7..c8add8b 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -48,6 +48,8 @@
             msg = ('Either project_networks_reachable must be "true", or '
                    'public_network_id must be defined.')
             raise cls.skipException(msg)
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
 
     @classmethod
     def setup_credentials(cls):
@@ -60,7 +62,7 @@
         if test.is_extension_enabled('security-group', 'network'):
             security_group = self._create_security_group()
             security_groups = [{'name': security_group['name']}]
-        network, subnet, router = self.create_networks()
+        network, _, _ = self.create_networks()
         server = self.create_server(
             networks=[{'uuid': network['id']}],
             key_name=keypair['name'],
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index a42691b..48ddac6 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -90,6 +90,8 @@
             if not test.is_extension_enabled(ext, 'network'):
                 msg = "%s extension not enabled." % ext
                 raise cls.skipException(msg)
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
 
     @classmethod
     def setup_credentials(cls):
@@ -126,21 +128,21 @@
         via checking the result of list_[networks,routers,subnets]
         """
 
-        seen_nets = self.admin_manager.networks_client.list_networks()
+        seen_nets = self.os_admin.networks_client.list_networks()
         seen_names = [n['name'] for n in seen_nets['networks']]
         seen_ids = [n['id'] for n in seen_nets['networks']]
         self.assertIn(self.network['name'], seen_names)
         self.assertIn(self.network['id'], seen_ids)
 
         if self.subnet:
-            seen_subnets = self.admin_manager.subnets_client.list_subnets()
+            seen_subnets = self.os_admin.subnets_client.list_subnets()
             seen_net_ids = [n['network_id'] for n in seen_subnets['subnets']]
             seen_subnet_ids = [n['id'] for n in seen_subnets['subnets']]
             self.assertIn(self.network['id'], seen_net_ids)
             self.assertIn(self.subnet['id'], seen_subnet_ids)
 
         if self.router:
-            seen_routers = self.admin_manager.routers_client.list_routers()
+            seen_routers = self.os_admin.routers_client.list_routers()
             seen_router_ids = [n['id'] for n in seen_routers['routers']]
             seen_router_names = [n['name'] for n in seen_routers['routers']]
             self.assertIn(self.router['name'],
@@ -210,7 +212,7 @@
             self.servers, mtu=mtu)
 
     def _disassociate_floating_ips(self):
-        floating_ip, server = self.floating_ip_tuple
+        floating_ip, _ = self.floating_ip_tuple
         self._disassociate_floating_ip(floating_ip)
         self.floating_ip_tuple = Floating_IP_tuple(
             floating_ip, None)
@@ -241,7 +243,7 @@
             ip_address, private_key=private_key, server=server)
         old_nic_list = self._get_server_nics(ssh_client)
         # get a port from a list of one item
-        port_list = self.admin_manager.ports_client.list_ports(
+        port_list = self.os_admin.ports_client.list_ports(
             device_id=server['id'])['ports']
         self.assertEqual(1, len(port_list))
         old_port = port_list[0]
@@ -257,7 +259,7 @@
         def check_ports():
             self.new_port_list = [
                 port for port in
-                self.admin_manager.ports_client.list_ports(
+                self.os_admin.ports_client.list_ports(
                     device_id=server['id'])['ports']
                 if port['id'] != old_port['id']
             ]
@@ -285,7 +287,7 @@
                                               "guest after %s sec"
                                               % CONF.network.build_timeout)
 
-        num, new_nic = self.diff_list[0]
+        _, new_nic = self.diff_list[0]
         ssh_client.exec_command("sudo ip addr add %s/%s dev %s" % (
                                 new_port['fixed_ips'][0]['ip_address'],
                                 CONF.network.project_network_mask_bits,
@@ -293,7 +295,7 @@
         ssh_client.exec_command("sudo ip link set %s up" % new_nic)
 
     def _get_server_nics(self, ssh_client):
-        reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
+        reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+)[@]?.*:')
         ipatxt = ssh_client.exec_command("ip address")
         return reg.findall(ipatxt)
 
@@ -309,7 +311,7 @@
         # get all network ports in the new network
         internal_ips = (
             p['fixed_ips'][0]['ip_address'] for p in
-            self.admin_manager.ports_client.list_ports(
+            self.os_admin.ports_client.list_ports(
                 tenant_id=server['tenant_id'],
                 network_id=network['id'])['ports']
             if p['device_owner'].startswith('network')
@@ -330,7 +332,7 @@
         # which is always IPv4, so we must only test connectivity to
         # external IPv4 IPs if the external network is dualstack.
         v4_subnets = [
-            s for s in self.admin_manager.subnets_client.list_subnets(
+            s for s in self.os_admin.subnets_client.list_subnets(
                 network_id=CONF.network.public_network_id)['subnets']
             if s['ip_version'] == 4
         ]
@@ -629,9 +631,9 @@
                 admin_state_up attribute of instance port to True
         """
         self._setup_network_and_servers()
-        floating_ip, server = self.floating_ip_tuple
+        _, server = self.floating_ip_tuple
         server_id = server['id']
-        port_id = self.admin_manager.ports_client.list_ports(
+        port_id = self.os_admin.ports_client.list_ports(
             device_id=server_id)['ports'][0]['id']
         server_pip = server['addresses'][self.network['name']][0]['addr']
 
@@ -687,7 +689,7 @@
                              'Server should have been created from a '
                              'pre-existing port.')
         # Assert the port is bound to the server.
-        port_list = self.admin_manager.ports_client.list_ports(
+        port_list = self.os_admin.ports_client.list_ports(
             device_id=server['id'], network_id=self.network['id'])['ports']
         self.assertEqual(1, len(port_list),
                          'There should only be one port created for '
@@ -706,7 +708,7 @@
         # Boot another server with the same port to make sure nothing was
         # left around that could cause issues.
         server = self._create_server(self.network, port['id'])
-        port_list = self.admin_manager.ports_client.list_ports(
+        port_list = self.os_admin.ports_client.list_ports(
             device_id=server['id'], network_id=self.network['id'])['ports']
         self.assertEqual(1, len(port_list),
                          'There should only be one port created for '
@@ -731,23 +733,23 @@
         # TODO(yfried): refactor this test to be used for other agents (dhcp)
         # as well
 
-        list_hosts = (self.admin_manager.routers_client.
+        list_hosts = (self.os_admin.routers_client.
                       list_l3_agents_hosting_router)
-        schedule_router = (self.admin_manager.network_agents_client.
+        schedule_router = (self.os_admin.network_agents_client.
                            create_router_on_l3_agent)
-        unschedule_router = (self.admin_manager.network_agents_client.
+        unschedule_router = (self.os_admin.network_agents_client.
                              delete_router_from_l3_agent)
 
         agent_list_alive = set(
             a["id"] for a in
-            self.admin_manager.network_agents_client.list_agents(
+            self.os_admin.network_agents_client.list_agents(
                 agent_type="L3 agent")['agents'] if a["alive"] is True
         )
         self._setup_network_and_servers()
 
         # NOTE(kevinbenton): we have to use the admin credentials to check
         # for the distributed flag because self.router only has a project view.
-        admin = self.admin_manager.routers_client.show_router(
+        admin = self.os_admin.routers_client.show_router(
             self.router['id'])
         if admin['router'].get('distributed', False):
             msg = "Rescheduling test does not apply to distributed routers."
@@ -825,7 +827,7 @@
         self._create_new_network()
         self._hotplug_server()
         fip, server = self.floating_ip_tuple
-        new_ports = self.admin_manager.ports_client.list_ports(
+        new_ports = self.os_admin.ports_client.list_ports(
             device_id=server["id"], network_id=self.new_net["id"])['ports']
         spoof_port = new_ports[0]
         private_key = self._get_server_key(server)
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index c5958f7..bf26c2e 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -51,6 +51,8 @@
         if CONF.network.shared_physical_network:
             msg = 'Deployment uses a shared physical network'
             raise cls.skipException(msg)
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
 
     @classmethod
     def setup_credentials(cls):
@@ -144,7 +146,7 @@
         """
         ports = [
             p["mac_address"] for p in
-            self.admin_manager.ports_client.list_ports(
+            self.os_admin.ports_client.list_ports(
                 device_id=sid, network_id=network_id)['ports']
         ]
 
@@ -169,7 +171,7 @@
 
         # Turn on 2nd NIC for Cirros when dualnet
         if dualnet:
-            network, network_v6 = net_list
+            _, network_v6 = net_list
             self.turn_nic6_on(sshv4_1, sid1, network_v6['id'])
             self.turn_nic6_on(sshv4_2, sid2, network_v6['id'])
 
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 2116fe8..41c60f1 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -148,6 +148,8 @@
             msg = ('Deployment uses a shared physical network, security '
                    'groups not supported')
             raise cls.skipException(msg)
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
 
     @classmethod
     def setup_credentials(cls):
@@ -168,7 +170,7 @@
 
         cls.floating_ips = {}
         cls.tenants = {}
-        cls.primary_tenant = cls.TenantProperties(cls.os)
+        cls.primary_tenant = cls.TenantProperties(cls.os_primary)
         cls.alt_tenant = cls.TenantProperties(cls.os_alt)
         for tenant in [cls.primary_tenant, cls.alt_tenant]:
             cls.tenants[tenant.creds.tenant_id] = tenant
@@ -221,7 +223,7 @@
         # Checks that we see the newly created network/subnet/router via
         # checking the result of list_[networks,routers,subnets]
         # Check that (router, subnet) couple exist in port_list
-        seen_nets = self.admin_manager.networks_client.list_networks()
+        seen_nets = self.os_admin.networks_client.list_networks()
         seen_names = [n['name'] for n in seen_nets['networks']]
         seen_ids = [n['id'] for n in seen_nets['networks']]
 
@@ -230,13 +232,13 @@
 
         seen_subnets = [
             (n['id'], n['cidr'], n['network_id']) for n in
-            self.admin_manager.subnets_client.list_subnets()['subnets']
+            self.os_admin.subnets_client.list_subnets()['subnets']
         ]
         mysubnet = (tenant.subnet['id'], tenant.subnet['cidr'],
                     tenant.network['id'])
         self.assertIn(mysubnet, seen_subnets)
 
-        seen_routers = self.admin_manager.routers_client.list_routers()
+        seen_routers = self.os_admin.routers_client.list_routers()
         seen_router_ids = [n['id'] for n in seen_routers['routers']]
         seen_router_names = [n['name'] for n in seen_routers['routers']]
 
@@ -246,7 +248,7 @@
         myport = (tenant.router['id'], tenant.subnet['id'])
         router_ports = [
             (i['device_id'], f['subnet_id'])
-            for i in self.admin_manager.ports_client.list_ports(
+            for i in self.os_admin.ports_client.list_ports(
                 device_id=tenant.router['id'])['ports']
             if net_info.is_router_interface_port(i)
             for f in i['fixed_ips']
@@ -279,7 +281,7 @@
 
         # Verify servers are on different compute nodes
         if self.multi_node:
-            adm_get_server = self.admin_manager.servers_client.show_server
+            adm_get_server = self.os_admin.servers_client.show_server
             new_host = adm_get_server(server["id"])["server"][
                 "OS-EXT-SRV-ATTR:host"]
             host_list = [adm_get_server(s)["server"]["OS-EXT-SRV-ATTR:host"]
@@ -447,7 +449,7 @@
         mac_addr = mac_addr.strip().lower()
         # Get the fixed_ips and mac_address fields of all ports. Select
         # only those two columns to reduce the size of the response.
-        port_list = self.admin_manager.ports_client.list_ports(
+        port_list = self.os_admin.ports_client.list_ports(
             fields=['fixed_ips', 'mac_address'])['ports']
         port_detail_list = [
             (port['fixed_ips'][0]['subnet_id'],
@@ -541,7 +543,7 @@
                                            dest=self._get_server_ip(server),
                                            should_succeed=False)
             server_id = server['id']
-            port_id = self.admin_manager.ports_client.list_ports(
+            port_id = self.os_admin.ports_client.list_ports(
                 device_id=server_id)['ports'][0]['id']
 
             # update port with new security group and check connectivity
@@ -605,7 +607,7 @@
 
         access_point_ssh = self._connect_to_access_point(new_tenant)
         server_id = server['id']
-        port_id = self.admin_manager.ports_client.list_ports(
+        port_id = self.os_admin.ports_client.list_ports(
             device_id=server_id)['ports'][0]['id']
 
         # Flip the port's port security and check connectivity
@@ -647,7 +649,7 @@
         sec_groups = []
         server = self._create_server(name, tenant, sec_groups)
         server_id = server['id']
-        ports = self.admin_manager.ports_client.list_ports(
+        ports = self.os_admin.ports_client.list_ports(
             device_id=server_id)['ports']
         self.assertEqual(1, len(ports))
         for port in ports:
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index cf2ccbe..0c441ab 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -43,6 +43,12 @@
      * Terminate the instance
     """
 
+    @classmethod
+    def skip_checks(cls):
+        super(TestServerBasicOps, cls).skip_checks()
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
+
     def setUp(self):
         super(TestServerBasicOps, self).setUp()
         self.run_ssh = CONF.validation.run_validation
diff --git a/tempest/scenario/test_server_multinode.py b/tempest/scenario/test_server_multinode.py
index d9bff09..552ab27 100644
--- a/tempest/scenario/test_server_multinode.py
+++ b/tempest/scenario/test_server_multinode.py
@@ -13,7 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-
 from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions
@@ -35,15 +34,6 @@
             raise cls.skipException(
                 "Less than 2 compute nodes, skipping multinode tests.")
 
-    @classmethod
-    def setup_clients(cls):
-        super(TestServerMultinode, cls).setup_clients()
-        # Use admin client by default
-        cls.manager = cls.admin_manager
-        # this is needed so that we can use the availability_zone:host
-        # scheduler hint, which is admin_only by default
-        cls.servers_client = cls.admin_manager.servers_client
-
     @decorators.idempotent_id('9cecbe35-b9d4-48da-a37e-7ce70aa43d30')
     @decorators.attr(type='smoke')
     @test.services('compute', 'network')
@@ -74,9 +64,13 @@
         for host in hosts[:CONF.compute.min_compute_nodes]:
             # by getting to active state here, this means this has
             # landed on the host in question.
+            # in order to use the availability_zone:host scheduler hint,
+            # admin client is need here.
             inst = self.create_server(
+                clients=self.os_admin,
                 availability_zone='%(zone)s:%(host_name)s' % host)
-            server = self.servers_client.show_server(inst['id'])['server']
+            server = self.os_admin.servers_client.show_server(
+                inst['id'])['server']
             # ensure server is located on the requested host
             self.assertEqual(host['host_name'], server['OS-EXT-SRV-ATTR:host'])
             servers.append(server)
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
index 63dc23d..81b71b1 100644
--- a/tempest/scenario/test_volume_migrate_attached.py
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -41,6 +41,7 @@
     def setup_clients(cls):
         super(TestVolumeMigrateRetypeAttached, cls).setup_clients()
         cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client
+        cls.admin_volumes_client = cls.os_admin.volumes_v2_client
 
     @classmethod
     def skip_checks(cls):
@@ -82,7 +83,7 @@
 
     def _volume_retype_with_migration(self, volume_id, new_volume_type):
         migration_policy = 'on-demand'
-        self.volumes_client.retype_volume(
+        self.admin_volumes_client.retype_volume(
             volume_id, new_type=new_volume_type,
             migration_policy=migration_policy)
         waiters.wait_for_volume_retype(self.volumes_client,
diff --git a/tempest/test.py b/tempest/test.py
index e8108f4..f07c071 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -373,9 +373,9 @@
     @classmethod
     def resource_setup(cls):
         """Class level resource setup for test cases."""
-        if hasattr(cls, "os"):
+        if hasattr(cls, "os_primary"):
             cls.validation_resources = vresources.create_validation_resources(
-                cls.os, cls.validation_resources)
+                cls.os_primary, cls.validation_resources)
         else:
             LOG.warning("Client manager not found, validation resources not"
                         " created")
@@ -388,8 +388,8 @@
         resources, in case a failure during `resource_setup` should happen.
         """
         if cls.validation_resources:
-            if hasattr(cls, "os"):
-                vresources.clear_validation_resources(cls.os,
+            if hasattr(cls, "os_primary"):
+                vresources.clear_validation_resources(cls.os_primary,
                                                       cls.validation_resources)
                 cls.validation_resources = {}
             else:
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 98bf145..640dcd4 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -12,9 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import fixtures
 import mock
 from oslo_serialization import jsonutils as json
-from oslotest import mockpatch
 
 from tempest.cmd import verify_tempest_config
 from tempest import config
@@ -73,12 +73,12 @@
                          fake_config.FakePrivate)
 
     def test_get_keystone_api_versions(self):
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
         fake_resp = {'versions': {'values': [{'id': 'v2.0'}, {'id': 'v3.0'}]}}
         fake_resp = json.dumps(fake_resp)
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.lib.common.http.ClosingHttp.request',
             return_value=(None, fake_resp)))
         fake_os = mock.MagicMock()
@@ -87,12 +87,12 @@
         self.assertIn('v3.0', versions)
 
     def test_get_cinder_api_versions(self):
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
         fake_resp = {'versions': [{'id': 'v1.0'}, {'id': 'v2.0'}]}
         fake_resp = json.dumps(fake_resp)
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.lib.common.http.ClosingHttp.request',
             return_value=(None, fake_resp)))
         fake_os = mock.MagicMock()
@@ -101,12 +101,12 @@
         self.assertIn('v2.0', versions)
 
     def test_get_nova_versions(self):
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
         fake_resp = {'versions': [{'id': 'v2.0'}, {'id': 'v3.0'}]}
         fake_resp = json.dumps(fake_resp)
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.lib.common.http.ClosingHttp.request',
             return_value=(None, fake_resp)))
         fake_os = mock.MagicMock()
@@ -117,17 +117,17 @@
     def test_get_versions_invalid_response(self):
         # When the response doesn't contain a JSON response, an error is
         # logged.
-        mock_log_error = self.useFixture(mockpatch.PatchObject(
+        mock_log_error = self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config.LOG, 'error')).mock
 
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, '_get_unversioned_endpoint'))
 
         # Simulated response is not JSON.
         sample_body = (
             '<html><head>Sample Response</head><body>This is the sample page '
             'for the web server. Why are you requesting it?</body></html>')
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.lib.common.http.ClosingHttp.request',
             return_value=(None, sample_body)))
 
@@ -157,7 +157,7 @@
 
     @mock.patch('tempest.lib.common.http.ClosingHttp.request')
     def test_verify_keystone_api_versions_no_v3(self, mock_request):
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
         fake_resp = {'versions': {'values': [{'id': 'v2.0'}]}}
@@ -173,7 +173,7 @@
 
     @mock.patch('tempest.lib.common.http.ClosingHttp.request')
     def test_verify_keystone_api_versions_no_v2(self, mock_request):
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
         fake_resp = {'versions': {'values': [{'id': 'v3.0'}]}}
@@ -189,7 +189,7 @@
 
     @mock.patch('tempest.lib.common.http.ClosingHttp.request')
     def test_verify_cinder_api_versions_no_v3(self, mock_request):
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
         fake_resp = {'versions': [{'id': 'v2.0'}]}
@@ -203,7 +203,7 @@
 
     @mock.patch('tempest.lib.common.http.ClosingHttp.request')
     def test_verify_cinder_api_versions_no_v2(self, mock_request):
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
         fake_resp = {'versions': [{'id': 'v3.0'}]}
@@ -221,7 +221,7 @@
 
     @mock.patch('tempest.lib.common.http.ClosingHttp.request')
     def test_verify_cinder_api_versions_no_v1(self, mock_request):
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
         fake_resp = {'versions': [{'id': 'v2.0'}, {'id': 'v3.0'}]}
@@ -276,7 +276,7 @@
         fake_os = mock.MagicMock()
         fake_os.network_extensions_client.list_extensions = (
             fake_list_extensions)
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['fake1', 'fake2', 'fake3'])))
         results = verify_tempest_config.verify_extensions(fake_os,
@@ -299,7 +299,7 @@
         fake_os = mock.MagicMock()
         fake_os.network_extensions_client.list_extensions = (
             fake_list_extensions)
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['all'])))
         results = verify_tempest_config.verify_extensions(fake_os,
@@ -319,7 +319,7 @@
         fake_os.volumes_extension_client.list_extensions = fake_list_extensions
         fake_os.volumes_v2_extension_client.list_extensions = (
             fake_list_extensions)
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['fake1', 'fake2', 'fake3'])))
         results = verify_tempest_config.verify_extensions(fake_os,
@@ -344,7 +344,7 @@
         fake_os.volumes_extension_client.list_extensions = fake_list_extensions
         fake_os.volumes_v2_extension_client.list_extensions = (
             fake_list_extensions)
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['all'])))
         results = verify_tempest_config.verify_extensions(fake_os,
@@ -360,7 +360,7 @@
                      {'alias': 'not_fake'}])
         fake_os = mock.MagicMock()
         fake_os.extensions_client.list_extensions = fake_list_extensions
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['fake1', 'fake2', 'fake3'])))
         results = verify_tempest_config.verify_extensions(fake_os,
@@ -382,7 +382,7 @@
                                     {'alias': 'not_fake'}]})
         fake_os = mock.MagicMock()
         fake_os.extensions_client.list_extensions = fake_list_extensions
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['all'])))
         results = verify_tempest_config.verify_extensions(fake_os,
@@ -400,7 +400,7 @@
                            'swift': 'metadata'})
         fake_os = mock.MagicMock()
         fake_os.capabilities_client.list_capabilities = fake_list_extensions
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['fake1', 'fake2', 'fake3'])))
         results = verify_tempest_config.verify_extensions(fake_os, 'swift', {})
@@ -422,7 +422,7 @@
                            'swift': 'metadata'})
         fake_os = mock.MagicMock()
         fake_os.capabilities_client.list_capabilities = fake_list_extensions
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['all'])))
         results = verify_tempest_config.verify_extensions(fake_os,
diff --git a/tempest/tests/common/test_admin_available.py b/tempest/tests/common/test_admin_available.py
index 01a9cd0..c3d248c 100644
--- a/tempest/tests/common/test_admin_available.py
+++ b/tempest/tests/common/test_admin_available.py
@@ -12,8 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import fixtures
 from oslo_config import cfg
-from oslotest import mockpatch
 
 from tempest.common import credentials_factory as credentials
 from tempest import config
@@ -52,16 +52,16 @@
                                  'project_name': 'admin',
                                  'password': 'p',
                                  'types': ['admin']})
-            self.useFixture(mockpatch.Patch(
+            self.useFixture(fixtures.MockPatch(
                 'tempest.common.preprov_creds.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))
+            self.useFixture(fixtures.MockPatch('os.path.isfile',
+                                               return_value=True))
         else:
-            self.useFixture(mockpatch.Patch('os.path.isfile',
-                                            return_value=False))
+            self.useFixture(fixtures.MockPatch('os.path.isfile',
+                                               return_value=False))
             if admin_creds:
                 username = 'u'
                 project = 't'
diff --git a/tempest/tests/common/test_alt_available.py b/tempest/tests/common/test_alt_available.py
index 27db95c..b9a8967 100644
--- a/tempest/tests/common/test_alt_available.py
+++ b/tempest/tests/common/test_alt_available.py
@@ -12,8 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import fixtures
 from oslo_config import cfg
-from oslotest import mockpatch
 
 from tempest.common import credentials_factory as credentials
 from tempest import config
@@ -39,16 +39,16 @@
             accounts = [dict(username="u%s" % ii,
                              project_name="t%s" % ii,
                              password="p") for ii in creds]
-            self.useFixture(mockpatch.Patch(
+            self.useFixture(fixtures.MockPatch(
                 'tempest.common.preprov_creds.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))
+            self.useFixture(fixtures.MockPatch('os.path.isfile',
+                                               return_value=True))
         else:
-            self.useFixture(mockpatch.Patch('os.path.isfile',
-                                            return_value=False))
+            self.useFixture(fixtures.MockPatch('os.path.isfile',
+                                               return_value=False))
         expected = len(set(creds)) > 1 or dynamic_creds
         observed = credentials.is_alt_available(
             identity_version=self.identity_version)
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index b4fbd50..c739619 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -12,9 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import fixtures
 import mock
 from oslo_config import cfg
-from oslotest import mockpatch
 
 from tempest.common import credentials_factory as credentials
 from tempest.common import dynamic_creds
@@ -84,7 +84,7 @@
             tenant_name='fake_tenant')
 
     def _mock_user_create(self, id, name):
-        user_fix = self.useFixture(mockpatch.PatchObject(
+        user_fix = self.useFixture(fixtures.MockPatchObject(
             self.users_client.UsersClient,
             'create_user',
             return_value=(rest_client.ResponseBody
@@ -92,7 +92,7 @@
         return user_fix
 
     def _mock_tenant_create(self, id, name):
-        tenant_fix = self.useFixture(mockpatch.PatchObject(
+        tenant_fix = self.useFixture(fixtures.MockPatchObject(
             self.tenants_client.TenantsClient,
             'create_tenant',
             return_value=(rest_client.ResponseBody
@@ -100,7 +100,7 @@
         return tenant_fix
 
     def _mock_list_roles(self, id, name):
-        roles_fix = self.useFixture(mockpatch.PatchObject(
+        roles_fix = self.useFixture(fixtures.MockPatchObject(
             self.roles_client.RolesClient,
             'list_roles',
             return_value=(rest_client.ResponseBody
@@ -111,7 +111,7 @@
         return roles_fix
 
     def _mock_list_2_roles(self):
-        roles_fix = self.useFixture(mockpatch.PatchObject(
+        roles_fix = self.useFixture(fixtures.MockPatchObject(
             self.roles_client.RolesClient,
             'list_roles',
             return_value=(rest_client.ResponseBody
@@ -122,7 +122,7 @@
         return roles_fix
 
     def _mock_assign_user_role(self):
-        tenant_fix = self.useFixture(mockpatch.PatchObject(
+        tenant_fix = self.useFixture(fixtures.MockPatchObject(
             self.roles_client.RolesClient,
             'create_user_role_on_project',
             return_value=(rest_client.ResponseBody
@@ -130,7 +130,7 @@
         return tenant_fix
 
     def _mock_list_role(self):
-        roles_fix = self.useFixture(mockpatch.PatchObject(
+        roles_fix = self.useFixture(fixtures.MockPatchObject(
             self.roles_client.RolesClient,
             'list_roles',
             return_value=(rest_client.ResponseBody
@@ -140,7 +140,7 @@
         return roles_fix
 
     def _mock_list_ec2_credentials(self, user_id, tenant_id):
-        ec2_creds_fix = self.useFixture(mockpatch.PatchObject(
+        ec2_creds_fix = self.useFixture(fixtures.MockPatchObject(
             self.users_client.UsersClient,
             'list_user_ec2_credentials',
             return_value=(rest_client.ResponseBody
@@ -153,21 +153,21 @@
         return ec2_creds_fix
 
     def _mock_network_create(self, iso_creds, id, name):
-        net_fix = self.useFixture(mockpatch.PatchObject(
+        net_fix = self.useFixture(fixtures.MockPatchObject(
             iso_creds.networks_admin_client,
             'create_network',
             return_value={'network': {'id': id, 'name': name}}))
         return net_fix
 
     def _mock_subnet_create(self, iso_creds, id, name):
-        subnet_fix = self.useFixture(mockpatch.PatchObject(
+        subnet_fix = self.useFixture(fixtures.MockPatchObject(
             iso_creds.subnets_admin_client,
             'create_subnet',
             return_value={'subnet': {'id': id, 'name': name}}))
         return subnet_fix
 
     def _mock_router_create(self, id, name):
-        router_fix = self.useFixture(mockpatch.PatchObject(
+        router_fix = self.useFixture(fixtures.MockPatchObject(
             routers_client.RoutersClient,
             'create_router',
             return_value={'router': {'id': id, 'name': name}}))
@@ -634,7 +634,7 @@
     def setUp(self):
         super(TestDynamicCredentialProviderV3, self).setUp()
         self.useFixture(fake_config.ConfigFixture())
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             domains_client.DomainsClient, 'list_domains',
             return_value=dict(domains=[dict(id='default',
                                             name='Default')])))
@@ -645,7 +645,7 @@
         pass
 
     def _mock_tenant_create(self, id, name):
-        project_fix = self.useFixture(mockpatch.PatchObject(
+        project_fix = self.useFixture(fixtures.MockPatchObject(
             self.tenants_client.ProjectsClient,
             'create_project',
             return_value=(rest_client.ResponseBody
diff --git a/tempest/tests/common/test_preprov_creds.py b/tempest/tests/common/test_preprov_creds.py
index 2fd375d..414b106 100644
--- a/tempest/tests/common/test_preprov_creds.py
+++ b/tempest/tests/common/test_preprov_creds.py
@@ -20,9 +20,9 @@
 import six
 import testtools
 
+import fixtures
 from oslo_concurrency.fixture import lockutils as lockutils_fixtures
 from oslo_config import cfg
-from oslotest import mockpatch
 
 from tempest.common import preprov_creds
 from tempest import config
@@ -86,10 +86,11 @@
         self.patch(self.token_client, side_effect=self.identity_response)
         self.useFixture(lockutils_fixtures.ExternalLockFixture())
         self.test_accounts = self._fake_accounts(cfg.CONF.identity.admin_role)
-        self.accounts_mock = self.useFixture(mockpatch.Patch(
+        self.accounts_mock = self.useFixture(fixtures.MockPatch(
             'tempest.common.preprov_creds.read_accounts_yaml',
             return_value=self.test_accounts))
-        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+        self.useFixture(fixtures.MockPatch(
+            'os.path.isfile', return_value=True))
 
     def tearDown(self):
         super(TestPreProvisionedCredentials, self).tearDown()
@@ -138,7 +139,8 @@
 
     def test_create_hash_file_previous_file(self):
         # Emulate the lock existing on the filesystem
-        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+        self.useFixture(fixtures.MockPatch(
+            'os.path.isfile', return_value=True))
         with mock.patch('six.moves.builtins.open', mock.mock_open(),
                         create=True):
             test_account_class = (
@@ -150,7 +152,8 @@
 
     def test_create_hash_file_no_previous_file(self):
         # Emulate the lock not existing on the filesystem
-        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=False))
+        self.useFixture(fixtures.MockPatch(
+            'os.path.isfile', return_value=False))
         with mock.patch('six.moves.builtins.open', mock.mock_open(),
                         create=True):
             test_account_class = (
@@ -163,10 +166,12 @@
     @mock.patch('oslo_concurrency.lockutils.lock')
     def test_get_free_hash_no_previous_accounts(self, lock_mock):
         # Emulate no pre-existing lock
-        self.useFixture(mockpatch.Patch('os.path.isdir', return_value=False))
+        self.useFixture(fixtures.MockPatch(
+            'os.path.isdir', return_value=False))
         hash_list = self._get_hash_list(self.test_accounts)
-        mkdir_mock = self.useFixture(mockpatch.Patch('os.mkdir'))
-        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=False))
+        mkdir_mock = self.useFixture(fixtures.MockPatch('os.mkdir'))
+        self.useFixture(fixtures.MockPatch(
+            'os.path.isfile', return_value=False))
         test_account_class = preprov_creds.PreProvisionedCredentialProvider(
             **self.fixed_params)
         with mock.patch('six.moves.builtins.open', mock.mock_open(),
@@ -182,9 +187,10 @@
     def test_get_free_hash_no_free_accounts(self, lock_mock):
         hash_list = self._get_hash_list(self.test_accounts)
         # Emulate pre-existing lock dir
-        self.useFixture(mockpatch.Patch('os.path.isdir', return_value=True))
-        # Emulate all lcoks in list are in use
-        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+        self.useFixture(fixtures.MockPatch('os.path.isdir', return_value=True))
+        # Emulate all locks in list are in use
+        self.useFixture(fixtures.MockPatch(
+            'os.path.isfile', return_value=True))
         test_account_class = preprov_creds.PreProvisionedCredentialProvider(
             **self.fixed_params)
         with mock.patch('six.moves.builtins.open', mock.mock_open(),
@@ -195,7 +201,7 @@
     @mock.patch('oslo_concurrency.lockutils.lock')
     def test_get_free_hash_some_in_use_accounts(self, lock_mock):
         # Emulate no pre-existing lock
-        self.useFixture(mockpatch.Patch('os.path.isdir', return_value=True))
+        self.useFixture(fixtures.MockPatch('os.path.isdir', return_value=True))
         hash_list = self._get_hash_list(self.test_accounts)
         test_account_class = preprov_creds.PreProvisionedCredentialProvider(
             **self.fixed_params)
@@ -219,13 +225,14 @@
     def test_remove_hash_last_account(self, lock_mock):
         hash_list = self._get_hash_list(self.test_accounts)
         # Pretend the pseudo-lock is there
-        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+        self.useFixture(
+            fixtures.MockPatch('os.path.isfile', return_value=True))
         # Pretend the lock dir is empty
-        self.useFixture(mockpatch.Patch('os.listdir', return_value=[]))
+        self.useFixture(fixtures.MockPatch('os.listdir', return_value=[]))
         test_account_class = preprov_creds.PreProvisionedCredentialProvider(
             **self.fixed_params)
-        remove_mock = self.useFixture(mockpatch.Patch('os.remove'))
-        rmdir_mock = self.useFixture(mockpatch.Patch('os.rmdir'))
+        remove_mock = self.useFixture(fixtures.MockPatch('os.remove'))
+        rmdir_mock = self.useFixture(fixtures.MockPatch('os.rmdir'))
         test_account_class.remove_hash(hash_list[2])
         hash_path = os.path.join(self.fixed_params['accounts_lock_dir'],
                                  hash_list[2])
@@ -237,14 +244,15 @@
     def test_remove_hash_not_last_account(self, lock_mock):
         hash_list = self._get_hash_list(self.test_accounts)
         # Pretend the pseudo-lock is there
-        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+        self.useFixture(fixtures.MockPatch(
+            'os.path.isfile', return_value=True))
         # Pretend the lock dir is empty
-        self.useFixture(mockpatch.Patch('os.listdir', return_value=[
+        self.useFixture(fixtures.MockPatch('os.listdir', return_value=[
             hash_list[1], hash_list[4]]))
         test_account_class = preprov_creds.PreProvisionedCredentialProvider(
             **self.fixed_params)
-        remove_mock = self.useFixture(mockpatch.Patch('os.remove'))
-        rmdir_mock = self.useFixture(mockpatch.Patch('os.rmdir'))
+        remove_mock = self.useFixture(fixtures.MockPatch('os.remove'))
+        rmdir_mock = self.useFixture(fixtures.MockPatch('os.rmdir'))
         test_account_class.remove_hash(hash_list[2])
         hash_path = os.path.join(self.fixed_params['accounts_lock_dir'],
                                  hash_list[2])
@@ -258,7 +266,7 @@
 
     def test_is_not_multi_user(self):
         self.test_accounts = [self.test_accounts[0]]
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.common.preprov_creds.read_accounts_yaml',
             return_value=self.test_accounts))
         test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -270,7 +278,7 @@
             **self.fixed_params)
         hashes = test_accounts_class.hash_dict['roles']['role4']
         temp_hash = hashes[0]
-        get_free_hash_mock = self.useFixture(mockpatch.PatchObject(
+        get_free_hash_mock = self.useFixture(fixtures.MockPatchObject(
             test_accounts_class, '_get_free_hash', return_value=temp_hash))
         # Test a single role returns all matching roles
         test_accounts_class._get_creds(roles=['role4'])
@@ -287,7 +295,7 @@
         hashes2 = test_accounts_class.hash_dict['roles']['role2']
         hashes = list(set(hashes) & set(hashes2))
         temp_hash = hashes[0]
-        get_free_hash_mock = self.useFixture(mockpatch.PatchObject(
+        get_free_hash_mock = self.useFixture(fixtures.MockPatchObject(
             test_accounts_class, '_get_free_hash', return_value=temp_hash))
         # Test an intersection of multiple roles
         test_accounts_class._get_creds(roles=['role2', 'role4'])
@@ -304,7 +312,7 @@
         admin_hashes = test_accounts_class.hash_dict['roles'][
             cfg.CONF.identity.admin_role]
         temp_hash = hashes[0]
-        get_free_hash_mock = self.useFixture(mockpatch.PatchObject(
+        get_free_hash_mock = self.useFixture(fixtures.MockPatchObject(
             test_accounts_class, '_get_free_hash', return_value=temp_hash))
         # Test an intersection of multiple roles
         test_accounts_class._get_creds()
@@ -322,7 +330,7 @@
             {'username': 'test_user14', 'tenant_name': 'test_tenant14',
              'password': 'p', 'roles': ['role-7', 'role-11'],
              'resources': {'network': 'network-2'}}]
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.common.preprov_creds.read_accounts_yaml',
             return_value=test_accounts))
         test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -350,7 +358,7 @@
     def test_get_primary_creds_none_available(self):
         admin_accounts = [x for x in self.test_accounts if 'test_admin'
                           in x['username']]
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.common.preprov_creds.read_accounts_yaml',
             return_value=admin_accounts))
         test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -368,7 +376,7 @@
     def test_get_alt_creds_none_available(self):
         admin_accounts = [x for x in self.test_accounts if 'test_admin'
                           in x['username']]
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.common.preprov_creds.read_accounts_yaml',
             return_value=admin_accounts))
         test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -389,7 +397,7 @@
              'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']},
             {'username': 'test_admin1', 'tenant_name': 'test_tenant11',
              'password': 'p', 'types': ['admin']}]
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.common.preprov_creds.read_accounts_yaml',
             return_value=test_accounts))
         test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -403,7 +411,7 @@
              'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']},
             {'username': 'test_admin1', 'tenant_name': 'test_tenant11',
              'password': 'p', 'roles': [cfg.CONF.identity.admin_role]}]
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.common.preprov_creds.read_accounts_yaml',
             return_value=test_accounts))
         test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -414,7 +422,7 @@
     def test_get_admin_creds_none_available(self):
         non_admin_accounts = [x for x in self.test_accounts if 'test_admin'
                               not in x['username']]
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.common.preprov_creds.read_accounts_yaml',
             return_value=non_admin_accounts))
         test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
index ecb8e64..739357b 100644
--- a/tempest/tests/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -16,7 +16,6 @@
 
 import fixtures
 from oslo_config import cfg
-from oslotest import mockpatch
 
 from tempest.common.utils.linux import remote_client
 from tempest import config
@@ -64,8 +63,8 @@
         cfg.CONF.set_default('connect_timeout', 1, group='validation')
 
         self.conn = remote_client.RemoteClient('127.0.0.1', 'user', 'pass')
-        self.ssh_mock = self.useFixture(mockpatch.PatchObject(self.conn,
-                                                              'ssh_client'))
+        self.ssh_mock = self.useFixture(fixtures.MockPatchObject(self.conn,
+                                                                 'ssh_client'))
 
     def test_write_to_console_regular_str(self):
         self.conn.write_to_console('test')
@@ -111,7 +110,7 @@
         booted_at = 10000
         uptime_sec = 5000.02
         self.ssh_mock.mock.exec_command.return_value = uptime_sec
-        self.useFixture(mockpatch.PatchObject(
+        self.useFixture(fixtures.MockPatchObject(
             time, 'time', return_value=booted_at + uptime_sec))
         self.assertEqual(self.conn.get_boot_time(),
                          time.localtime(booted_at))
diff --git a/tempest/tests/lib/test_rest_client.py b/tempest/tests/lib/common/test_rest_client.py
similarity index 96%
rename from tempest/tests/lib/test_rest_client.py
rename to tempest/tests/lib/common/test_rest_client.py
index 43bb6d0..4c0bb57 100644
--- a/tempest/tests/lib/test_rest_client.py
+++ b/tempest/tests/lib/common/test_rest_client.py
@@ -15,8 +15,8 @@
 import copy
 import json
 
+import fixtures
 import jsonschema
-from oslotest import mockpatch
 import six
 
 from tempest.lib.common import http
@@ -38,16 +38,16 @@
         self.rest_client = rest_client.RestClient(
             self.fake_auth_provider, None, None)
         self.patchobject(http.ClosingHttp, 'request', self.fake_http.request)
-        self.useFixture(mockpatch.PatchObject(self.rest_client,
-                                              '_log_request'))
+        self.useFixture(fixtures.MockPatchObject(self.rest_client,
+                                                 '_log_request'))
 
 
 class TestRestClientHTTPMethods(BaseRestClientTestClass):
     def setUp(self):
         self.fake_http = fake_http.fake_httplib2()
         super(TestRestClientHTTPMethods, self).setUp()
-        self.useFixture(mockpatch.PatchObject(self.rest_client,
-                                              '_error_checker'))
+        self.useFixture(fixtures.MockPatchObject(self.rest_client,
+                                                 '_error_checker'))
 
     def test_post(self):
         __, return_dict = self.rest_client.post(self.url, {}, {})
@@ -70,8 +70,8 @@
         self.assertEqual('PUT', return_dict['method'])
 
     def test_head(self):
-        self.useFixture(mockpatch.PatchObject(self.rest_client,
-                                              'response_checker'))
+        self.useFixture(fixtures.MockPatchObject(self.rest_client,
+                                                 'response_checker'))
         __, return_dict = self.rest_client.head(self.url)
         self.assertEqual('HEAD', return_dict['method'])
 
@@ -122,8 +122,8 @@
         self._verify_headers(resp)
 
     def test_head(self):
-        self.useFixture(mockpatch.PatchObject(self.rest_client,
-                                              'response_checker'))
+        self.useFixture(fixtures.MockPatchObject(self.rest_client,
+                                                 'response_checker'))
         resp, __ = self.rest_client.head(self.url)
         self._verify_headers(resp)
 
@@ -136,8 +136,8 @@
     def setUp(self):
         self.fake_http = fake_http.fake_httplib2()
         super(TestRestClientUpdateHeaders, self).setUp()
-        self.useFixture(mockpatch.PatchObject(self.rest_client,
-                                              '_error_checker'))
+        self.useFixture(fixtures.MockPatchObject(self.rest_client,
+                                                 '_error_checker'))
         self.headers = {'X-Configuration-Session': 'session_id'}
 
     def test_post_update_headers(self):
@@ -201,8 +201,8 @@
         )
 
     def test_head_update_headers(self):
-        self.useFixture(mockpatch.PatchObject(self.rest_client,
-                                              'response_checker'))
+        self.useFixture(fixtures.MockPatchObject(self.rest_client,
+                                                 'response_checker'))
 
         __, return_dict = self.rest_client.head(self.url,
                                                 extra_headers=True,
@@ -276,6 +276,11 @@
         body = self.rest_client._parse_resp(json.dumps(self.null_dict))
         self.assertEqual(self.null_dict, body)
 
+    def test_parse_empty_list(self):
+        empty_list = []
+        body = self.rest_client._parse_resp(json.dumps(empty_list))
+        self.assertEqual(empty_list, body)
+
 
 class TestRestClientErrorCheckerJSON(base.TestCase):
     c_type = "application/json"
@@ -1145,8 +1150,8 @@
     }
 
     def test_current_json_schema_validator_version(self):
-        with mockpatch.PatchObject(jsonschema.Draft4Validator,
-                                   "check_schema") as chk_schema:
+        with fixtures.MockPatchObject(jsonschema.Draft4Validator,
+                                      "check_schema") as chk_schema:
             body = {'foo': 'test'}
             self._test_validate_pass(self.schema, body)
             chk_schema.mock.assert_called_once_with(
diff --git a/tempest/tests/lib/services/base.py b/tempest/tests/lib/services/base.py
index 71b7f2d..90c9f63 100644
--- a/tempest/tests/lib/services/base.py
+++ b/tempest/tests/lib/services/base.py
@@ -31,12 +31,42 @@
 
     def check_service_client_function(self, function, function2mock,
                                       body, to_utf=False, status=200,
-                                      headers=None, **kwargs):
+                                      headers=None, mock_args=None,
+                                      **kwargs):
+        """Mock a service client function for unit testing.
+
+        :param function: The service client function to call.
+        :param function2mock: The REST call to mock inside the service client
+               function.
+        :param body: Expected response body returned by the service client
+               function.
+        :param to_utf: Whether to use UTF-8 encoding for request.
+        :param status: Expected response status returned by the service client
+               function.
+        :param headers: Expected headers returned by the service client
+               function.
+        :param mock_args: List/dict/value of expected args/kwargs called by
+               function2mock. For example:
+               * If mock_args=['foo'] then ``assert_called_once_with('foo')``
+                 is called.
+               * If mock_args={'foo': 'bar'} then
+                 ``assert_called_once_with(foo='bar')`` is called.
+               * If mock_args='foo' then ``assert_called_once_with('foo')``
+                 is called.
+        :param kwargs: kwargs that are passed to function.
+        """
         mocked_response = self.create_response(body, to_utf, status, headers)
-        self.useFixture(fixtures.MockPatch(
+        fixture = self.useFixture(fixtures.MockPatch(
             function2mock, return_value=mocked_response))
         if kwargs:
             resp = function(**kwargs)
         else:
             resp = function()
         self.assertEqual(body, resp)
+
+        if isinstance(mock_args, list):
+            fixture.mock.assert_called_once_with(*mock_args)
+        elif isinstance(mock_args, dict):
+            fixture.mock.assert_called_once_with(**mock_args)
+        elif mock_args is not None:
+            fixture.mock.assert_called_once_with(mock_args)
diff --git a/tempest/tests/lib/services/compute/test_server_groups_client.py b/tempest/tests/lib/services/compute/test_server_groups_client.py
index 1c535ca..9055a36 100644
--- a/tempest/tests/lib/services/compute/test_server_groups_client.py
+++ b/tempest/tests/lib/services/compute/test_server_groups_client.py
@@ -13,9 +13,10 @@
 #    under the License.
 
 import fixtures
-from tempest.tests.lib import fake_auth_provider
 
+from tempest.lib.services.compute import base_compute_client
 from tempest.lib.services.compute import server_groups_client
+from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib import fake_http
 from tempest.tests.lib.services import base
 
@@ -36,7 +37,7 @@
             fake_auth, 'compute', 'regionOne')
 
     def _test_create_server_group(self, bytes_body=False):
-        expected = {"server_group": TestServerGroupsClient.server_group}
+        expected = {"server_group": self.server_group}
         self.check_service_client_function(
             self.client.create_server_group,
             'tempest.lib.common.rest_client.RestClient.post', expected,
@@ -56,7 +57,7 @@
         self.client.delete_server_group('fake-group')
 
     def _test_list_server_groups(self, bytes_body=False):
-        expected = {"server_groups": [TestServerGroupsClient.server_group]}
+        expected = {"server_groups": [self.server_group]}
         self.check_service_client_function(
             self.client.list_server_groups,
             'tempest.lib.common.rest_client.RestClient.get',
@@ -69,7 +70,7 @@
         self._test_list_server_groups(bytes_body=True)
 
     def _test_show_server_group(self, bytes_body=False):
-        expected = {"server_group": TestServerGroupsClient.server_group}
+        expected = {"server_group": self.server_group}
         self.check_service_client_function(
             self.client.show_server_group,
             'tempest.lib.common.rest_client.RestClient.get',
@@ -81,3 +82,20 @@
 
     def test_show_server_group_byte_body(self):
         self._test_show_server_group(bytes_body=True)
+
+
+class TestServerGroupsClientMinV213(TestServerGroupsClient):
+
+    server_group = {
+        "id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9",
+        "name": "test",
+        "policies": ["anti-affinity"],
+        "members": [],
+        "metadata": {},
+        "project_id": "0beb4bffb7a445eb8eb05fee3ee7660a",
+        "user_id": "86031628064a4f99bb66ec03c507dcd8"}
+
+    def setUp(self):
+        super(TestServerGroupsClientMinV213, self).setUp()
+        self.patchobject(base_compute_client, 'COMPUTE_MICROVERSION',
+                         new='2.13')
diff --git a/tempest/tests/lib/services/identity/v3/test_services_client.py b/tempest/tests/lib/services/identity/v3/test_services_client.py
index f87fcce..b464644 100644
--- a/tempest/tests/lib/services/identity/v3/test_services_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_services_client.py
@@ -101,12 +101,15 @@
             bytes_body,
             service_id="686766")
 
-    def _test_list_services(self, bytes_body=False):
+    def _test_list_services(self, bytes_body=False, mock_args='services',
+                            **params):
         self.check_service_client_function(
             self.client.list_services,
             'tempest.lib.common.rest_client.RestClient.get',
             self.FAKE_LIST_SERVICES,
-            bytes_body)
+            bytes_body,
+            mock_args=[mock_args],
+            **params)
 
     def _test_update_service(self, bytes_body=False):
         self.check_service_client_function(
@@ -134,6 +137,10 @@
     def test_list_services_with_bytes_body(self):
         self._test_list_services(bytes_body=True)
 
+    def test_list_services_with_params(self):
+        self._test_list_services(
+            type='fake-type', mock_args='services?type=fake-type')
+
     def test_update_service_with_str_body(self):
         self._test_update_service()
 
diff --git a/tempest/tests/lib/services/network/test_security_groups_client.py b/tempest/tests/lib/services/network/test_security_groups_client.py
new file mode 100644
index 0000000..d066378
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_security_groups_client.py
@@ -0,0 +1,157 @@
+# Copyright 2017 AT&T 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.
+
+import copy
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.services.network import security_groups_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestSecurityGroupsClient(base.BaseServiceTest):
+
+    FAKE_SEC_GROUP_ID = "85cc3048-abc3-43cc-89b3-377341426ac5"
+
+    FAKE_SECURITY_GROUPS = {
+        "security_groups": [
+            {
+                "description": "default",
+                "id": FAKE_SEC_GROUP_ID,
+                "name": "fake-security-group-name",
+                "security_group_rules": [
+                    {
+                        "direction": "egress",
+                        "ethertype": "IPv4",
+                        "id": "38ce2d8e-e8f1-48bd-83c2-d33cb9f50c3d",
+                        "port_range_max": None,
+                        "port_range_min": None,
+                        "protocol": None,
+                        "remote_group_id": None,
+                        "remote_ip_prefix": None,
+                        "security_group_id": FAKE_SEC_GROUP_ID,
+                        "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+                        "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+                        "description": ""
+                    },
+                    {
+                        "direction": "egress",
+                        "ethertype": "IPv6",
+                        "id": "565b9502-12de-4ffd-91e9-68885cff6ae1",
+                        "port_range_max": None,
+                        "port_range_min": None,
+                        "protocol": None,
+                        "remote_group_id": None,
+                        "remote_ip_prefix": None,
+                        "security_group_id": FAKE_SEC_GROUP_ID,
+                        "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+                        "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+                        "description": ""
+                    }
+                ],
+                "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+                "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550"
+            }
+        ]
+    }
+
+    FAKE_SECURITY_GROUP = {
+        "security_group": copy.deepcopy(
+            FAKE_SECURITY_GROUPS["security_groups"][0])
+    }
+
+    def setUp(self):
+        super(TestSecurityGroupsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = security_groups_client.SecurityGroupsClient(
+            fake_auth, 'network', 'regionOne')
+
+    def _test_list_security_groups(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_security_groups,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SECURITY_GROUPS,
+            bytes_body,
+            mock_args='v2.0/security-groups')
+
+    def _test_create_security_group(self, bytes_body=False):
+        kwargs = {'name': 'fake-security-group-name'}
+        self.check_service_client_function(
+            self.client.create_security_group,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_SECURITY_GROUP,
+            bytes_body,
+            status=201,
+            mock_args=['v2.0/security-groups',
+                       json.dumps({"security_group": kwargs})],
+            **kwargs)
+
+    def _test_show_security_group(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_security_group,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SECURITY_GROUP,
+            bytes_body,
+            security_group_id=self.FAKE_SEC_GROUP_ID,
+            mock_args='v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID)
+
+    def _test_update_security_group(self, bytes_body=False):
+        kwargs = {'name': 'updated-security-group-name'}
+        resp_body = copy.deepcopy(self.FAKE_SECURITY_GROUP)
+        resp_body["security_group"]["name"] = 'updated-security-group-name'
+
+        self.check_service_client_function(
+            self.client.update_security_group,
+            'tempest.lib.common.rest_client.RestClient.put',
+            resp_body,
+            bytes_body,
+            security_group_id=self.FAKE_SEC_GROUP_ID,
+            mock_args=['v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID,
+                       json.dumps({'security_group': kwargs})],
+            **kwargs)
+
+    def test_list_security_groups_with_str_body(self):
+        self._test_list_security_groups()
+
+    def test_list_security_groups_with_bytes_body(self):
+        self._test_list_security_groups(bytes_body=True)
+
+    def test_create_security_group_with_str_body(self):
+        self._test_create_security_group()
+
+    def test_create_security_group_with_bytes_body(self):
+        self._test_create_security_group(bytes_body=True)
+
+    def test_show_security_group_with_str_body(self):
+        self._test_show_security_group()
+
+    def test_show_security_group_with_bytes_body(self):
+        self._test_show_security_group(bytes_body=True)
+
+    def test_update_security_group_with_str_body(self):
+        self._test_update_security_group()
+
+    def test_update_security_group_with_bytes_body(self):
+        self._test_update_security_group(bytes_body=True)
+
+    def test_delete_security_group(self):
+        self.check_service_client_function(
+            self.client.delete_security_group,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            status=204,
+            security_group_id=self.FAKE_SEC_GROUP_ID,
+            mock_args='v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID)
diff --git a/tempest/tests/lib/services/network/test_subnetpools_client.py b/tempest/tests/lib/services/network/test_subnetpools_client.py
new file mode 100644
index 0000000..3abb438
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_subnetpools_client.py
@@ -0,0 +1,163 @@
+# Copyright 2017 AT&T 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.
+
+import copy
+
+from tempest.lib.services.network import subnetpools_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestSubnetsClient(base.BaseServiceTest):
+
+    FAKE_SUBNETPOOLS = {
+        "subnetpools": [
+            {
+                "min_prefixlen": "64",
+                "address_scope_id": None,
+                "default_prefixlen": "64",
+                "id": "03f761e6-eee0-43fc-a921-8acf64c14988",
+                "max_prefixlen": "64",
+                "name": "my-subnet-pool-ipv6",
+                "default_quota": None,
+                "is_default": False,
+                "project_id": "9fadcee8aa7c40cdb2114fff7d569c08",
+                "tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08",
+                "prefixes": [
+                    "2001:db8:0:2::/64",
+                    "2001:db8::/63"
+                ],
+                "ip_version": 6,
+                "shared": False,
+                "description": "",
+                "revision_number": 2
+            },
+            {
+                "min_prefixlen": "24",
+                "address_scope_id": None,
+                "default_prefixlen": "25",
+                "id": "f49a1319-423a-4ee6-ba54-1d95a4f6cc68",
+                "max_prefixlen": "30",
+                "name": "my-subnet-pool-ipv4",
+                "default_quota": None,
+                "is_default": False,
+                "project_id": "9fadcee8aa7c40cdb2114fff7d569c08",
+                "tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08",
+                "prefixes": [
+                    "10.10.0.0/21",
+                    "192.168.0.0/16"
+                ],
+                "ip_version": 4,
+                "shared": False,
+                "description": "",
+                "revision_number": 2
+            }
+        ]
+    }
+
+    FAKE_SUBNETPOOL_ID = "03f761e6-eee0-43fc-a921-8acf64c14988"
+
+    def setUp(self):
+        super(TestSubnetsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.subnetpools_client = subnetpools_client.SubnetpoolsClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_list_subnetpools(self, bytes_body=False):
+        self.check_service_client_function(
+            self.subnetpools_client.list_subnetpools,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SUBNETPOOLS,
+            bytes_body,
+            200)
+
+    def _test_create_subnetpool(self, bytes_body=False):
+        self.check_service_client_function(
+            self.subnetpools_client.create_subnetpool,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {'subnetpool': self.FAKE_SUBNETPOOLS['subnetpools'][1]},
+            bytes_body,
+            201,
+            name="my-subnet-pool-ipv4",
+            prefixes=["192.168.0.0/16", "10.10.0.0/21"])
+
+    def _test_show_subnetpool(self, bytes_body=False):
+        self.check_service_client_function(
+            self.subnetpools_client.show_subnetpool,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {'subnetpool': self.FAKE_SUBNETPOOLS['subnetpools'][0]},
+            bytes_body,
+            200,
+            subnetpool_id=self.FAKE_SUBNETPOOL_ID)
+
+    def _test_update_subnetpool(self, bytes_body=False):
+        update_kwargs = {
+            "name": "my-new-subnetpool-name",
+            "prefixes": [
+                "2001:db8::/64",
+                "2001:db8:0:1::/64",
+                "2001:db8:0:2::/64"
+            ],
+            "min_prefixlen": 64,
+            "default_prefixlen": 64,
+            "max_prefixlen": 64
+        }
+
+        resp_body = {
+            'subnetpool': copy.deepcopy(
+                self.FAKE_SUBNETPOOLS['subnetpools'][0])
+        }
+        resp_body['subnetpool'].update(update_kwargs)
+
+        self.check_service_client_function(
+            self.subnetpools_client.update_subnetpool,
+            'tempest.lib.common.rest_client.RestClient.put',
+            resp_body,
+            bytes_body,
+            200,
+            subnetpool_id=self.FAKE_SUBNETPOOL_ID,
+            **update_kwargs)
+
+    def test_list_subnetpools_with_str_body(self):
+        self._test_list_subnetpools()
+
+    def test_list_subnetpools_with_bytes_body(self):
+        self._test_list_subnetpools(bytes_body=True)
+
+    def test_create_subnetpool_with_str_body(self):
+        self._test_create_subnetpool()
+
+    def test_create_subnetpool_with_bytes_body(self):
+        self._test_create_subnetpool(bytes_body=True)
+
+    def test_show_subnetpool_with_str_body(self):
+        self._test_show_subnetpool()
+
+    def test_show_subnetpool_with_bytes_body(self):
+        self._test_show_subnetpool(bytes_body=True)
+
+    def test_update_subnet_with_str_body(self):
+        self._test_update_subnetpool()
+
+    def test_update_subnet_with_bytes_body(self):
+        self._test_update_subnetpool(bytes_body=True)
+
+    def test_delete_subnetpool(self):
+        self.check_service_client_function(
+            self.subnetpools_client.delete_subnetpool,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            status=204,
+            subnetpool_id=self.FAKE_SUBNETPOOL_ID)
diff --git a/tempest/tests/lib/services/network/test_subnets_client.py b/tempest/tests/lib/services/network/test_subnets_client.py
new file mode 100644
index 0000000..0aadf54
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_subnets_client.py
@@ -0,0 +1,250 @@
+# Copyright 2017 AT&T 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.
+
+import copy
+
+from tempest.lib.services.network import subnets_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestSubnetsClient(base.BaseServiceTest):
+
+    FAKE_SUBNET = {
+        "subnet": {
+            "name": "",
+            "enable_dhcp": True,
+            "network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+            "segment_id": None,
+            "project_id": "4fd44f30292945e481c7b8a0c8908869",
+            "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
+            "dns_nameservers": [],
+            "allocation_pools": [
+                {
+                    "start": "192.168.199.2",
+                    "end": "192.168.199.254"
+                }
+            ],
+            "host_routes": [],
+            "ip_version": 4,
+            "gateway_ip": "192.168.199.1",
+            "cidr": "192.168.199.0/24",
+            "id": "3b80198d-4f7b-4f77-9ef5-774d54e17126",
+            "created_at": "2016-10-10T14:35:47Z",
+            "description": "",
+            "ipv6_address_mode": None,
+            "ipv6_ra_mode": None,
+            "revision_number": 2,
+            "service_types": [],
+            "subnetpool_id": None,
+            "updated_at": "2016-10-10T14:35:47Z"
+        }
+    }
+
+    FAKE_UPDATED_SUBNET = {
+        "subnet": {
+            "name": "my_subnet",
+            "enable_dhcp": True,
+            "network_id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
+            "segment_id": None,
+            "project_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+            "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+            "dns_nameservers": [],
+            "allocation_pools": [
+                {
+                    "start": "10.0.0.2",
+                    "end": "10.0.0.254"
+                }
+            ],
+            "host_routes": [],
+            "ip_version": 4,
+            "gateway_ip": "10.0.0.1",
+            "cidr": "10.0.0.0/24",
+            "id": "08eae331-0402-425a-923c-34f7cfe39c1b",
+            "description": ""
+        }
+    }
+
+    FAKE_SUBNETS = {
+        "subnets": [
+            {
+                "name": "private-subnet",
+                "enable_dhcp": True,
+                "network_id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
+                "segment_id": None,
+                "project_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+                "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+                "dns_nameservers": [],
+                "allocation_pools": [
+                    {
+                        "start": "10.0.0.2",
+                        "end": "10.0.0.254"
+                    }
+                ],
+                "host_routes": [],
+                "ip_version": 4,
+                "gateway_ip": "10.0.0.1",
+                "cidr": "10.0.0.0/24",
+                "id": "08eae331-0402-425a-923c-34f7cfe39c1b",
+                "created_at": "2016-10-10T14:35:34Z",
+                "description": "",
+                "ipv6_address_mode": None,
+                "ipv6_ra_mode": None,
+                "revision_number": 2,
+                "service_types": [],
+                "subnetpool_id": None,
+                "updated_at": "2016-10-10T14:35:34Z"
+            },
+            {
+                "name": "my_subnet",
+                "enable_dhcp": True,
+                "network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+                "segment_id": None,
+                "project_id": "4fd44f30292945e481c7b8a0c8908869",
+                "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
+                "dns_nameservers": [],
+                "allocation_pools": [
+                    {
+                        "start": "192.0.0.2",
+                        "end": "192.255.255.254"
+                    }
+                ],
+                "host_routes": [],
+                "ip_version": 4,
+                "gateway_ip": "192.0.0.1",
+                "cidr": "192.0.0.0/8",
+                "id": "54d6f61d-db07-451c-9ab3-b9609b6b6f0b",
+                "created_at": "2016-10-10T14:35:47Z",
+                "description": "",
+                "ipv6_address_mode": None,
+                "ipv6_ra_mode": None,
+                "revision_number": 2,
+                "service_types": [],
+                "subnetpool_id": None,
+                "updated_at": "2016-10-10T14:35:47Z"
+            }
+        ]
+    }
+
+    FAKE_BULK_SUBNETS = copy.deepcopy(FAKE_SUBNETS)
+
+    FAKE_SUBNET_ID = "54d6f61d-db07-451c-9ab3-b9609b6b6f0b"
+
+    FAKE_NETWORK_ID = "d32019d3-bc6e-4319-9c1d-6722fc136a22"
+
+    def setUp(self):
+        super(TestSubnetsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.subnets_client = subnets_client.SubnetsClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_create_subnet(self, bytes_body=False):
+        self.check_service_client_function(
+            self.subnets_client.create_subnet,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_SUBNET,
+            bytes_body,
+            201,
+            network_id=self.FAKE_NETWORK_ID,
+            ip_version=4,
+            cidr="192.168.199.0/24")
+
+    def _test_update_subnet(self, bytes_body=False):
+        self.check_service_client_function(
+            self.subnets_client.update_subnet,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_UPDATED_SUBNET,
+            bytes_body,
+            200,
+            subnet_id=self.FAKE_SUBNET_ID,
+            name="fake_updated_subnet_name")
+
+    def _test_show_subnet(self, bytes_body=False):
+        self.check_service_client_function(
+            self.subnets_client.show_subnet,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SUBNET,
+            bytes_body,
+            200,
+            subnet_id=self.FAKE_SUBNET_ID)
+
+    def _test_list_subnets(self, bytes_body=False):
+        self.check_service_client_function(
+            self.subnets_client.list_subnets,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SUBNETS,
+            bytes_body,
+            200)
+
+    def _test_create_bulk_subnets(self, bytes_body=False):
+        kwargs = {
+            "subnets": [
+                {
+                    "cidr": "192.168.199.0/24",
+                    "ip_version": 4,
+                    "network_id": "e6031bc2-901a-4c66-82da-f4c32ed89406"
+                },
+                {
+                    "cidr": "10.56.4.0/22",
+                    "ip_version": 4,
+                    "network_id": "64239a54-dcc4-4b39-920b-b37c2144effa"
+                }
+            ]
+        }
+        self.check_service_client_function(
+            self.subnets_client.create_bulk_subnets,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_SUBNETS,
+            bytes_body,
+            201,
+            **kwargs)
+
+    def test_create_subnet_with_str_body(self):
+        self._test_create_subnet()
+
+    def test_create_subnet_with_bytes_body(self):
+        self._test_create_subnet(bytes_body=True)
+
+    def test_update_subnet_with_str_body(self):
+        self._test_update_subnet()
+
+    def test_update_subnet_with_bytes_body(self):
+        self._test_update_subnet(bytes_body=True)
+
+    def test_show_subnet_with_str_body(self):
+        self._test_show_subnet()
+
+    def test_show_subnet_with_bytes_body(self):
+        self._test_show_subnet(bytes_body=True)
+
+    def test_list_subnets_with_str_body(self):
+        self._test_list_subnets()
+
+    def test_list_subnets_with_bytes_body(self):
+        self._test_list_subnets(bytes_body=True)
+
+    def test_delete_subnet(self):
+        self.check_service_client_function(
+            self.subnets_client.delete_subnet,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            status=204,
+            subnet_id=self.FAKE_SUBNET_ID)
+
+    def test_create_bulk_subnets_with_str_body(self):
+        self._test_create_bulk_subnets()
+
+    def test_create_bulk_subnets_with_bytes_body(self):
+        self._test_create_bulk_subnets(bytes_body=True)
diff --git a/tempest/tests/lib/services/network/test_tags_client.py b/tempest/tests/lib/services/network/test_tags_client.py
new file mode 100644
index 0000000..dbe50a0
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_tags_client.py
@@ -0,0 +1,123 @@
+# Copyright 2017 AT&T 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.
+
+
+from tempest.lib.services.network import tags_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestTagsClient(base.BaseServiceTest):
+
+    FAKE_TAGS = {
+        "tags": [
+            "red",
+            "blue"
+        ]
+    }
+
+    FAKE_RESOURCE_TYPE = 'network'
+
+    FAKE_RESOURCE_ID = '7a8f904b-c1ed-4446-a87d-60440c02934b'
+
+    def setUp(self):
+        super(TestTagsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = tags_client.TagsClient(
+            fake_auth, 'network', 'regionOne')
+
+    def _test_update_all_tags(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_all_tags,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_TAGS,
+            bytes_body,
+            resource_type=self.FAKE_RESOURCE_TYPE,
+            resource_id=self.FAKE_RESOURCE_ID,
+            tags=self.FAKE_TAGS)
+
+    def _test_check_tag_existence(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.check_tag_existence,
+            'tempest.lib.common.rest_client.RestClient.get',
+            {},
+            bytes_body,
+            resource_type=self.FAKE_RESOURCE_TYPE,
+            resource_id=self.FAKE_RESOURCE_ID,
+            tag=self.FAKE_TAGS['tags'][0],
+            status=204)
+
+    def _test_create_tag(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_tag,
+            'tempest.lib.common.rest_client.RestClient.put',
+            {},
+            bytes_body,
+            resource_type=self.FAKE_RESOURCE_TYPE,
+            resource_id=self.FAKE_RESOURCE_ID,
+            tag=self.FAKE_TAGS['tags'][0],
+            status=201)
+
+    def _test_list_tags(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_tags,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_TAGS,
+            bytes_body,
+            resource_type=self.FAKE_RESOURCE_TYPE,
+            resource_id=self.FAKE_RESOURCE_ID)
+
+    def test_update_all_tags_with_str_body(self):
+        self._test_update_all_tags()
+
+    def test_update_all_tags_with_bytes_body(self):
+        self._test_update_all_tags(bytes_body=True)
+
+    def test_delete_all_tags(self):
+        self.check_service_client_function(
+            self.client.delete_all_tags,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            resource_type=self.FAKE_RESOURCE_TYPE,
+            resource_id=self.FAKE_RESOURCE_ID,
+            status=204)
+
+    def test_check_tag_existence_with_str_body(self):
+        self._test_check_tag_existence()
+
+    def test_check_tag_existence_with_bytes_body(self):
+        self._test_check_tag_existence(bytes_body=True)
+
+    def test_create_tag_with_str_body(self):
+        self._test_create_tag()
+
+    def test_create_tag_with_bytes_body(self):
+        self._test_create_tag(bytes_body=True)
+
+    def test_list_tags_with_str_body(self):
+        self._test_list_tags()
+
+    def test_list_tags_with_bytes_body(self):
+        self._test_list_tags(bytes_body=True)
+
+    def test_delete_tag(self):
+        self.check_service_client_function(
+            self.client.delete_tag,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            resource_type=self.FAKE_RESOURCE_TYPE,
+            resource_id=self.FAKE_RESOURCE_ID,
+            tag=self.FAKE_TAGS['tags'][0],
+            status=204)
diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py
index ac13a13..c3a792f 100644
--- a/tempest/tests/lib/test_auth.py
+++ b/tempest/tests/lib/test_auth.py
@@ -16,7 +16,7 @@
 import copy
 import datetime
 
-from oslotest import mockpatch
+import fixtures
 import testtools
 
 from tempest.lib import auth
@@ -82,9 +82,9 @@
 
     def test_auth_data_property_when_cache_exists(self):
         self.auth_provider.cache = 'foo'
-        self.useFixture(mockpatch.PatchObject(self.auth_provider,
-                                              'is_expired',
-                                              return_value=False))
+        self.useFixture(fixtures.MockPatchObject(self.auth_provider,
+                                                 'is_expired',
+                                                 return_value=False))
         self.assertEqual('foo', getattr(self.auth_provider, 'auth_data'))
 
     def test_delete_auth_data_property_through_deleter(self):
diff --git a/tempest/tests/test_decorators.py b/tempest/tests/test_decorators.py
index 8b6472b..2fc84dc 100644
--- a/tempest/tests/test_decorators.py
+++ b/tempest/tests/test_decorators.py
@@ -12,8 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import fixtures
 from oslo_config import cfg
-from oslotest import mockpatch
 import testtools
 
 from tempest import config
@@ -95,8 +95,8 @@
                           'bad_service')
 
     def test_services_decorator_with_service_valid_and_unavailable(self):
-        self.useFixture(mockpatch.PatchObject(test.CONF.service_available,
-                                              'cinder', False))
+        self.useFixture(fixtures.MockPatchObject(test.CONF.service_available,
+                                                 'cinder', False))
         self.assertRaises(testtools.TestCase.skipException,
                           self._test_services_helper, 'compute',
                           'volume')
diff --git a/test-requirements.txt b/test-requirements.txt
index fbdad44..19b45ea 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -5,7 +5,7 @@
 # needed for doc build
 sphinx!=1.6.1,>=1.5.1 # BSD
 oslosphinx>=4.7.0 # Apache-2.0
-reno>=1.8.0 # Apache-2.0
+reno!=2.3.1,>=1.8.0 # Apache-2.0
 mock>=2.0 # BSD
 coverage!=4.4,>=4.0 # Apache-2.0
 oslotest>=1.10.0 # Apache-2.0
diff --git a/tools/check_logs.py b/tools/check_logs.py
index f82b387..fc21f75 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -25,7 +25,6 @@
 import six.moves.urllib.request as urlreq
 import yaml
 
-
 # DEVSTACK_GATE_GRENADE is either unset if grenade is not running
 # or a string describing what type of grenade run to perform.
 is_grenade = os.environ.get('DEVSTACK_GATE_GRENADE') is not None
@@ -137,7 +136,7 @@
     with open(WHITELIST_FILE) as stream:
         loaded = yaml.safe_load(stream)
         if loaded:
-            for (name, l) in loaded.iteritems():
+            for (name, l) in six.iteritems(loaded):
                 for w in l:
                     assert 'module' in w, 'no module in %s' % name
                     assert 'message' in w, 'no message in %s' % name
diff --git a/tools/find_stack_traces.py b/tools/find_stack_traces.py
index 2ba8b16..1f2b88b 100755
--- a/tools/find_stack_traces.py
+++ b/tools/find_stack_traces.py
@@ -126,8 +126,8 @@
 
 
 def print_stats(items, fname, verbose=False):
-    errors = len(filter(lambda x: x.level == "ERROR", items))
-    traces = len(filter(lambda x: x.level == "TRACE", items))
+    errors = len([x for x in items if x.level == "ERROR"])
+    traces = len([x for x in items if x.level == "TRACE"])
     print("%d ERRORS found in %s" % (errors, fname))
     print("%d TRACES found in %s" % (traces, fname))
 
diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py
index acb29af..238a976 100644
--- a/tools/generate-tempest-plugins-list.py
+++ b/tools/generate-tempest-plugins-list.py
@@ -26,7 +26,12 @@
 import json
 import re
 
-import requests
+try:
+    # For Python 3.0 and later
+    import urllib
+except ImportError:
+    # Fall back to Python 2's urllib2
+    import urllib2 as urllib
 
 url = 'https://review.openstack.org/projects/'
 
@@ -49,23 +54,25 @@
 
 
 def has_tempest_plugin(proj):
-    if proj.startswith('openstack/deb-'):
-        return False
-    r = requests.get(
-        "https://git.openstack.org/cgit/%s/plain/setup.cfg" % proj)
+    try:
+        r = urllib.urlopen("https://git.openstack.org/cgit/%s/plain/setup.cfg"
+                           % proj)
+    except urllib.HTTPError as err:
+        if err.code == 404:
+            return False
     p = re.compile('^tempest\.test_plugins', re.M)
-    if p.findall(r.text):
+    if p.findall(r.read()):
         return True
     else:
         False
 
-r = requests.get(url)
+r = urllib.urlopen(url)
 # Gerrit prepends 4 garbage octets to the JSON, in order to counter
 # cross-site scripting attacks.  Therefore we must discard it so the
 # json library won't choke.
-projects = sorted(filter(is_in_openstack_namespace, json.loads(r.text[4:])))
+projects = sorted(filter(is_in_openstack_namespace, json.loads(r.read()[4:])))
 
-found_plugins = filter(has_tempest_plugin, projects)
+found_plugins = list(filter(has_tempest_plugin, projects))
 
 # Every element of the found_plugins list begins with "openstack/".
 # We drop those initial 10 octets when printing the list.