Merge "common/compute.py: remove some useless code"
diff --git a/doc/source/library.rst b/doc/source/library.rst
index 24ead08..64bd2c2 100644
--- a/doc/source/library.rst
+++ b/doc/source/library.rst
@@ -1,6 +1,6 @@
 .. _library:
 
-Tempest Library Doucmentation
+Tempest Library Documentation
 =============================
 
 Tempest provides a stable library interface that provides external tools or
@@ -66,3 +66,4 @@
    library/decorators
    library/rest_client
    library/utils
+   library/api_microversion_testing
diff --git a/doc/source/library/api_microversion_testing.rst b/doc/source/library/api_microversion_testing.rst
new file mode 100644
index 0000000..0d0b595
--- /dev/null
+++ b/doc/source/library/api_microversion_testing.rst
@@ -0,0 +1,29 @@
+.. _api_microversion_testing:
+
+API Microversion Testing Support in Temepst
+===========================================
+
+---------------------------------------------
+Framework to support API Microversion testing
+---------------------------------------------
+
+Many of the OpenStack components have implemented API microversions.
+It is important to tests those microversion in Tempest or external plugins.
+Tempest now provides stable interfaces to support to test the API microversions.
+Based on the microversion range coming from the combination of both configuration
+and each test case, APIs request will be made with selected microversion.
+
+This document explains the interfaces needed for microversion testing.
+
+
+The api_version_request module
+""""""""""""""""""""""""""""""
+
+.. automodule:: tempest.lib.common.api_version_request
+   :members:
+
+The api_version_utils module
+""""""""""""""""""""""""""""
+
+.. automodule:: tempest.lib.common.api_version_utils
+   :members:
diff --git a/doc/source/plugin.rst b/doc/source/plugin.rst
index 29653a6..2622c22 100644
--- a/doc/source/plugin.rst
+++ b/doc/source/plugin.rst
@@ -55,6 +55,37 @@
   tempest.test_plugins =
       plugin_name = module.path:PluginClass
 
+Standalone Plugin vs In-repo Plugin
+-----------------------------------
+
+Since all that's required for a plugin to be detected by tempest is a valid
+setuptools entry point in the proper namespace there is no difference from the
+tempest perspective on either creating a separate python package to
+house the plugin or adding the code to an existing python project. However,
+there are tradeoffs to consider when deciding which approach to take when
+creating a new plugin.
+
+If you create a separate python project for your plugin this makes a lot of
+things much easier. Firstly it makes packaging and versioning much simpler, you
+can easily decouple the requirements for the plugin from the requirements for
+the other project. It lets you version the plugin independently and maintain a
+single version of the test code across project release boundaries (see the
+`Branchless Tempest Spec`_ for more details on this). It also greatly
+simplifies the install time story for external users. Instead of having to
+install the right version of a project in the same python namespace as tempest
+they simply need to pip install the plugin in that namespace. It also means
+that users don't have to worry about inadvertently installing a tempest plugin
+when they install another package.
+
+.. _Branchless Tempest Spec: http://specs.openstack.org/openstack/qa-specs/specs/tempest/implemented/branchless-tempest.html
+
+The sole advantage to integrating a plugin into an existing python project is
+that it enables you to land code changes at the same time you land test changes
+in the plugin. This reduces some of the burden on contributors by not having
+to land 2 changes to add a new API feature and then test it and doing it as a
+single combined commit.
+
+
 Plugin Class
 ============
 
diff --git a/etc/accounts.yaml.sample b/etc/accounts.yaml.sample
index decc659..3dbed79 100644
--- a/etc/accounts.yaml.sample
+++ b/etc/accounts.yaml.sample
@@ -3,7 +3,25 @@
 # This is required to provide isolation between test for running in parallel
 #
 # Valid fields for credentials are defined in the descendants of
-# auth.Credentials - see KeystoneV[2|3]Credentials.CONF_ATTRIBUTES
+# lib.auth.Credentials - see KeystoneV[2|3]Credentials.ATTRIBUTES
+#
+# The fields in KeystoneV3Credentials behave as follows:
+#
+# tenant_[id|name] also sets project_[id|name].
+#
+# project_[id|name] also sets tenant_[id|name].
+#
+# Providing distinct values for both tenant_[id|name] and project_[id|name]
+# will result in an InvalidCredentials exception.
+#
+# The value of project_domain_[id|name] is used for user_domain_[id|name] if
+# the latter is not specified.
+#
+# The value of user_domain_[id|name] is used for project_domain_[id|name] if
+# the latter is not specified.
+#
+# The value of domain_[id|name] is used for project_domain_[id|name] if not
+# specified and user_domain_[id|name] if not specified.
 
 - username: 'user_1'
   tenant_name: 'test_tenant_1'
diff --git a/releasenotes/notes/api-microversion-testing-support-2ceddd2255670932.yaml b/releasenotes/notes/api-microversion-testing-support-2ceddd2255670932.yaml
new file mode 100644
index 0000000..e98671a
--- /dev/null
+++ b/releasenotes/notes/api-microversion-testing-support-2ceddd2255670932.yaml
@@ -0,0 +1,3 @@
+---
+features:
+  - Tempest library interface addition(API Microversion testing interfaces).
\ No newline at end of file
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index b1c42a6..ead6db3 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -63,7 +63,7 @@
     def _get_host_for_server(self, server_id):
         return self._get_server_details(server_id)[self._host_key]
 
-    def _migrate_server_to(self, server_id, dest_host, volume_backed):
+    def _migrate_server_to(self, server_id, dest_host, volume_backed=False):
         block_migration = (CONF.compute_feature_enabled.
                            block_migration_for_live_migration and
                            not volume_backed)
diff --git a/tempest/api/compute/api_microversion_fixture.py b/tempest/api/compute/api_microversion_fixture.py
index bf4de3e..695af52 100644
--- a/tempest/api/compute/api_microversion_fixture.py
+++ b/tempest/api/compute/api_microversion_fixture.py
@@ -14,7 +14,7 @@
 
 import fixtures
 
-from tempest.services.compute.json import base_compute_client
+from tempest.lib.services.compute import base_compute_client
 
 
 class APIMicroversionFixture(fixtures.Fixture):
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index ee21284..77ed7cd 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -18,12 +18,12 @@
 from oslo_log import log as logging
 
 from tempest.api.compute import api_microversion_fixture
-from tempest.common import api_version_utils
 from tempest.common import compute
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
+from tempest.lib.common import api_version_utils
 from tempest.lib import exceptions as lib_exc
 import tempest.test
 
@@ -47,8 +47,8 @@
         super(BaseV2ComputeTest, cls).skip_checks()
         if not CONF.service_available.nova:
             raise cls.skipException("Nova is not available")
-        cfg_min_version = CONF.compute_feature_enabled.min_microversion
-        cfg_max_version = CONF.compute_feature_enabled.max_microversion
+        cfg_min_version = CONF.compute.min_microversion
+        cfg_max_version = CONF.compute.max_microversion
         api_version_utils.check_skip_with_microversion(cls.min_microversion,
                                                        cls.max_microversion,
                                                        cfg_min_version,
@@ -105,7 +105,7 @@
         cls.request_microversion = (
             api_version_utils.select_request_microversion(
                 cls.min_microversion,
-                CONF.compute_feature_enabled.min_microversion))
+                CONF.compute.min_microversion))
         cls.build_interval = CONF.compute.build_interval
         cls.build_timeout = CONF.compute.build_timeout
         cls.image_ref = CONF.compute.image_ref
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 0b33d66..c1fbb12 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.api import utils
 from tempest.common import fixed_network
 from tempest.common.utils import data_utils
 from tempest.common import waiters
@@ -89,7 +88,7 @@
                                         wait_until='ACTIVE')
 
     @test.idempotent_id('05e8a8e7-9659-459a-989d-92c2f501f4ba')
-    @utils.skip_unless_attr('multiple_images', 'Only one image found')
+    @decorators.skip_unless_attr('multiple_images', 'Only one image found')
     def test_list_servers_filter_by_image(self):
         # Filter the list of servers by image
         params = {'image': self.image_ref}
@@ -174,7 +173,7 @@
                          len([x for x in servers['servers'] if 'id' in x]))
 
     @test.idempotent_id('b3304c3b-97df-46d2-8cd3-e2b6659724e7')
-    @utils.skip_unless_attr('multiple_images', 'Only one image found')
+    @decorators.skip_unless_attr('multiple_images', 'Only one image found')
     def test_list_servers_detailed_filter_by_image(self):
         # Filter the detailed list of servers by image
         params = {'image': self.image_ref}
diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py
new file mode 100644
index 0000000..fe20349
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -0,0 +1,147 @@
+#    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.identity import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class BaseInheritsV3Test(base.BaseIdentityV3AdminTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(BaseInheritsV3Test, cls).skip_checks()
+        if not test.is_extension_enabled('OS-INHERIT', 'identity'):
+            raise cls.skipException("Inherits aren't enabled")
+
+    @classmethod
+    def resource_setup(cls):
+        super(BaseInheritsV3Test, cls).resource_setup()
+        u_name = data_utils.rand_name('user-')
+        u_desc = '%s description' % u_name
+        u_email = '%s@testmail.tm' % u_name
+        u_password = data_utils.rand_name('pass-')
+        cls.domain = cls.domains_client.create_domain(
+            data_utils.rand_name('domain-'),
+            description=data_utils.rand_name('domain-desc-'))['domain']
+        cls.project = cls.projects_client.create_project(
+            data_utils.rand_name('project-'),
+            description=data_utils.rand_name('project-desc-'),
+            domain_id=cls.domain['id'])['project']
+        cls.group = cls.groups_client.create_group(
+            name=data_utils.rand_name('group-'), project_id=cls.project['id'],
+            domain_id=cls.domain['id'])['group']
+        cls.user = cls.users_client.create_user(
+            u_name, description=u_desc, password=u_password,
+            email=u_email, project_id=cls.project['id'],
+            domain_id=cls.domain['id'])['user']
+
+    @classmethod
+    def resource_cleanup(cls):
+        cls.groups_client.delete_group(cls.group['id'])
+        cls.users_client.delete_user(cls.user['id'])
+        cls.projects_client.delete_project(cls.project['id'])
+        cls.domains_client.update_domain(cls.domain['id'], enabled=False)
+        cls.domains_client.delete_domain(cls.domain['id'])
+        super(BaseInheritsV3Test, cls).resource_cleanup()
+
+    def _list_assertions(self, body, fetched_role_ids, role_id):
+        self.assertEqual(len(body), 1)
+        self.assertIn(role_id, fetched_role_ids)
+
+
+class InheritsV3TestJSON(BaseInheritsV3Test):
+
+    @test.idempotent_id('4e6f0366-97c8-423c-b2be-41eae6ac91c8')
+    def test_inherit_assign_list_check_revoke_roles_on_domains_user(self):
+        # Create role
+        src_role = self.roles_client.create_role(
+            name=data_utils.rand_name('Role'))['role']
+        self.addCleanup(self.roles_client.delete_role, src_role['id'])
+        # Assign role on domains user
+        self.roles_client.assign_inherited_role_on_domains_user(
+            self.domain['id'], self.user['id'], src_role['id'])
+        # list role on domains user
+        roles = self.roles_client.\
+            list_inherited_project_role_for_user_on_domain(
+                self.domain['id'], self.user['id'])['roles']
+
+        fetched_role_ids = [i['id'] for i in roles]
+        self._list_assertions(roles, fetched_role_ids,
+                              src_role['id'])
+
+        # Check role on domains user
+        self.roles_client.check_user_inherited_project_role_on_domain(
+            self.domain['id'], self.user['id'], src_role['id'])
+        # Revoke role from domains user.
+        self.roles_client.revoke_inherited_role_from_user_on_domain(
+            self.domain['id'], self.user['id'], src_role['id'])
+
+    @test.idempotent_id('c7a8dda2-be50-4fb4-9a9c-e830771078b1')
+    def test_inherit_assign_list_check_revoke_roles_on_domains_group(self):
+        # Create role
+        src_role = self.roles_client.create_role(
+            name=data_utils.rand_name('Role'))['role']
+        self.addCleanup(self.roles_client.delete_role, src_role['id'])
+        # Assign role on domains group
+        self.roles_client.assign_inherited_role_on_domains_group(
+            self.domain['id'], self.group['id'], src_role['id'])
+        # List role on domains group
+        roles = self.roles_client.\
+            list_inherited_project_role_for_group_on_domain(
+                self.domain['id'], self.group['id'])['roles']
+
+        fetched_role_ids = [i['id'] for i in roles]
+        self._list_assertions(roles, fetched_role_ids,
+                              src_role['id'])
+
+        # Check role on domains group
+        self.roles_client.check_group_inherited_project_role_on_domain(
+            self.domain['id'], self.group['id'], src_role['id'])
+        # Revoke role from domains group
+        self.roles_client.revoke_inherited_role_from_group_on_domain(
+            self.domain['id'], self.group['id'], src_role['id'])
+
+    @test.idempotent_id('18b70e45-7687-4b72-8277-b8f1a47d7591')
+    def test_inherit_assign_check_revoke_roles_on_projects_user(self):
+        # Create role
+        src_role = self.roles_client.create_role(
+            name=data_utils.rand_name('Role'))['role']
+        self.addCleanup(self.roles_client.delete_role, src_role['id'])
+        # Assign role on projects user
+        self.roles_client.assign_inherited_role_on_projects_user(
+            self.project['id'], self.user['id'], src_role['id'])
+        # Check role on projects user
+        self.roles_client.check_user_has_flag_on_inherited_to_project(
+            self.project['id'], self.user['id'], src_role['id'])
+        # Revoke role from projects user
+        self.roles_client.revoke_inherited_role_from_user_on_project(
+            self.project['id'], self.user['id'], src_role['id'])
+
+    @test.idempotent_id('26021436-d5a4-4256-943c-ded01e0d4b45')
+    def test_inherit_assign_check_revoke_roles_on_projects_group(self):
+        # Create role
+        src_role = self.roles_client.create_role(
+            name=data_utils.rand_name('Role'))['role']
+        self.addCleanup(self.roles_client.delete_role, src_role['id'])
+        # Assign role on projects group
+        self.roles_client.assign_inherited_role_on_projects_group(
+            self.project['id'], self.group['id'], src_role['id'])
+        # Check role on projects group
+        self.roles_client.check_group_has_flag_on_inherited_to_project(
+            self.project['id'], self.group['id'], src_role['id'])
+        # Revoke role from projects group
+        self.roles_client.revoke_inherited_role_from_group_on_project(
+            self.project['id'], self.group['id'], src_role['id'])
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 91b3105..3bcae17 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -106,8 +106,8 @@
         cls.non_admin_roles_client = cls.os.roles_client
         cls.users_client = cls.os_adm.users_client
         cls.non_admin_users_client = cls.os.users_client
-        cls.services_client = cls.os_adm.services_v2_client
-        cls.endpoints_client = cls.os_adm.endpoints_v2_client
+        cls.services_client = cls.os_adm.identity_services_client
+        cls.endpoints_client = cls.os_adm.endpoints_client
 
     @classmethod
     def resource_setup(cls):
@@ -155,9 +155,9 @@
         cls.trusts_client = cls.os_adm.trusts_client
         cls.roles_client = cls.os_adm.roles_v3_client
         cls.token = cls.os_adm.token_v3_client
-        cls.endpoints_client = cls.os_adm.endpoints_client
+        cls.endpoints_client = cls.os_adm.endpoints_v3_client
         cls.regions_client = cls.os_adm.regions_client
-        cls.services_client = cls.os_adm.identity_services_client
+        cls.services_client = cls.os_adm.identity_services_v3_client
         cls.policies_client = cls.os_adm.policies_client
         cls.creds_client = cls.os_adm.credentials_client
         cls.groups_client = cls.os_adm.groups_client
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index 78d6aea..7a4547a 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -74,14 +74,14 @@
         # query and setup steps are only required if the extension is available
         # and only if the router's default type is distributed.
         if test.is_extension_enabled('dvr', 'network'):
-            cls.is_dvr_router = cls.admin_client.show_router(
+            cls.is_dvr_router = cls.admin_routers_client.show_router(
                 cls.router['id'])['router'].get('distributed', False)
             if cls.is_dvr_router:
                 cls.network = cls.create_network()
                 cls.subnet = cls.create_subnet(cls.network)
                 cls.port = cls.create_port(cls.network)
-                cls.client.add_router_interface(cls.router['id'],
-                                                port_id=cls.port['id'])
+                cls.routers_client.add_router_interface(
+                    cls.router['id'], port_id=cls.port['id'])
                 # NOTE: Sometimes we have seen this test fail with dvr in,
                 # multinode tests, since the dhcp port is not created before
                 # the test gets executed and so the router is not scheduled
@@ -92,15 +92,15 @@
                 external_gateway_info = {
                     'network_id': CONF.network.public_network_id,
                     'enable_snat': True}
-                cls.admin_client.update_router_with_snat_gw_info(
+                cls.admin_routers_client.update_router_with_snat_gw_info(
                     cls.router['id'],
                     external_gateway_info=external_gateway_info)
 
     @classmethod
     def resource_cleanup(cls):
         if cls.is_dvr_router:
-            cls.client.remove_router_interface(cls.router['id'],
-                                               port_id=cls.port['id'])
+            cls.routers_client.remove_router_interface(cls.router['id'],
+                                                       port_id=cls.port['id'])
         super(L3AgentSchedulerTestJSON, cls).resource_cleanup()
 
     @test.idempotent_id('b7ce6e89-e837-4ded-9b78-9ed3c9c6a45a')
@@ -114,7 +114,8 @@
             self.agent['id'],
             router_id=self.router['id'])
         body = (
-            self.admin_client.list_l3_agents_hosting_router(self.router['id']))
+            self.admin_routers_client.list_l3_agents_hosting_router(
+                self.router['id']))
         for agent in body['agents']:
             l3_agent_ids.append(agent['id'])
             self.assertIn('agent_type', agent)
diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py
index a1a881d..c1cdbf2 100644
--- a/tempest/api/network/admin/test_negative_quotas.py
+++ b/tempest/api/network/admin/test_negative_quotas.py
@@ -60,7 +60,7 @@
                         n2['network']['id'])
 
         # Try to create a third network while the quota is two
-        with self.assertRaisesRegexp(
+        with self.assertRaisesRegex(
                 lib_exc.Conflict,
                 "An object with that identifier already exists\\n" +
                 "Details.*Quota exceeded for resources: \['network'\].*"):
diff --git a/tempest/api/network/admin/test_routers_dvr.py b/tempest/api/network/admin/test_routers_dvr.py
index 3e787af..2bc86ad 100644
--- a/tempest/api/network/admin/test_routers_dvr.py
+++ b/tempest/api/network/admin/test_routers_dvr.py
@@ -34,8 +34,8 @@
         # has a distributed attribute.
         super(RoutersTestDVR, cls).resource_setup()
         name = data_utils.rand_name('pretest-check')
-        router = cls.admin_client.create_router(name)
-        cls.admin_client.delete_router(router['router']['id'])
+        router = cls.admin_routers_client.create_router(name)
+        cls.admin_routers_client.delete_router(router['router']['id'])
         if 'distributed' not in router['router']:
             msg = "'distributed' flag not found. DVR Possibly not enabled"
             raise cls.skipException(msg)
@@ -53,8 +53,9 @@
         set to True
         """
         name = data_utils.rand_name('router')
-        router = self.admin_client.create_router(name, distributed=True)
-        self.addCleanup(self.admin_client.delete_router,
+        router = self.admin_routers_client.create_router(name,
+                                                         distributed=True)
+        self.addCleanup(self.admin_routers_client.delete_router,
                         router['router']['id'])
         self.assertTrue(router['router']['distributed'])
 
@@ -72,8 +73,9 @@
         as opposed to a "Distributed Virtual Router"
         """
         name = data_utils.rand_name('router')
-        router = self.admin_client.create_router(name, distributed=False)
-        self.addCleanup(self.admin_client.delete_router,
+        router = self.admin_routers_client.create_router(name,
+                                                         distributed=False)
+        self.addCleanup(self.admin_routers_client.delete_router,
                         router['router']['id'])
         self.assertFalse(router['router']['distributed'])
 
@@ -93,11 +95,12 @@
         """
         name = data_utils.rand_name('router')
         # router needs to be in admin state down in order to be upgraded to DVR
-        router = self.admin_client.create_router(name, distributed=False,
-                                                 admin_state_up=False)
-        self.addCleanup(self.admin_client.delete_router,
+        router = self.admin_routers_client.create_router(name,
+                                                         distributed=False,
+                                                         admin_state_up=False)
+        self.addCleanup(self.admin_routers_client.delete_router,
                         router['router']['id'])
         self.assertFalse(router['router']['distributed'])
-        router = self.admin_client.update_router(router['router']['id'],
-                                                 distributed=True)
+        router = self.admin_routers_client.update_router(
+            router['router']['id'], distributed=True)
         self.assertTrue(router['router']['distributed'])
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 1e636f1..8e0c361 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -71,6 +71,7 @@
         cls.agents_client = cls.os.network_agents_client
         cls.network_extensions_client = cls.os.network_extensions_client
         cls.networks_client = cls.os.networks_client
+        cls.routers_client = cls.os.routers_client
         cls.subnetpools_client = cls.os.subnetpools_client
         cls.subnets_client = cls.os.subnets_client
         cls.ports_client = cls.os.ports_client
@@ -231,7 +232,7 @@
             ext_gw_info['network_id'] = external_network_id
         if enable_snat is not None:
             ext_gw_info['enable_snat'] = enable_snat
-        body = cls.client.create_router(
+        body = cls.routers_client.create_router(
             router_name, external_gateway_info=ext_gw_info,
             admin_state_up=admin_state_up, **kwargs)
         router = body['router']
@@ -250,8 +251,8 @@
     @classmethod
     def create_router_interface(cls, router_id, subnet_id):
         """Wrapper utility that returns a router interface."""
-        interface = cls.client.add_router_interface(router_id,
-                                                    subnet_id=subnet_id)
+        interface = cls.routers_client.add_router_interface(
+            router_id, subnet_id=subnet_id)
         return interface
 
     @classmethod
@@ -260,12 +261,12 @@
         interfaces = body['ports']
         for i in interfaces:
             try:
-                cls.client.remove_router_interface(
+                cls.routers_client.remove_router_interface(
                     router['id'],
                     subnet_id=i['fixed_ips'][0]['subnet_id'])
             except lib_exc.NotFound:
                 pass
-        cls.client.delete_router(router['id'])
+        cls.routers_client.delete_router(router['id'])
 
 
 class BaseAdminNetworkTest(BaseNetworkTest):
@@ -278,6 +279,7 @@
         cls.admin_client = cls.os_adm.network_client
         cls.admin_agents_client = cls.os_adm.network_agents_client
         cls.admin_networks_client = cls.os_adm.networks_client
+        cls.admin_routers_client = cls.os_adm.routers_client
         cls.admin_subnets_client = cls.os_adm.subnets_client
         cls.admin_ports_client = cls.os_adm.ports_client
         cls.admin_quotas_client = cls.os_adm.network_quotas_client
diff --git a/tempest/api/network/base_routers.py b/tempest/api/network/base_routers.py
index 3495b76f..807257f 100644
--- a/tempest/api/network/base_routers.py
+++ b/tempest/api/network/base_routers.py
@@ -33,31 +33,31 @@
         self.addCleanup(self._cleanup_router, router)
         return router
 
-    def _delete_router(self, router_id, network_client=None):
-        client = network_client or self.client
+    def _delete_router(self, router_id, routers_client=None):
+        client = routers_client or self.routers_client
         client.delete_router(router_id)
         # Asserting that the router is not found in the list
         # after deletion
-        list_body = self.client.list_routers()
+        list_body = self.routers_client.list_routers()
         routers_list = list()
         for router in list_body['routers']:
             routers_list.append(router['id'])
         self.assertNotIn(router_id, routers_list)
 
     def _add_router_interface_with_subnet_id(self, router_id, subnet_id):
-        interface = self.client.add_router_interface(router_id,
-                                                     subnet_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.client.remove_router_interface(router_id,
-                                                   subnet_id=subnet_id)
+        body = self.routers_client.remove_router_interface(router_id,
+                                                           subnet_id=subnet_id)
         self.assertEqual(subnet_id, body['subnet_id'])
 
     def _remove_router_interface_with_port_id(self, router_id, port_id):
-        body = self.client.remove_router_interface(router_id,
-                                                   port_id=port_id)
+        body = self.routers_client.remove_router_interface(router_id,
+                                                           port_id=port_id)
         self.assertEqual(port_id, body['port_id'])
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index f59ecff..77008ab 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -68,8 +68,8 @@
         for port in ports:
             if (port['device_owner'].startswith('network:router_interface') and
                 port['device_id'] in [r['id'] for r in self.routers]):
-                self.client.remove_router_interface(port['device_id'],
-                                                    port_id=port['id'])
+                self.routers_client.remove_router_interface(port['device_id'],
+                                                            port_id=port['id'])
             else:
                 if port['id'] in [p['id'] for p in self.ports]:
                     self.ports_client.delete_port(port['id'])
@@ -80,11 +80,11 @@
             if subnet['id'] in [s['id'] for s in self.subnets]:
                 self.subnets_client.delete_subnet(subnet['id'])
                 self._remove_from_list_by_index(self.subnets, subnet)
-        body = self.client.list_routers()
+        body = self.routers_client.list_routers()
         routers = body['routers']
         for router in routers:
             if router['id'] in [r['id'] for r in self.routers]:
-                self.client.delete_router(router['id'])
+                self.routers_client.delete_router(router['id'])
                 self._remove_from_list_by_index(self.routers, router)
 
     def _get_ips_from_subnet(self, **kwargs):
@@ -338,12 +338,12 @@
                          fixed_ips=[
                              {'subnet_id': subnet['id'],
                               'ip_address': ip}])
-        self.assertRaisesRegexp(lib_exc.Conflict,
-                                "object with that identifier already exists",
-                                self.create_port,
-                                self.network,
-                                fixed_ips=[{'subnet_id': subnet['id'],
-                                            'ip_address': ip}])
+        self.assertRaisesRegex(lib_exc.Conflict,
+                               "object with that identifier already exists",
+                               self.create_port,
+                               self.network,
+                               fixed_ips=[{'subnet_id': subnet['id'],
+                                           'ip_address': ip}])
 
     def _create_subnet_router(self, kwargs):
         subnet = self.create_subnet(self.network, **kwargs)
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index a31a4f0..d916891 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -621,7 +621,7 @@
         subnet_ids = [subnet['id'] for subnet in subnets['subnets']]
         self.assertNotIn(subnet_slaac['id'], subnet_ids,
                          "Subnet wasn't deleted")
-        self.assertRaisesRegexp(
+        self.assertRaisesRegex(
             lib_exc.Conflict,
             "There are one or more ports still in use on the network",
             self.networks_client.delete_network,
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 0088a4d..5ff23c6 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -197,13 +197,13 @@
         subnet = self.create_subnet(network)
         self.addCleanup(self.subnets_client.delete_subnet, subnet['id'])
         router = self.create_router(data_utils.rand_name('router-'))
-        self.addCleanup(self.client.delete_router, router['id'])
+        self.addCleanup(self.routers_client.delete_router, router['id'])
         port = self.ports_client.create_port(network_id=network['id'])
         # Add router interface to port created above
-        self.client.add_router_interface(router['id'],
-                                         port_id=port['port']['id'])
-        self.addCleanup(self.client.remove_router_interface, router['id'],
-                        port_id=port['port']['id'])
+        self.routers_client.add_router_interface(router['id'],
+                                                 port_id=port['port']['id'])
+        self.addCleanup(self.routers_client.remove_router_interface,
+                        router['id'], port_id=port['port']['id'])
         # List ports filtered by router_id
         port_list = self.ports_client.list_ports(device_id=router['id'])
         ports = port_list['ports']
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 0b64be4..01afc51 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -52,7 +52,7 @@
         # NOTE(salv-orlando): Do not invoke self.create_router
         # as we need to check the response code
         name = data_utils.rand_name('router-')
-        create_body = self.client.create_router(
+        create_body = self.routers_client.create_router(
             name, external_gateway_info={
                 "network_id": CONF.network.public_network_id},
             admin_state_up=False)
@@ -63,24 +63,25 @@
             CONF.network.public_network_id)
         self.assertEqual(create_body['router']['admin_state_up'], False)
         # Show details of the created router
-        show_body = self.client.show_router(create_body['router']['id'])
+        show_body = self.routers_client.show_router(
+            create_body['router']['id'])
         self.assertEqual(show_body['router']['name'], name)
         self.assertEqual(
             show_body['router']['external_gateway_info']['network_id'],
             CONF.network.public_network_id)
         self.assertEqual(show_body['router']['admin_state_up'], False)
         # List routers and verify if created router is there in response
-        list_body = self.client.list_routers()
+        list_body = self.routers_client.list_routers()
         routers_list = list()
         for router in list_body['routers']:
             routers_list.append(router['id'])
         self.assertIn(create_body['router']['id'], routers_list)
         # Update the name of router and verify if it is updated
         updated_name = 'updated ' + name
-        update_body = self.client.update_router(create_body['router']['id'],
-                                                name=updated_name)
+        update_body = self.routers_client.update_router(
+            create_body['router']['id'], name=updated_name)
         self.assertEqual(update_body['router']['name'], updated_name)
-        show_body = self.client.show_router(
+        show_body = self.routers_client.show_router(
             create_body['router']['id'])
         self.assertEqual(show_body['router']['name'], updated_name)
 
@@ -95,9 +96,9 @@
         self.addCleanup(self.identity_utils.delete_project, project_id)
 
         name = data_utils.rand_name('router-')
-        create_body = self.admin_client.create_router(name,
-                                                      tenant_id=project_id)
-        self.addCleanup(self.admin_client.delete_router,
+        create_body = self.admin_routers_client.create_router(
+            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'])
 
@@ -122,9 +123,9 @@
             external_gateway_info = {
                 'network_id': CONF.network.public_network_id,
                 'enable_snat': enable_snat}
-            create_body = self.admin_client.create_router(
+            create_body = self.admin_routers_client.create_router(
                 name, external_gateway_info=external_gateway_info)
-            self.addCleanup(self.admin_client.delete_router,
+            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'],
@@ -137,8 +138,8 @@
         subnet = self.create_subnet(network)
         router = self._create_router(data_utils.rand_name('router-'))
         # Add router interface with subnet id
-        interface = self.client.add_router_interface(router['id'],
-                                                     subnet_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.assertIn('subnet_id', interface.keys())
@@ -158,7 +159,7 @@
         port_body = self.ports_client.create_port(
             network_id=network['id'])
         # add router interface to port created above
-        interface = self.client.add_router_interface(
+        interface = self.routers_client.add_router_interface(
             router['id'],
             port_id=port_body['port']['id'])
         self.addCleanup(self._remove_router_interface_with_port_id,
@@ -172,7 +173,7 @@
                          router['id'])
 
     def _verify_router_gateway(self, router_id, exp_ext_gw_info=None):
-        show_body = self.admin_client.show_router(router_id)
+        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)
@@ -198,7 +199,7 @@
     @test.idempotent_id('6cc285d8-46bf-4f36-9b1a-783e3008ba79')
     def test_update_router_set_gateway(self):
         router = self._create_router(data_utils.rand_name('router-'))
-        self.client.update_router(
+        self.routers_client.update_router(
             router['id'],
             external_gateway_info={
                 'network_id': CONF.network.public_network_id})
@@ -212,7 +213,7 @@
     @test.requires_ext(extension='ext-gw-mode', service='network')
     def test_update_router_set_gateway_with_snat_explicit(self):
         router = self._create_router(data_utils.rand_name('router-'))
-        self.admin_client.update_router_with_snat_gw_info(
+        self.admin_routers_client.update_router_with_snat_gw_info(
             router['id'],
             external_gateway_info={
                 'network_id': CONF.network.public_network_id,
@@ -227,7 +228,7 @@
     @test.requires_ext(extension='ext-gw-mode', service='network')
     def test_update_router_set_gateway_without_snat(self):
         router = self._create_router(data_utils.rand_name('router-'))
-        self.admin_client.update_router_with_snat_gw_info(
+        self.admin_routers_client.update_router_with_snat_gw_info(
             router['id'],
             external_gateway_info={
                 'network_id': CONF.network.public_network_id,
@@ -243,7 +244,8 @@
         router = self._create_router(
             data_utils.rand_name('router-'),
             external_network_id=CONF.network.public_network_id)
-        self.client.update_router(router['id'], external_gateway_info={})
+        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(
@@ -257,7 +259,7 @@
         router = self._create_router(
             data_utils.rand_name('router-'),
             external_network_id=CONF.network.public_network_id)
-        self.admin_client.update_router_with_snat_gw_info(
+        self.admin_routers_client.update_router_with_snat_gw_info(
             router['id'],
             external_gateway_info={
                 'network_id': CONF.network.public_network_id,
@@ -270,7 +272,7 @@
 
     @test.idempotent_id('c86ac3a8-50bd-4b00-a6b8-62af84a0765c')
     @test.requires_ext(extension='extraroute', service='network')
-    def test_update_extra_route(self):
+    def test_update_delete_extra_route(self):
         # Create different cidr for each subnet to avoid cidr duplicate
         # The cidr starts from tenant_cidr
         next_cidr = netaddr.IPNetwork(self.tenant_cidr)
@@ -301,9 +303,9 @@
             )
 
         test_routes.sort(key=lambda x: x['destination'])
-        extra_route = self.client.update_extra_routes(router['id'],
-                                                      routes=test_routes)
-        show_body = self.client.show_router(router['id'])
+        extra_route = self.routers_client.update_extra_routes(
+            router['id'], routes=test_routes)
+        show_body = self.routers_client.show_router(router['id'])
         # Assert the number of routes
         self.assertEqual(routes_num, len(extra_route['router']['routes']))
         self.assertEqual(routes_num, len(show_body['router']['routes']))
@@ -323,18 +325,23 @@
                              routes[i]['destination'])
             self.assertEqual(test_routes[i]['nexthop'], routes[i]['nexthop'])
 
+        self.routers_client.delete_extra_routes(router['id'])
+        show_body_after_deletion = self.routers_client.show_router(
+            router['id'])
+        self.assertEmpty(show_body_after_deletion['router']['routes'])
+
     def _delete_extra_routes(self, router_id):
-        self.client.delete_extra_routes(router_id)
+        self.routers_client.delete_extra_routes(router_id)
 
     @test.idempotent_id('a8902683-c788-4246-95c7-ad9c6d63a4d9')
     def test_update_router_admin_state(self):
         router = self._create_router(data_utils.rand_name('router-'))
         self.assertFalse(router['admin_state_up'])
         # Update router admin state
-        update_body = self.client.update_router(router['id'],
-                                                admin_state_up=True)
+        update_body = self.routers_client.update_router(router['id'],
+                                                        admin_state_up=True)
         self.assertTrue(update_body['router']['admin_state_up'])
-        show_body = self.client.show_router(router['id'])
+        show_body = self.routers_client.show_router(router['id'])
         self.assertTrue(show_body['router']['admin_state_up'])
 
     @test.attr(type='smoke')
@@ -381,21 +388,21 @@
     @test.idempotent_id('141297aa-3424-455d-aa8d-f2d95731e00a')
     def test_create_distributed_router(self):
         name = data_utils.rand_name('router')
-        create_body = self.admin_client.create_router(
+        create_body = self.admin_routers_client.create_router(
             name, distributed=True)
         self.addCleanup(self._delete_router,
                         create_body['router']['id'],
-                        self.admin_client)
+                        self.admin_routers_client)
         self.assertTrue(create_body['router']['distributed'])
 
     @test.idempotent_id('644d7a4a-01a1-4b68-bb8d-0c0042cb1729')
     def test_convert_centralized_router(self):
         router = self._create_router(data_utils.rand_name('router'))
         self.assertNotIn('distributed', router)
-        update_body = self.admin_client.update_router(router['id'],
-                                                      distributed=True)
+        update_body = self.admin_routers_client.update_router(router['id'],
+                                                              distributed=True)
         self.assertTrue(update_body['router']['distributed'])
-        show_body = self.admin_client.show_router(router['id'])
+        show_body = self.admin_routers_client.show_router(router['id'])
         self.assertTrue(show_body['router']['distributed'])
-        show_body = self.client.show_router(router['id'])
+        show_body = self.routers_client.show_router(router['id'])
         self.assertNotIn('distributed', show_body['router'])
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index 84dbd8d..36aaf2d 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -47,7 +47,7 @@
     @test.idempotent_id('37a94fc0-a834-45b9-bd23-9a81d2fd1e22')
     def test_router_add_gateway_invalid_network_returns_404(self):
         self.assertRaises(lib_exc.NotFound,
-                          self.client.update_router,
+                          self.routers_client.update_router,
                           self.router['id'],
                           external_gateway_info={
                               'network_id': self.router['id']})
@@ -60,7 +60,7 @@
         sub_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
         self.create_subnet(alt_network, cidr=sub_cidr)
         self.assertRaises(lib_exc.BadRequest,
-                          self.client.update_router,
+                          self.routers_client.update_router,
                           self.router['id'],
                           external_gateway_info={
                               'network_id': alt_network['id']})
@@ -84,31 +84,31 @@
     @test.attr(type=['negative'])
     @test.idempotent_id('04df80f9-224d-47f5-837a-bf23e33d1c20')
     def test_router_remove_interface_in_use_returns_409(self):
-        self.client.add_router_interface(self.router['id'],
-                                         subnet_id=self.subnet['id'])
+        self.routers_client.add_router_interface(self.router['id'],
+                                                 subnet_id=self.subnet['id'])
         self.assertRaises(lib_exc.Conflict,
-                          self.client.delete_router,
+                          self.routers_client.delete_router,
                           self.router['id'])
 
     @test.attr(type=['negative'])
     @test.idempotent_id('c2a70d72-8826-43a7-8208-0209e6360c47')
     def test_show_non_existent_router_returns_404(self):
         router = data_utils.rand_name('non_exist_router')
-        self.assertRaises(lib_exc.NotFound, self.client.show_router,
+        self.assertRaises(lib_exc.NotFound, self.routers_client.show_router,
                           router)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('b23d1569-8b0c-4169-8d4b-6abd34fad5c7')
     def test_update_non_existent_router_returns_404(self):
         router = data_utils.rand_name('non_exist_router')
-        self.assertRaises(lib_exc.NotFound, self.client.update_router,
+        self.assertRaises(lib_exc.NotFound, self.routers_client.update_router,
                           router, name="new_name")
 
     @test.attr(type=['negative'])
     @test.idempotent_id('c7edc5ad-d09d-41e6-a344-5c0c31e2e3e4')
     def test_delete_non_existent_router_returns_404(self):
         router = data_utils.rand_name('non_exist_router')
-        self.assertRaises(lib_exc.NotFound, self.client.delete_router,
+        self.assertRaises(lib_exc.NotFound, self.routers_client.delete_router,
                           router)
 
 
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index 5213c18..401fa3b 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -227,7 +227,7 @@
                  {'ethertype': 'IPv4',
                   'ip_prefix': CONF.network.tenant_network_v6_cidr})
         for pair in pairs:
-            self.assertRaisesRegexp(
+            self.assertRaisesRegex(
                 lib_exc.BadRequest,
                 "Conflicting value ethertype",
                 self.security_group_rules_client.create_security_group_rule,
diff --git a/tempest/api/network/test_subnetpools_extensions.py b/tempest/api/network/test_subnetpools_extensions.py
index d027132..c6cc8e2 100644
--- a/tempest/api/network/test_subnetpools_extensions.py
+++ b/tempest/api/network/test_subnetpools_extensions.py
@@ -30,7 +30,7 @@
         Lists subnet pool.
         Show subnet pool details.
 
-    v2.0 of the Neutron API is assumed. It is assumed that subnetpools
+    v2.0 of the Neutron API is assumed. It is assumed that subnet_allocation
     options mentioned in the [network-feature-enabled] section and
     default_network option mentioned in the [network] section of
     etc/tempest.conf:
@@ -40,8 +40,8 @@
     @classmethod
     def skip_checks(cls):
         super(SubnetPoolsTestJSON, cls).skip_checks()
-        if not test.is_extension_enabled('subnetpools', 'network'):
-            msg = "subnet pools extension not enabled."
+        if not test.is_extension_enabled('subnet_allocation', 'network'):
+            msg = "subnet_allocation extension not enabled."
             raise cls.skipException(msg)
 
     @test.attr(type='smoke')
diff --git a/tempest/api/orchestration/stacks/templates/cinder_basic.yaml b/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
index ffff580..61c271c 100644
--- a/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
+++ b/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
@@ -1,10 +1,15 @@
 heat_template_version: 2013-05-23
 
+parameters:
+  volume_size:
+    type: number
+    default: 1
+
 resources:
     volume:
         type: OS::Cinder::Volume
         properties:
-            size: 1
+            size: { get_param: volume_size }
             description: a descriptive description
             name: volume_name
 
diff --git a/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml b/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
index b660c19..0bc6d69 100644
--- a/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
+++ b/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
@@ -1,11 +1,16 @@
 heat_template_version: 2013-05-23
 
+parameters:
+  volume_size:
+    type: number
+    default: 1
+
 resources:
     volume:
         deletion_policy: 'Retain'
         type: OS::Cinder::Volume
         properties:
-            size: 1
+            size: { get_param: volume_size }
             description: a descriptive description
             name: volume_name
 
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index 001bc08..5483361 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -151,7 +151,7 @@
     def test_created_router(self):
         """Verifies created router."""
         router_id = self.test_resources.get('Router')['physical_resource_id']
-        body = self.network_client.show_router(router_id)
+        body = self.routers_client.show_router(router_id)
         router = body['router']
         self.assertEqual(self.neutron_basic_template['resources'][
             'Router']['properties']['name'], router['name'])
diff --git a/tempest/api/orchestration/stacks/test_volumes.py b/tempest/api/orchestration/stacks/test_volumes.py
index 37e68ef..a5aaf6e 100644
--- a/tempest/api/orchestration/stacks/test_volumes.py
+++ b/tempest/api/orchestration/stacks/test_volumes.py
@@ -32,8 +32,7 @@
         self.assertIsNotNone(volume_id)
         volume = self.volumes_client.show_volume(volume_id)['volume']
         self.assertEqual('available', volume.get('status'))
-        self.assertEqual(template['resources']['volume']['properties'][
-            'size'], volume.get('size'))
+        self.assertEqual(CONF.volume.volume_size, volume.get('size'))
 
         # Some volume properties have been renamed with Cinder v2
         if CONF.volume_feature_enabled.api_v2:
@@ -51,8 +50,8 @@
     def _outputs_verify(self, stack_identifier, template):
         self.assertEqual('available',
                          self.get_stack_output(stack_identifier, 'status'))
-        self.assertEqual(str(template['resources']['volume']['properties'][
-            'size']), self.get_stack_output(stack_identifier, 'size'))
+        self.assertEqual(str(CONF.volume.volume_size),
+                         self.get_stack_output(stack_identifier, 'size'))
         self.assertEqual(template['resources']['volume']['properties'][
             'description'], self.get_stack_output(stack_identifier,
                                                   'display_description'))
@@ -65,7 +64,12 @@
         """Create and delete a volume via OS::Cinder::Volume."""
         stack_name = data_utils.rand_name('heat')
         template = self.read_template('cinder_basic')
-        stack_identifier = self.create_stack(stack_name, template)
+        stack_identifier = self.create_stack(
+            stack_name,
+            template,
+            parameters={
+                'volume_size': CONF.volume.volume_size
+            })
         self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
 
         # Verify with cinder that the volume exists, with matching details
@@ -94,7 +98,12 @@
         """Ensure the 'Retain' deletion policy is respected."""
         stack_name = data_utils.rand_name('heat')
         template = self.read_template('cinder_basic_delete_retain')
-        stack_identifier = self.create_stack(stack_name, template)
+        stack_identifier = self.create_stack(
+            stack_name,
+            template,
+            parameters={
+                'volume_size': CONF.volume.volume_size
+            })
         self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
 
         # Verify with cinder that the volume exists, with matching details
diff --git a/tempest/api/utils.py b/tempest/api/utils.py
deleted file mode 100644
index 00c93b7..0000000
--- a/tempest/api/utils.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2012 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.
-
-"""Common utilities used in testing."""
-
-from tempest import test
-
-
-class skip_unless_attr(object):
-    """Decorator that skips a test if a specified attr exists and is True."""
-    def __init__(self, attr, msg=None):
-        self.attr = attr
-        self.message = msg or ("Test case attribute %s not found "
-                               "or False") % attr
-
-    def __call__(self, func):
-        def _skipper(*args, **kw):
-            """Wrapped skipper function."""
-            testobj = args[0]
-            if not getattr(testobj, self.attr, False):
-                raise test.BaseTestCase.skipException(self.message)
-            func(*args, **kw)
-        _skipper.__name__ = func.__name__
-        _skipper.__doc__ = func.__doc__
-        return _skipper
diff --git a/tempest/clients.py b/tempest/clients.py
index e88a016..8931706 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -103,32 +103,24 @@
     DatabaseLimitsClient
 from tempest.services.database.json.versions_client import \
     DatabaseVersionsClient
-from tempest.services.identity.v2.json.endpoints_client import \
-    EndpointsClient as EndpointsV2Client
-from tempest.services.identity.v2.json.identity_client import \
-    IdentityClient
-from tempest.services.identity.v2.json.roles_client import \
-    RolesClient
+from tempest.services.identity.v2.json.endpoints_client import EndpointsClient
+from tempest.services.identity.v2.json.identity_client import IdentityClient
+from tempest.services.identity.v2.json.roles_client import RolesClient
 from tempest.services.identity.v2.json.services_client import \
-    ServicesClient as ServicesV2Client
-from tempest.services.identity.v2.json.tenants_client import \
-    TenantsClient
-from tempest.services.identity.v2.json.users_client import \
-    UsersClient
+    ServicesClient as IdentityServicesClient
+from tempest.services.identity.v2.json.tenants_client import TenantsClient
+from tempest.services.identity.v2.json.users_client import UsersClient
 from tempest.services.identity.v3.json.credentials_client import \
-    CredentialsClient as CredentialsV3Client
+    CredentialsClient
 from tempest.services.identity.v3.json.domains_client import DomainsClient
 from tempest.services.identity.v3.json.endpoints_client import \
-    EndPointClient as EndPointV3Client
-from tempest.services.identity.v3.json.groups_client import \
-    GroupsClient as GroupsV3Client
+    EndPointsClient as EndPointsV3Client
+from tempest.services.identity.v3.json.groups_client import GroupsClient
 from tempest.services.identity.v3.json.identity_client import \
     IdentityClient as IdentityV3Client
-from tempest.services.identity.v3.json.policies_client import \
-    PoliciesClient as PoliciesV3Client
+from tempest.services.identity.v3.json.policies_client import PoliciesClient
 from tempest.services.identity.v3.json.projects_client import ProjectsClient
-from tempest.services.identity.v3.json.regions_client import \
-    RegionsClient as RegionsV3Client
+from tempest.services.identity.v3.json.regions_client import RegionsClient
 from tempest.services.identity.v3.json.roles_client import \
     RolesClient as RolesV3Client
 from tempest.services.identity.v3.json.services_client import \
@@ -139,6 +131,7 @@
 from tempest.services.image.v1.json.images_client import ImagesClient
 from tempest.services.image.v2.json.images_client import ImagesClientV2
 from tempest.services.network.json.network_client import NetworkClient
+from tempest.services.network.json.routers_client import RoutersClient
 from tempest.services.network.json.security_group_rules_client import \
     SecurityGroupRulesClient
 from tempest.services.object_storage.account_client import AccountClient
@@ -316,6 +309,14 @@
             build_interval=CONF.network.build_interval,
             build_timeout=CONF.network.build_timeout,
             **self.default_params)
+        self.routers_client = RoutersClient(
+            self.auth_provider,
+            CONF.network.catalog_type,
+            CONF.network.region or CONF.identity.region,
+            endpoint_type=CONF.network.endpoint_type,
+            build_interval=CONF.network.build_interval,
+            build_timeout=CONF.network.build_timeout,
+            **self.default_params)
         self.security_group_rules_client = SecurityGroupRulesClient(
             self.auth_provider,
             CONF.network.catalog_type,
@@ -488,18 +489,16 @@
         # Clients below use the admin endpoint type of Keystone API v2
         params_v2_admin = params.copy()
         params_v2_admin['endpoint_type'] = CONF.identity.v2_admin_endpoint_type
-        self.endpoints_v2_client = EndpointsV2Client(self.auth_provider,
-                                                     **params_v2_admin)
+        self.endpoints_client = EndpointsClient(self.auth_provider,
+                                                **params_v2_admin)
         self.identity_client = IdentityClient(self.auth_provider,
                                               **params_v2_admin)
         self.tenants_client = TenantsClient(self.auth_provider,
                                             **params_v2_admin)
-        self.roles_client = RolesClient(self.auth_provider,
-                                        **params_v2_admin)
-        self.users_client = UsersClient(self.auth_provider,
-                                        **params_v2_admin)
-        self.services_v2_client = ServicesV2Client(self.auth_provider,
-                                                   **params_v2_admin)
+        self.roles_client = RolesClient(self.auth_provider, **params_v2_admin)
+        self.users_client = UsersClient(self.auth_provider, **params_v2_admin)
+        self.identity_services_client = IdentityServicesClient(
+            self.auth_provider, **params_v2_admin)
 
         # Clients below use the public endpoint type of Keystone API v2
         params_v2_public = params.copy()
@@ -521,18 +520,17 @@
                                                    **params_v3)
         self.trusts_client = TrustsClient(self.auth_provider, **params_v3)
         self.users_v3_client = UsersV3Client(self.auth_provider, **params_v3)
-        self.endpoints_client = EndPointV3Client(self.auth_provider,
-                                                 **params_v3)
+        self.endpoints_v3_client = EndPointsV3Client(self.auth_provider,
+                                                     **params_v3)
         self.roles_v3_client = RolesV3Client(self.auth_provider, **params_v3)
-        self.identity_services_client = IdentityServicesV3Client(
+        self.identity_services_v3_client = IdentityServicesV3Client(
             self.auth_provider, **params_v3)
-        self.policies_client = PoliciesV3Client(self.auth_provider,
-                                                **params_v3)
+        self.policies_client = PoliciesClient(self.auth_provider, **params_v3)
         self.projects_client = ProjectsClient(self.auth_provider, **params_v3)
-        self.regions_client = RegionsV3Client(self.auth_provider, **params_v3)
-        self.credentials_client = CredentialsV3Client(self.auth_provider,
-                                                      **params_v3)
-        self.groups_client = GroupsV3Client(self.auth_provider, **params_v3)
+        self.regions_client = RegionsClient(self.auth_provider, **params_v3)
+        self.credentials_client = CredentialsClient(self.auth_provider,
+                                                    **params_v3)
+        self.groups_client = GroupsClient(self.auth_provider, **params_v3)
 
         # Token clients do not use the catalog. They only need default_params.
         # They read auth_url, so they should only be set if the corresponding
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index b95111a..03dfd7b 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -104,6 +104,7 @@
 from tempest.services.identity.v2.json import tenants_client
 from tempest.services.identity.v2.json import users_client
 from tempest.services.network.json import network_client
+from tempest.services.network.json import routers_client
 
 LOG = None
 CONF = config.CONF
@@ -171,6 +172,7 @@
     )
     network_admin = None
     networks_admin = None
+    routers_admin = None
     subnets_admin = None
     neutron_iso_networks = False
     if (CONF.service_available.neutron and
@@ -188,6 +190,12 @@
             CONF.network.region or CONF.identity.region,
             endpoint_type='adminURL',
             **params)
+        routers_admin = routers_client.RoutersClient(
+            _auth,
+            CONF.network.catalog_type,
+            CONF.network.region or CONF.identity.region,
+            endpoint_type='adminURL',
+            **params)
         subnets_admin = subnets_client.SubnetsClient(
             _auth,
             CONF.network.catalog_type,
@@ -195,12 +203,13 @@
             endpoint_type='adminURL',
             **params)
     return (identity_admin, tenants_admin, roles_admin, users_admin,
-            neutron_iso_networks, network_admin, networks_admin, subnets_admin)
+            neutron_iso_networks, network_admin, networks_admin, routers_admin,
+            subnets_admin)
 
 
 def create_resources(opts, resources):
     (identity_admin, tenants_admin, roles_admin, users_admin,
-     neutron_iso_networks, network_admin, networks_admin,
+     neutron_iso_networks, network_admin, networks_admin, routers_admin,
      subnets_admin) = get_admin_clients(opts)
     roles = roles_admin.list_roles()['roles']
     for u in resources['users']:
@@ -246,8 +255,8 @@
         for u in resources['users']:
             tenant = identity.get_tenant_by_name(tenants_admin, u['tenant'])
             network_name, router_name = create_network_resources(
-                network_admin, networks_admin, subnets_admin, tenant['id'],
-                u['name'])
+                network_admin, networks_admin, routers_admin, subnets_admin,
+                tenant['id'], u['name'])
             u['network'] = network_name
             u['router'] = router_name
         LOG.info('Networks created')
@@ -274,7 +283,8 @@
 
 
 def create_network_resources(network_admin_client, networks_admin_client,
-                             subnets_admin_client, tenant_id, name):
+                             routers_admin_client, subnets_admin_client,
+                             tenant_id, name):
 
     def _create_network(name):
         resp_body = networks_admin_client.create_network(
@@ -305,14 +315,14 @@
     def _create_router(router_name):
         external_net_id = dict(
             network_id=CONF.network.public_network_id)
-        resp_body = network_admin_client.create_router(
+        resp_body = routers_admin_client.create_router(
             router_name,
             external_gateway_info=external_net_id,
             tenant_id=tenant_id)
         return resp_body['router']
 
     def _add_router_interface(router_id, subnet_id):
-        network_admin_client.add_router_interface(router_id,
+        routers_admin_client.add_router_interface(router_id,
                                                   subnet_id=subnet_id)
 
     network_name = name + "-network"
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index 5a52043..3706b54 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -117,7 +117,6 @@
 
         if is_dry_run:
             self.dry_run_data["_tenants_to_clean"] = {}
-            f = open(DRY_RUN_JSON, 'w+')
 
         admin_mgr = self.admin_mgr
         # Always cleanup tempest and alt tempest tenants unless
@@ -146,9 +145,9 @@
             svc.run()
 
         if is_dry_run:
-            f.write(json.dumps(self.dry_run_data, sort_keys=True,
-                               indent=2, separators=(',', ': ')))
-            f.close()
+            with open(DRY_RUN_JSON, 'w+') as f:
+                f.write(json.dumps(self.dry_run_data, sort_keys=True,
+                                   indent=2, separators=(',', ': ')))
 
         self._remove_admin_user_roles()
 
@@ -281,16 +280,15 @@
             svc = service(admin_mgr, **kwargs)
             svc.run()
 
-        f = open(SAVED_STATE_JSON, 'w+')
-        f.write(json.dumps(data,
-                           sort_keys=True, indent=2, separators=(',', ': ')))
-        f.close()
+        with open(SAVED_STATE_JSON, 'w+') as f:
+            f.write(json.dumps(data,
+                    sort_keys=True, indent=2, separators=(',', ': ')))
 
     def _load_json(self):
         try:
-            json_file = open(SAVED_STATE_JSON)
-            self.json_data = json.load(json_file)
-            json_file.close()
+            with open(SAVED_STATE_JSON) as json_file:
+                self.json_data = json.load(json_file)
+
         except IOError as ex:
             LOG.exception("Failed loading saved state, please be sure you"
                           " have first run cleanup with --init-saved-state "
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 0640a4e..a0676b6 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -390,6 +390,7 @@
         self.metering_labels_client = manager.metering_labels_client
         self.metering_label_rules_client = manager.metering_label_rules_client
         self.security_groups_client = manager.security_groups_client
+        self.routers_client = manager.routers_client
 
     def _filter_by_conf_networks(self, item_list):
         if not item_list or not all(('network_id' in i for i in item_list)):
@@ -449,7 +450,7 @@
 class NetworkRouterService(NetworkService):
 
     def list(self):
-        client = self.client
+        client = self.routers_client
         routers = client.list_routers(**self.tenant_filter)
         routers = routers['routers']
         if self.is_preserve:
@@ -460,7 +461,7 @@
         return routers
 
     def delete(self):
-        client = self.client
+        client = self.routers_client
         routers = self.list()
         for router in routers:
             try:
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 95be89e..48c06ff 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -134,6 +134,7 @@
 from tempest.services.identity.v2.json import users_client
 from tempest.services.image.v2.json import images_client
 from tempest.services.network.json import network_client
+from tempest.services.network.json import routers_client
 from tempest.services.object_storage import container_client
 from tempest.services.object_storage import object_client
 from tempest.services.telemetry.json import alarming_client
@@ -270,6 +271,14 @@
             build_interval=CONF.network.build_interval,
             build_timeout=CONF.network.build_timeout,
             **default_params)
+        self.routers = routers_client.RoutersClient(
+            _auth,
+            CONF.network.catalog_type,
+            CONF.network.region or CONF.identity.region,
+            endpoint_type=CONF.network.endpoint_type,
+            build_interval=CONF.network.build_interval,
+            build_timeout=CONF.network.build_timeout,
+            **default_params)
         self.subnets = subnets_client.SubnetsClient(
             _auth,
             CONF.network.catalog_type,
@@ -739,7 +748,7 @@
 def _get_router_namespace(client, network):
     network_id = _get_resource_by_name(client.networks,
                                        'networks', network)['id']
-    n_body = client.networks.list_routers()
+    n_body = client.routers.list_routers()
     for router in n_body['routers']:
         router_id = router['id']
         r_body = client.networks.list_router_interfaces(router_id)
@@ -824,7 +833,7 @@
         client = client_for_user(router['owner'])
 
         # only create a router if the name isn't here
-        body = client.networks.list_routers()
+        body = client.routers.list_routers()
         if any(item['name'] == router['name'] for item in body['routers']):
             LOG.warning("Duplicated router name: %s" % router['name'])
             continue
@@ -841,9 +850,9 @@
         for subnet in router['subnet']:
             subnet_id = _get_resource_by_name(client.networks,
                                               'subnets', subnet)['id']
-            client.networks.remove_router_interface(router_id,
-                                                    subnet_id=subnet_id)
-        client.networks.delete_router(router_id)
+            client.routers.remove_router_interface(router_id,
+                                                   subnet_id=subnet_id)
+        client.routers.delete_router(router_id)
 
 
 def add_router_interface(routers):
@@ -856,13 +865,13 @@
             subnet_id = _get_resource_by_name(client.networks,
                                               'subnets', subnet)['id']
             # connect routers to their subnets
-            client.networks.add_router_interface(router_id,
-                                                 subnet_id=subnet_id)
+            client.routers.add_router_interface(router_id,
+                                                subnet_id=subnet_id)
         # connect routers to external network if set to "gateway"
         if router['gateway']:
             if CONF.network.public_network_id:
                 ext_net = CONF.network.public_network_id
-                client.networks._update_router(
+                client.routers._update_router(
                     router_id, set_enable_snat=True,
                     external_gateway_info={"network_id": ext_net})
             else:
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 5e5e127..9049886 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -354,8 +354,6 @@
     outfile = sys.stdout
     if update:
         conf_file = _get_config_file()
-        if opts.output:
-            outfile = open(opts.output, 'w+')
         CONF_PARSER = moves.configparser.SafeConfigParser()
         CONF_PARSER.optionxform = str
         CONF_PARSER.readfp(conf_file)
@@ -378,8 +376,9 @@
         display_results(results, update, replace)
         if update:
             conf_file.close()
-            CONF_PARSER.write(outfile)
-        outfile.close()
+            if opts.output:
+                with open(opts.output, 'w+') as outfile:
+                    CONF_PARSER.write(outfile)
     finally:
         icreds.clear_creds()
 
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index b4a74a4..2d2909a 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -17,9 +17,9 @@
 from oslo_utils import excutils
 
 from tempest.common import fixed_network
-from tempest.common import service_client
 from tempest.common import waiters
 from tempest import config
+from tempest.lib.common import rest_client
 from tempest.lib.common.utils import data_utils
 
 CONF = config.CONF
@@ -125,7 +125,7 @@
         servers = \
             [s for s in body_servers['servers'] if s['name'].startswith(name)]
     else:
-        body = service_client.ResponseBody(body.response, body['server'])
+        body = rest_client.ResponseBody(body.response, body['server'])
         servers = [body]
 
     # The name of the method to associate a floating IP to as server is too
diff --git a/tempest/common/dynamic_creds.py b/tempest/common/dynamic_creds.py
index 0a01bd4..2ffc92d 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -64,6 +64,7 @@
          self.domains_admin_client,
          self.network_admin_client,
          self.networks_admin_client,
+         self.routers_admin_client,
          self.subnets_admin_client,
          self.ports_admin_client,
          self.security_groups_admin_client) = self._get_admin_clients()
@@ -93,13 +94,14 @@
         if self.identity_version == 'v2':
             return (os.identity_client, os.tenants_client, os.users_client,
                     os.roles_client, None, os.network_client,
-                    os.networks_client, os.subnets_client, os.ports_client,
-                    os.security_groups_client)
+                    os.networks_client, os.routers_client, os.subnets_client,
+                    os.ports_client, os.security_groups_client)
         else:
             return (os.identity_v3_client, os.projects_client,
                     os.users_v3_client, os.roles_v3_client, os.domains_client,
-                    os.network_client, os.networks_client, os.subnets_client,
-                    os.ports_client, os.security_groups_client)
+                    os.network_client, os.networks_client, os.routers_client,
+                    os.subnets_client, os.ports_client,
+                    os.security_groups_client)
 
     def _create_creds(self, suffix="", admin=False, roles=None):
         """Create random credentials under the following schema.
@@ -237,14 +239,14 @@
     def _create_router(self, router_name, tenant_id):
         external_net_id = dict(
             network_id=CONF.network.public_network_id)
-        resp_body = self.network_admin_client.create_router(
+        resp_body = self.routers_admin_client.create_router(
             router_name,
             external_gateway_info=external_net_id,
             tenant_id=tenant_id)
         return resp_body['router']
 
     def _add_router_interface(self, router_id, subnet_id):
-        self.network_admin_client.add_router_interface(router_id,
+        self.routers_admin_client.add_router_interface(router_id,
                                                        subnet_id=subnet_id)
 
     def get_credentials(self, credential_type):
@@ -295,9 +297,9 @@
         return self.get_credentials(roles)
 
     def _clear_isolated_router(self, router_id, router_name):
-        net_client = self.network_admin_client
+        client = self.routers_admin_client
         try:
-            net_client.delete_router(router_id)
+            client.delete_router(router_id)
         except lib_exc.NotFound:
             LOG.warning('router with name: %s not found for delete' %
                         router_name)
@@ -331,7 +333,7 @@
                             (secgroup['name'], secgroup['id']))
 
     def _clear_isolated_net_resources(self):
-        net_client = self.network_admin_client
+        client = self.routers_admin_client
         for cred in self._creds:
             creds = self._creds.get(cred)
             if (not creds or not any([creds.router, creds.network,
@@ -344,7 +346,7 @@
             if (not self.network_resources or
                     (self.network_resources.get('router') and creds.subnet)):
                 try:
-                    net_client.remove_router_interface(
+                    client.remove_router_interface(
                         creds.router['id'],
                         subnet_id=creds.subnet['id'])
                 except lib_exc.NotFound:
diff --git a/tempest/common/negative_rest_client.py b/tempest/common/negative_rest_client.py
index d97411c..3495a24 100644
--- a/tempest/common/negative_rest_client.py
+++ b/tempest/common/negative_rest_client.py
@@ -15,30 +15,19 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.common import service_client
 from tempest import config
+from tempest.lib.common import rest_client
 
 CONF = config.CONF
 
 
-class NegativeRestClient(service_client.ServiceClient):
+class NegativeRestClient(rest_client.RestClient):
     """Version of RestClient that does not raise exceptions."""
-    def __init__(self, auth_provider, service,
-                 build_interval=None, build_timeout=None,
-                 disable_ssl_certificate_validation=None,
-                 ca_certs=None, trace_requests=None):
+    def __init__(self, auth_provider, service, **kwargs):
         region, endpoint_type = self._get_region_and_endpoint_type(service)
         super(NegativeRestClient, self).__init__(
-            auth_provider,
-            service,
-            region,
-            endpoint_type=endpoint_type,
-            build_interval=build_interval,
-            build_timeout=build_timeout,
-            disable_ssl_certificate_validation=(
-                disable_ssl_certificate_validation),
-            ca_certs=ca_certs,
-            trace_requests=trace_requests)
+            auth_provider, service, region, endpoint_type=endpoint_type,
+            **kwargs)
 
     def _get_region_and_endpoint_type(self, service):
         """Returns the region for a specific service"""
diff --git a/tempest/common/service_client.py b/tempest/common/service_client.py
deleted file mode 100644
index 14a3bd6..0000000
--- a/tempest/common/service_client.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# Copyright 2015 NEC Corporation.  All rights reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.lib.common import rest_client
-
-
-class ServiceClient(rest_client.RestClient):
-
-    def __init__(self, auth_provider, service, region,
-                 endpoint_type=None, build_interval=None, build_timeout=None,
-                 disable_ssl_certificate_validation=None, ca_certs=None,
-                 trace_requests=None):
-
-        dscv = disable_ssl_certificate_validation
-        params = {
-            'disable_ssl_certificate_validation': dscv,
-            'ca_certs': ca_certs,
-            'trace_requests': trace_requests
-        }
-
-        if endpoint_type is not None:
-            params.update({'endpoint_type': endpoint_type})
-        if build_interval is not None:
-            params.update({'build_interval': build_interval})
-        if build_timeout is not None:
-            params.update({'build_timeout': build_timeout})
-        super(ServiceClient, self).__init__(auth_provider, service, region,
-                                            **params)
-
-
-class ResponseBody(dict):
-    """Class that wraps an http response and dict body into a single value.
-
-    Callers that receive this object will normally use it as a dict but
-    can extract the response if needed.
-    """
-
-    def __init__(self, response, body=None):
-        body_data = body or {}
-        self.update(body_data)
-        self.response = response
-
-    def __str__(self):
-        body = super(ResponseBody, self).__str__()
-        return "response: %s\nBody: %s" % (self.response, body)
-
-
-class ResponseBodyData(object):
-    """Class that wraps an http response and string data into a single value"""
-
-    def __init__(self, response, data):
-        self.response = response
-        self.data = data
-
-    def __str__(self):
-        return "response: %s\nBody: %s" % (self.response, self.data)
-
-
-class ResponseBodyList(list):
-    """Class that wraps an http response and list body into a single value.
-
-    Callers that receive this object will normally use it as a list but
-    can extract the response if needed.
-    """
-
-    def __init__(self, response, body=None):
-        body_data = body or []
-        self.extend(body_data)
-        self.response = response
-
-    def __str__(self):
-        body = super(ResponseBodyList, self).__str__()
-        return "response: %s\nBody: %s" % (self.response, body)
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index cfd9df6..36e3e3a 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -102,7 +102,12 @@
         cmd = "ip addr %s| awk '/ether/ {print $2}'" % show_nic
         return self.exec_command(cmd).strip().lower()
 
-    def get_nic_name(self, address):
+    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()
+
+    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()
@@ -142,7 +147,7 @@
     def _renew_lease_udhcpc(self, fixed_ip=None):
         """Renews DHCP lease via udhcpc client. """
         file_path = '/var/run/udhcpc.'
-        nic_name = self.get_nic_name(fixed_ip)
+        nic_name = self.get_nic_name_by_ip(fixed_ip)
         pid = self.exec_command('cat {path}{nic}.pid'.
                                 format(path=file_path, nic=nic_name))
         pid = pid.strip()
diff --git a/tempest/config.py b/tempest/config.py
index c3c6eda..4c3b04b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -281,13 +281,7 @@
                help=('The minimum number of compute nodes expected. This will '
                      'be utilized by some multinode specific tests to ensure '
                      'that requests match the expected size of the cluster '
-                     'you are testing with.'))
-]
-
-compute_features_group = cfg.OptGroup(name='compute-feature-enabled',
-                                      title="Enabled Compute Service Features")
-
-ComputeFeaturesGroup = [
+                     'you are testing with.')),
     cfg.StrOpt('min_microversion',
                default=None,
                help="Lower version of the test target microversion range. "
@@ -296,7 +290,8 @@
                     "min_microversion and max_microversion. "
                     "If both values are not specified, Tempest avoids tests "
                     "which require a microversion. Valid values are string "
-                    "with format 'X.Y' or string 'latest'"),
+                    "with format 'X.Y' or string 'latest'",
+                    deprecated_group='compute-feature-enabled'),
     cfg.StrOpt('max_microversion',
                default=None,
                help="Upper version of the test target microversion range. "
@@ -305,7 +300,14 @@
                     "min_microversion and max_microversion. "
                     "If both values are not specified, Tempest avoids tests "
                     "which require a microversion. Valid values are string "
-                    "with format 'X.Y' or string 'latest'"),
+                    "with format 'X.Y' or string 'latest'",
+                    deprecated_group='compute-feature-enabled'),
+]
+
+compute_features_group = cfg.OptGroup(name='compute-feature-enabled',
+                                      title="Enabled Compute Service Features")
+
+ComputeFeaturesGroup = [
     cfg.BoolOpt('disk_config',
                 default=True,
                 help="If false, skip disk config tests"),
@@ -962,7 +964,7 @@
 
 DataProcessingFeaturesGroup = [
     cfg.ListOpt('plugins',
-                default=["vanilla", "hdp"],
+                default=["vanilla", "cdh"],
                 deprecated_group="data_processing-feature-enabled",
                 help="List of enabled data processing plugins")
 ]
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 86e8460..031df7f 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -176,20 +176,6 @@
     message = "Invalid structure of table with details"
 
 
-class InvalidAPIVersionString(TempestException):
-    message = ("API Version String %(version)s is of invalid format. Must "
-               "be of format MajorNum.MinorNum or string 'latest'.")
-
-
-class JSONSchemaNotFound(TempestException):
-    message = ("JSON Schema for %(version)s is not found in \n"
-               " %(schema_versions_info)s")
-
-
-class InvalidAPIVersionRange(TempestException):
-    message = ("API Min Version is greater than Max version")
-
-
 class CommandFailed(Exception):
     def __init__(self, returncode, cmd, output, stderr):
         super(CommandFailed, self).__init__()
diff --git a/tempest/hacking/ignored_list_T110.txt b/tempest/hacking/ignored_list_T110.txt
index 50a5477..5d3fc93 100644
--- a/tempest/hacking/ignored_list_T110.txt
+++ b/tempest/hacking/ignored_list_T110.txt
@@ -5,3 +5,4 @@
 ./tempest/services/volume/base/base_backups_client.py
 ./tempest/services/baremetal/base.py
 ./tempest/services/network/json/network_client.py
+./tempest/services/network/json/routers_client.py
diff --git a/tempest/lib/api_schema/response/compute/v2_1/servers.py b/tempest/lib/api_schema/response/compute/v2_1/servers.py
index 485c51a..3289f04 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/servers.py
@@ -267,12 +267,13 @@
     'type': 'object',
     'properties': {
         'id': {'type': 'string'},
-        'device': {'type': 'string'},
+        'device': {'type': ['string', 'null']},
         'volumeId': {'type': 'string'},
         'serverId': {'type': ['integer', 'string']}
     },
     'additionalProperties': False,
-    'required': ['id', 'device', 'volumeId', 'serverId']
+    # 'device' is optional in response.
+    'required': ['id', 'volumeId', 'serverId']
 }
 
 attach_volume = {
diff --git a/tempest/lib/auth.py b/tempest/lib/auth.py
index e269fd1..71c4f4f 100644
--- a/tempest/lib/auth.py
+++ b/tempest/lib/auth.py
@@ -325,13 +325,24 @@
 
         parts = urlparse.urlparse(_base_url)
         if filters.get('api_version', None) is not None:
+            version_path = '/%s' % filters['api_version']
             path = re.sub(r'(^|/)+v\d+(?:\.\d+)?',
-                          '/' + filters['api_version'],
+                          version_path,
                           parts.path,
                           count=1)
-            _base_url = _base_url.replace(parts.path, path)
+            _base_url = urlparse.urlunparse((parts.scheme,
+                                             parts.netloc,
+                                             path or version_path,
+                                             parts.params,
+                                             parts.query,
+                                             parts.fragment))
         if filters.get('skip_path', None) is not None and parts.path != '':
-            _base_url = _base_url.replace(parts.path, "/")
+            _base_url = urlparse.urlunparse((parts.scheme,
+                                             parts.netloc,
+                                             '/',
+                                             parts.params,
+                                             parts.query,
+                                             parts.fragment))
 
         return _base_url
 
@@ -447,13 +458,24 @@
 
         parts = urlparse.urlparse(_base_url)
         if filters.get('api_version', None) is not None:
+            version_path = '/%s' % filters['api_version']
             path = re.sub(r'(^|/)+v\d+(?:\.\d+)?',
-                          '/' + filters['api_version'],
+                          version_path,
                           parts.path,
                           count=1)
-            _base_url = _base_url.replace(parts.path, path)
+            _base_url = urlparse.urlunparse((parts.scheme,
+                                             parts.netloc,
+                                             path or version_path,
+                                             parts.params,
+                                             parts.query,
+                                             parts.fragment))
         if filters.get('skip_path', None) is not None:
-            _base_url = _base_url.replace(parts.path, "/")
+            _base_url = urlparse.urlunparse((parts.scheme,
+                                             parts.netloc,
+                                             '/',
+                                             parts.params,
+                                             parts.query,
+                                             parts.fragment))
 
         return _base_url
 
@@ -600,6 +622,9 @@
         return None not in (self.username, self.password)
 
 
+COLLISIONS = [('project_name', 'tenant_name'), ('project_id', 'tenant_id')]
+
+
 class KeystoneV3Credentials(Credentials):
     """Credentials suitable for the Keystone Identity V3 API"""
 
@@ -608,6 +633,16 @@
                   'project_name', 'tenant_id', 'tenant_name', 'user_domain_id',
                   'user_domain_name', 'user_id']
 
+    def _apply_credentials(self, attr):
+        for (key1, key2) in COLLISIONS:
+            val1 = attr.get(key1)
+            val2 = attr.get(key2)
+            if val1 and val2 and val1 != val2:
+                msg = ('Cannot have conflicting values for %s and %s' %
+                       (key1, key2))
+                raise exceptions.InvalidCredentials(msg)
+        super(KeystoneV3Credentials, self)._apply_credentials(attr)
+
     def __setattr__(self, key, value):
         parent = super(KeystoneV3Credentials, self)
         # for tenant_* set both project and tenant
@@ -635,8 +670,10 @@
                 parent.__setattr__('user_domain_name', value)
         # support domain_name coming from config
         if key == 'domain_name':
-            parent.__setattr__('user_domain_name', value)
-            parent.__setattr__('project_domain_name', value)
+            if self.user_domain_name is None:
+                parent.__setattr__('user_domain_name', value)
+            if self.project_domain_name is None:
+                parent.__setattr__('project_domain_name', value)
         # finally trigger default behaviour for all attributes
         parent.__setattr__(key, value)
 
diff --git a/tempest/lib/cmd/skip_tracker.py b/tempest/lib/cmd/skip_tracker.py
index b5c9b95..b7d6a24 100755
--- a/tempest/lib/cmd/skip_tracker.py
+++ b/tempest/lib/cmd/skip_tracker.py
@@ -81,21 +81,23 @@
     DEF_RE = re.compile(r'\s*def (\w+)\(')
     bug_found = False
     results = []
-    lines = open(path, 'rb').readlines()
-    for x, line in enumerate(lines):
-        if not bug_found:
-            res = BUG_RE.match(line)
-            if res:
-                bug_no = int(res.group(1))
-                debug("Found bug skip %s on line %d", bug_no, x + 1)
-                bug_found = True
-        else:
-            res = DEF_RE.match(line)
-            if res:
-                method = res.group(1)
-                debug("Found test method %s skips for bug %d", method, bug_no)
-                results.append((method, bug_no))
-                bug_found = False
+    with open(path, 'rb') as content:
+        lines = content.readlines()
+        for x, line in enumerate(lines):
+            if not bug_found:
+                res = BUG_RE.match(line)
+                if res:
+                    bug_no = int(res.group(1))
+                    debug("Found bug skip %s on line %d", bug_no, x + 1)
+                    bug_found = True
+            else:
+                res = DEF_RE.match(line)
+                if res:
+                    method = res.group(1)
+                    debug("Found test method %s skips for bug %d",
+                          method, bug_no)
+                    results.append((method, bug_no))
+                    bug_found = False
     return results
 
 
diff --git a/tempest/common/api_version_request.py b/tempest/lib/common/api_version_request.py
similarity index 92%
rename from tempest/common/api_version_request.py
rename to tempest/lib/common/api_version_request.py
index d8a5b56..b2b68a6 100644
--- a/tempest/common/api_version_request.py
+++ b/tempest/lib/common/api_version_request.py
@@ -14,7 +14,7 @@
 
 import re
 
-from tempest import exceptions
+from tempest.lib import exceptions
 
 
 # Define the minimum and maximum version of the API across all of the
@@ -39,6 +39,11 @@
     This class provides convenience methods for manipulation
     and comparison of version numbers that we need to do to
     implement microversions.
+
+    :param version_string: String representation of APIVersionRequest.
+            Correct format is 'X.Y', where 'X' and 'Y' are int values.
+            None value should be used to create Null APIVersionRequest,
+            which is equal to 0.0
     """
 
     # NOTE: This 'latest' version is a magic number, we assume any
@@ -47,13 +52,7 @@
     latest_ver_minor = 99999
 
     def __init__(self, version_string=None):
-        """Create an API version request object.
-
-        :param version_string: String representation of APIVersionRequest.
-            Correct format is 'X.Y', where 'X' and 'Y' are int values.
-            None value should be used to create Null APIVersionRequest,
-            which is equal to 0.0
-        """
+        """Create an API version request object."""
         # NOTE(gmann): 'version_string' as String "None" will be considered as
         # invalid version string.
         self.ver_major = 0
@@ -77,6 +76,12 @@
         return ("API Version Request: %s" % self.get_string())
 
     def is_null(self):
+        """Checks whether version is null.
+
+        Return True if version object is null otherwise False.
+
+        :returns: boolean
+        """
         return self.ver_major == 0 and self.ver_minor == 0
 
     def _format_type_error(self, other):
@@ -120,9 +125,9 @@
         greater than or equal to the minimum version and less than
         or equal to the maximum version.
 
-        @param min_version: Minimum acceptable version.
-        @param max_version: Maximum acceptable version.
-        @returns: boolean
+        :param min_version: Minimum acceptable version.
+        :param max_version: Maximum acceptable version.
+        :returns: boolean
 
         If min_version is null then there is no minimum limit.
         If max_version is null then there is no maximum limit.
diff --git a/tempest/common/api_version_utils.py b/tempest/lib/common/api_version_utils.py
similarity index 78%
rename from tempest/common/api_version_utils.py
rename to tempest/lib/common/api_version_utils.py
index 7c7e96a..73cd280 100644
--- a/tempest/common/api_version_utils.py
+++ b/tempest/lib/common/api_version_utils.py
@@ -14,8 +14,8 @@
 
 import testtools
 
-from tempest.common import api_version_request
-from tempest import exceptions
+from tempest.lib.common import api_version_request
+from tempest.lib import exceptions
 
 
 LATEST_MICROVERSION = 'latest'
@@ -35,6 +35,20 @@
 
 def check_skip_with_microversion(test_min_version, test_max_version,
                                  cfg_min_version, cfg_max_version):
+    """Checks API microversions range and returns whether test needs to be skip
+
+    Compare the test and configured microversion range and returns
+    whether test microversion range is out of configured one.
+    This method can be used to skip the test based on configured and test
+    microversion range.
+
+    :param test_min_version: Test Minimum Microversion
+    :param test_max_version: Test Maximum Microversion
+    :param cfg_min_version: Configured Minimum Microversion
+    :param cfg_max_version: Configured Maximum Microversion
+    :returns: boolean
+    """
+
     min_version = api_version_request.APIVersionRequest(test_min_version)
     max_version = api_version_request.APIVersionRequest(test_max_version)
     config_min_version = api_version_request.APIVersionRequest(cfg_min_version)
@@ -68,6 +82,16 @@
 
 
 def select_request_microversion(test_min_version, cfg_min_version):
+    """Select microversion from test and configuration.
+
+    Compare requested microversion and return the maximum
+    microversion out of those.
+
+    :param test_min_version: Test Minimum Microversion
+    :param cfg_min_version: Configured Minimum Microversion
+    :returns: Selected microversion string
+    """
+
     test_version = api_version_request.APIVersionRequest(test_min_version)
     cfg_version = api_version_request.APIVersionRequest(cfg_min_version)
     max_version = cfg_version if cfg_version >= test_version else test_version
@@ -82,10 +106,10 @@
     Verify whether microversion is present in response header
     and with specified 'api_microversion' value.
 
-    @param: api_microversion_header_name: Microversion header name
+    :param api_microversion_header_name: Microversion header name
             Example- "X-OpenStack-Nova-API-Version"
-    @param: api_microversion: Microversion number like "2.10"
-    @param: response_header: Response header where microversion is
+    :param api_microversion: Microversion number like "2.10"
+    :param response_header: Response header where microversion is
             expected to be present.
     """
     api_microversion_header_name = api_microversion_header_name.lower()
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
index 2bf7cdd..b9b2ae9 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -153,6 +153,20 @@
     message = "Invalid structure of table with details"
 
 
+class InvalidAPIVersionString(TempestException):
+    message = ("API Version String %(version)s is of invalid format. Must "
+               "be of format MajorNum.MinorNum or string 'latest'.")
+
+
+class JSONSchemaNotFound(TempestException):
+    message = ("JSON Schema for %(version)s is not found in\n"
+               " %(schema_versions_info)s")
+
+
+class InvalidAPIVersionRange(TempestException):
+    message = ("The API version range is invalid.")
+
+
 class BadAltAuth(TempestException):
     """Used when trying and failing to change to alt creds.
 
diff --git a/tempest/services/compute/json/base_compute_client.py b/tempest/lib/services/compute/base_compute_client.py
similarity index 78%
rename from tempest/services/compute/json/base_compute_client.py
rename to tempest/lib/services/compute/base_compute_client.py
index 8cfde4b..bbadc8f 100644
--- a/tempest/services/compute/json/base_compute_client.py
+++ b/tempest/lib/services/compute/base_compute_client.py
@@ -11,16 +11,30 @@
 #    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.common import rest_client
 
-from tempest.common import api_version_request
-from tempest.common import api_version_utils
-from tempest import exceptions
+from tempest.lib.common import api_version_request
+from tempest.lib.common import api_version_utils
+from tempest.lib.common import rest_client
+from tempest.lib import exceptions
 
 COMPUTE_MICROVERSION = None
 
 
 class BaseComputeClient(rest_client.RestClient):
+    """Base compute service clients class to support microversion.
+
+    This class adds microversion to API request header if same is set
+    and provide interface to select appropriate JSON schema file for
+    response validation.
+
+    :param auth_provider: an auth provider object used to wrap requests in
+                          auth
+    :param str service: The service name to use for the catalog lookup
+    :param str region: The region to use for the catalog lookup
+                                             request with microversion
+    :param kwargs: kwargs required by rest_client.RestClient
+    """
+
     api_microversion_header_name = 'X-OpenStack-Nova-API-Version'
 
     def __init__(self, auth_provider, service, region,
@@ -50,9 +64,10 @@
         """Get JSON schema
 
         This method provides the matching schema for requested
-        microversion (self.api_microversion).
+        microversion.
+
         :param schema_versions_info: List of dict which provides schema
-        information with range of valid versions.
+                                     information with range of valid versions.
         Example -
         schema_versions_info = [
             {'min': None, 'max': '2.1', 'schema': schemav21},
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index eb29176..c2b0bf4 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -66,6 +66,7 @@
         cls.network_client = cls.manager.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
@@ -393,8 +394,6 @@
         if properties is None:
             properties = {}
         name = data_utils.rand_name('%s-' % name)
-        image_file = open(path, 'rb')
-        self.addCleanup(image_file.close)
         params = {
             'name': name,
             'container_format': fmt,
@@ -405,7 +404,8 @@
         image = self.image_client.create_image(**params)['image']
         self.addCleanup(self.image_client.delete_image, image['id'])
         self.assertEqual("queued", image['status'])
-        self.image_client.update_image(image['id'], data=image_file)
+        with open(path, 'rb') as image_file:
+            self.image_client.update_image(image['id'], data=image_file)
         return image['id']
 
     def glance_image_create(self):
@@ -690,17 +690,21 @@
         cls.tenant_id = cls.manager.identity_client.tenant_id
 
     def _create_network(self, client=None, networks_client=None,
-                        tenant_id=None, namestart='network-smoke-'):
+                        routers_client=None, tenant_id=None,
+                        namestart='network-smoke-'):
         if not client:
             client = self.network_client
         if not networks_client:
             networks_client = self.networks_client
+        if not routers_client:
+            routers_client = self.routers_client
         if not tenant_id:
             tenant_id = client.tenant_id
         name = data_utils.rand_name(namestart)
         result = networks_client.create_network(name=name, tenant_id=tenant_id)
         network = net_resources.DeletableNetwork(
-            networks_client=networks_client, **result['network'])
+            networks_client=networks_client, routers_client=routers_client,
+            **result['network'])
         self.assertEqual(network.name, name)
         self.addCleanup(self.delete_wrapper, network.delete)
         return network
@@ -719,7 +723,7 @@
 
     def _list_routers(self, *args, **kwargs):
         """List routers using admin creds """
-        routers_list = self.admin_manager.network_client.list_routers(
+        routers_list = self.admin_manager.routers_client.list_routers(
             *args, **kwargs)
         return routers_list['routers']
 
@@ -736,7 +740,8 @@
         return agents_list['agents']
 
     def _create_subnet(self, network, client=None, subnets_client=None,
-                       namestart='subnet-smoke', **kwargs):
+                       routers_client=None, namestart='subnet-smoke',
+                       **kwargs):
         """Create a subnet for the given network
 
         within the cidr block configured for tenant networks.
@@ -745,6 +750,8 @@
             client = self.network_client
         if not subnets_client:
             subnets_client = self.subnets_client
+        if not routers_client:
+            routers_client = self.routers_client
 
         def cidr_in_use(cidr, tenant_id):
             """Check cidr existence
@@ -792,7 +799,7 @@
         self.assertIsNotNone(result, 'Unable to allocate tenant network')
         subnet = net_resources.DeletableSubnet(
             network_client=client, subnets_client=subnets_client,
-            **result['subnet'])
+            routers_client=routers_client, **result['subnet'])
         self.assertEqual(subnet.cidr, str_cidr)
         self.addCleanup(self.delete_wrapper, subnet.delete)
         return subnet
@@ -992,7 +999,7 @@
         sg_dict['tenant_id'] = tenant_id
         result = client.create_security_group(**sg_dict)
         secgroup = net_resources.DeletableSecurityGroup(
-            client=client,
+            client=client, routers_client=self.routers_client,
             **result['security_group']
         )
         self.assertEqual(secgroup.name, sg_name)
@@ -1128,7 +1135,7 @@
         routes traffic to the public network.
         """
         if not client:
-            client = self.network_client
+            client = self.routers_client
         if not tenant_id:
             tenant_id = client.tenant_id
         router_id = CONF.network.public_router_id
@@ -1147,14 +1154,14 @@
     def _create_router(self, client=None, tenant_id=None,
                        namestart='router-smoke'):
         if not client:
-            client = self.network_client
+            client = self.routers_client
         if not tenant_id:
             tenant_id = client.tenant_id
         name = data_utils.rand_name(namestart)
         result = client.create_router(name=name,
                                       admin_state_up=True,
                                       tenant_id=tenant_id)
-        router = net_resources.DeletableRouter(client=client,
+        router = net_resources.DeletableRouter(routers_client=client,
                                                **result['router'])
         self.assertEqual(router.name, name)
         self.addCleanup(self.delete_wrapper, router.delete)
@@ -1165,8 +1172,8 @@
         self.assertEqual(admin_state_up, router.admin_state_up)
 
     def create_networks(self, client=None, networks_client=None,
-                        subnets_client=None, tenant_id=None,
-                        dns_nameservers=None):
+                        routers_client=None, subnets_client=None,
+                        tenant_id=None, dns_nameservers=None):
         """Create a network with a subnet connected to a router.
 
         The baremetal driver is a special case since all nodes are
@@ -1194,10 +1201,12 @@
             network = self._create_network(
                 client=client, networks_client=networks_client,
                 tenant_id=tenant_id)
-            router = self._get_router(client=client, tenant_id=tenant_id)
+            router = self._get_router(client=routers_client,
+                                      tenant_id=tenant_id)
 
             subnet_kwargs = dict(network=network, client=client,
-                                 subnets_client=subnets_client)
+                                 subnets_client=subnets_client,
+                                 routers_client=routers_client)
             # use explicit check because empty list is a valid option
             if dns_nameservers is not None:
                 subnet_kwargs['dns_nameservers'] = dns_nameservers
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 4d03ed7..9e2477e 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -680,7 +680,7 @@
         # TODO(yfried): refactor this test to be used for other agents (dhcp)
         # as well
 
-        list_hosts = (self.admin_manager.network_client.
+        list_hosts = (self.admin_manager.routers_client.
                       list_l3_agents_hosting_router)
         schedule_router = (self.admin_manager.network_agents_client.
                            create_router_on_l3_agent)
@@ -693,7 +693,7 @@
 
         # NOTE(kevinbenton): we have to use the admin credentials to check
         # for the distributed flag because self.router only has a tenant view.
-        admin = self.admin_manager.network_client.show_router(self.router.id)
+        admin = self.admin_manager.routers_client.show_router(self.router.id)
         if admin['router'].get('distributed', False):
             msg = "Rescheduling test does not apply to distributed routers."
             raise self.skipException(msg)
@@ -776,7 +776,7 @@
         private_key = self._get_server_key(server)
         ssh_client = self.get_remote_client(fip.floating_ip_address,
                                             private_key=private_key)
-        spoof_nic = ssh_client.get_nic_name(spoof_port["mac_address"])
+        spoof_nic = ssh_client.get_nic_name_by_mac(spoof_port["mac_address"])
         dhcp_ports = self._list_ports(device_owner="network:dhcp",
                                       network_id=self.new_net["id"])
         new_net_dhcp = dhcp_ports[0]["fixed_ips"][0]["ip_address"]
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index fc33dd9..66c8ade 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -145,7 +145,7 @@
                                   "ports: %s")
                          % (self.network_v6, ports))
         mac6 = ports[0]
-        ssh.set_nic_state(ssh.get_nic_name(mac6))
+        ssh.set_nic_state(ssh.get_nic_name_by_mac(mac6))
 
     def _prepare_and_test(self, address6_mode, n_subnets6=1, dualnet=False):
         net_list = self.prepare_network(address6_mode=address6_mode,
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index f59354d..058f43b 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -323,6 +323,7 @@
         network, subnet, router = self.create_networks(
             client=tenant.manager.network_client,
             networks_client=tenant.manager.networks_client,
+            routers_client=tenant.manager.routers_client,
             subnets_client=tenant.manager.subnets_client)
         tenant.set_network(network, subnet, router)
 
diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py
index 045f03c..2af55b2 100644
--- a/tempest/services/compute/json/keypairs_client.py
+++ b/tempest/services/compute/json/keypairs_client.py
@@ -18,7 +18,7 @@
 from tempest.api_schema.response.compute.v2_1 import keypairs as schemav21
 from tempest.api_schema.response.compute.v2_2 import keypairs as schemav22
 from tempest.lib.common import rest_client
-from tempest.services.compute.json import base_compute_client
+from tempest.lib.services.compute import base_compute_client
 
 
 class KeyPairsClient(base_compute_client.BaseComputeClient):
diff --git a/tempest/services/identity/v3/json/endpoints_client.py b/tempest/services/identity/v3/json/endpoints_client.py
index c83212f..db30508 100644
--- a/tempest/services/identity/v3/json/endpoints_client.py
+++ b/tempest/services/identity/v3/json/endpoints_client.py
@@ -22,7 +22,7 @@
 from tempest.lib.common import rest_client
 
 
-class EndPointClient(rest_client.RestClient):
+class EndPointsClient(rest_client.RestClient):
     api_version = "v3"
 
     def list_endpoints(self):
diff --git a/tempest/services/identity/v3/json/roles_client.py b/tempest/services/identity/v3/json/roles_client.py
index 303a892..bdb0490 100644
--- a/tempest/services/identity/v3/json/roles_client.py
+++ b/tempest/services/identity/v3/json/roles_client.py
@@ -183,3 +183,133 @@
                                (domain_id, group_id, role_id))
         self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp)
+
+    def assign_inherited_role_on_domains_user(
+            self, domain_id, user_id, role_id):
+        """Assigns a role to a user on projects owned by a domain."""
+        resp, body = self.put(
+            "OS-INHERIT/domains/%s/users/%s/roles/%s/inherited_to_projects"
+            % (domain_id, user_id, role_id), None)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def revoke_inherited_role_from_user_on_domain(
+            self, domain_id, user_id, role_id):
+        """Revokes an inherited project role from a user on a domain."""
+        resp, body = self.delete(
+            "OS-INHERIT/domains/%s/users/%s/roles/%s/inherited_to_projects"
+            % (domain_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_inherited_project_role_for_user_on_domain(
+            self, domain_id, user_id):
+        """Lists the inherited project roles on a domain for a user."""
+        resp, body = self.get(
+            "OS-INHERIT/domains/%s/users/%s/roles/inherited_to_projects"
+            % (domain_id, user_id))
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_user_inherited_project_role_on_domain(
+            self, domain_id, user_id, role_id):
+        """Checks whether a user has an inherited project role on a domain."""
+        resp, body = self.head(
+            "OS-INHERIT/domains/%s/users/%s/roles/%s/inherited_to_projects"
+            % (domain_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def assign_inherited_role_on_domains_group(
+            self, domain_id, group_id, role_id):
+        """Assigns a role to a group on projects owned by a domain."""
+        resp, body = self.put(
+            "OS-INHERIT/domains/%s/groups/%s/roles/%s/inherited_to_projects"
+            % (domain_id, group_id, role_id), None)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def revoke_inherited_role_from_group_on_domain(
+            self, domain_id, group_id, role_id):
+        """Revokes an inherited project role from a group on a domain."""
+        resp, body = self.delete(
+            "OS-INHERIT/domains/%s/groups/%s/roles/%s/inherited_to_projects"
+            % (domain_id, group_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_inherited_project_role_for_group_on_domain(
+            self, domain_id, group_id):
+        """Lists the inherited project roles on a domain for a group."""
+        resp, body = self.get(
+            "OS-INHERIT/domains/%s/groups/%s/roles/inherited_to_projects"
+            % (domain_id, group_id))
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_group_inherited_project_role_on_domain(
+            self, domain_id, group_id, role_id):
+        """Checks whether a group has an inherited project role on a domain."""
+        resp, body = self.head(
+            "OS-INHERIT/domains/%s/groups/%s/roles/%s/inherited_to_projects"
+            % (domain_id, group_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def assign_inherited_role_on_projects_user(
+            self, project_id, user_id, role_id):
+        """Assigns a role to a user on projects in a subtree."""
+        resp, body = self.put(
+            "OS-INHERIT/projects/%s/users/%s/roles/%s/inherited_to_projects"
+            % (project_id, user_id, role_id), None)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def revoke_inherited_role_from_user_on_project(
+            self, project_id, user_id, role_id):
+        """Revokes an inherited role from a user on a project."""
+        resp, body = self.delete(
+            "OS-INHERIT/projects/%s/users/%s/roles/%s/inherited_to_projects"
+            % (project_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_user_has_flag_on_inherited_to_project(
+            self, project_id, user_id, role_id):
+        """Checks whether a user has a role assignment"""
+        """with the inherited_to_projects flag on a project."""
+        resp, body = self.head(
+            "OS-INHERIT/projects/%s/users/%s/roles/%s/inherited_to_projects"
+            % (project_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def assign_inherited_role_on_projects_group(
+            self, project_id, group_id, role_id):
+        """Assigns a role to a group on projects in a subtree."""
+        resp, body = self.put(
+            "OS-INHERIT/projects/%s/groups/%s/roles/%s/inherited_to_projects"
+            % (project_id, group_id, role_id), None)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def revoke_inherited_role_from_group_on_project(
+            self, project_id, group_id, role_id):
+        """Revokes an inherited role from a group on a project."""
+        resp, body = self.delete(
+            "OS-INHERIT/projects/%s/groups/%s/roles/%s/inherited_to_projects"
+            % (project_id, group_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_group_has_flag_on_inherited_to_project(
+            self, project_id, group_id, role_id):
+        """Checks whether a group has a role assignment"""
+        """with the inherited_to_projects flag on a project."""
+        resp, body = self.head(
+            "OS-INHERIT/projects/%s/groups/%s/roles/%s/inherited_to_projects"
+            % (project_id, group_id, role_id))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
diff --git a/tempest/services/network/json/base.py b/tempest/services/network/json/base.py
deleted file mode 100644
index a6ada04..0000000
--- a/tempest/services/network/json/base.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#    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 six.moves.urllib import parse as urllib
-
-from tempest.lib.common import rest_client
-
-
-class BaseNetworkClient(rest_client.RestClient):
-
-    """Base class for Tempest REST clients for Neutron.
-
-    Child classes use v2 of the Neutron API, since the V1 API has been
-    removed from the code base.
-    """
-
-    version = '2.0'
-    uri_prefix = "v2.0"
-
-    def list_resources(self, uri, **filters):
-        req_uri = self.uri_prefix + uri
-        if filters:
-            req_uri += '?' + urllib.urlencode(filters, doseq=1)
-        resp, body = self.get(req_uri)
-        body = json.loads(body)
-        self.expected_success(200, resp.status)
-        return rest_client.ResponseBody(resp, body)
-
-    def delete_resource(self, uri):
-        req_uri = self.uri_prefix + uri
-        resp, body = self.delete(req_uri)
-        self.expected_success(204, resp.status)
-        return rest_client.ResponseBody(resp, body)
-
-    def show_resource(self, uri, **fields):
-        # fields is a dict which key is 'fields' and value is a
-        # list of field's name. An example:
-        # {'fields': ['id', 'name']}
-        req_uri = self.uri_prefix + uri
-        if fields:
-            req_uri += '?' + urllib.urlencode(fields, doseq=1)
-        resp, body = self.get(req_uri)
-        body = json.loads(body)
-        self.expected_success(200, resp.status)
-        return rest_client.ResponseBody(resp, body)
-
-    def create_resource(self, uri, post_data):
-        req_uri = self.uri_prefix + uri
-        req_post_data = json.dumps(post_data)
-        resp, body = self.post(req_uri, req_post_data)
-        body = json.loads(body)
-        self.expected_success(201, resp.status)
-        return rest_client.ResponseBody(resp, body)
-
-    def update_resource(self, uri, post_data):
-        req_uri = self.uri_prefix + uri
-        req_post_data = json.dumps(post_data)
-        resp, body = self.put(req_uri, req_post_data)
-        body = json.loads(body)
-        self.expected_success(200, resp.status)
-        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 8b1a388..bcef36b 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -15,7 +15,7 @@
 from tempest import exceptions
 from tempest.lib.common.utils import misc
 from tempest.lib import exceptions as lib_exc
-from tempest.services.network.json import base
+from tempest.lib.services.network import base
 
 
 class NetworkClient(base.BaseNetworkClient):
@@ -93,110 +93,10 @@
             message = '(%s) %s' % (caller, message)
         raise exceptions.TimeoutException(message)
 
-    def create_router(self, name, admin_state_up=True, **kwargs):
-        post_body = {'router': kwargs}
-        post_body['router']['name'] = name
-        post_body['router']['admin_state_up'] = admin_state_up
-        uri = '/routers'
-        return self.create_resource(uri, post_body)
-
-    def _update_router(self, router_id, set_enable_snat, **kwargs):
-        uri = '/routers/%s' % router_id
-        body = self.show_resource(uri)
-        update_body = {}
-        update_body['name'] = kwargs.get('name', body['router']['name'])
-        update_body['admin_state_up'] = kwargs.get(
-            'admin_state_up', body['router']['admin_state_up'])
-        cur_gw_info = body['router']['external_gateway_info']
-        if cur_gw_info:
-            # TODO(kevinbenton): setting the external gateway info is not
-            # allowed for a regular tenant. If the ability to update is also
-            # merged, a test case for this will need to be added similar to
-            # the SNAT case.
-            cur_gw_info.pop('external_fixed_ips', None)
-            if not set_enable_snat:
-                cur_gw_info.pop('enable_snat', None)
-        update_body['external_gateway_info'] = kwargs.get(
-            'external_gateway_info', body['router']['external_gateway_info'])
-        if 'distributed' in kwargs:
-            update_body['distributed'] = kwargs['distributed']
-        update_body = dict(router=update_body)
-        return self.update_resource(uri, update_body)
-
-    def update_router(self, router_id, **kwargs):
-        """Update a router leaving enable_snat to its default value."""
-        # If external_gateway_info contains enable_snat the request will fail
-        # with 404 unless executed with admin client, and therefore we instruct
-        # _update_router to not set this attribute
-        # NOTE(salv-orlando): The above applies as long as Neutron's default
-        # policy is to restrict enable_snat usage to admins only.
-        return self._update_router(router_id, set_enable_snat=False, **kwargs)
-
-    def show_router(self, router_id, **fields):
-        uri = '/routers/%s' % router_id
-        return self.show_resource(uri, **fields)
-
-    def delete_router(self, router_id):
-        uri = '/routers/%s' % router_id
-        return self.delete_resource(uri)
-
-    def list_routers(self, **filters):
-        uri = '/routers'
-        return self.list_resources(uri, **filters)
-
-    def update_router_with_snat_gw_info(self, router_id, **kwargs):
-        """Update a router passing also the enable_snat attribute.
-
-        This method must be execute with admin credentials, otherwise the API
-        call will return a 404 error.
-        """
-        return self._update_router(router_id, set_enable_snat=True, **kwargs)
-
-    def add_router_interface(self, router_id, **kwargs):
-        """Add router interface.
-
-        Available params: see http://developer.openstack.org/
-                              api-ref-networking-v2-ext.html#addRouterInterface
-        """
-        uri = '/routers/%s/add_router_interface' % router_id
-        return self.update_resource(uri, kwargs)
-
-    def remove_router_interface(self, router_id, **kwargs):
-        """Remove router interface.
-
-        Available params: see http://developer.openstack.org/
-                              api-ref-networking-v2-ext.html#removeRouterInterface
-        """
-        uri = '/routers/%s/remove_router_interface' % router_id
-        return self.update_resource(uri, kwargs)
-
     def list_router_interfaces(self, uuid):
         uri = '/ports?device_id=%s' % uuid
         return self.list_resources(uri)
 
-    def list_l3_agents_hosting_router(self, router_id):
-        uri = '/routers/%s/l3-agents' % router_id
-        return self.list_resources(uri)
-
     def list_dhcp_agent_hosting_network(self, network_id):
         uri = '/networks/%s/dhcp-agents' % network_id
         return self.list_resources(uri)
-
-    def update_extra_routes(self, router_id, **kwargs):
-        """Update Extra routes.
-
-        Available params: see http://developer.openstack.org/
-                              api-ref-networking-v2-ext.html#updateExtraRoutes
-        """
-        uri = '/routers/%s' % router_id
-        put_body = {'router': kwargs}
-        return self.update_resource(uri, put_body)
-
-    def delete_extra_routes(self, router_id):
-        uri = '/routers/%s' % router_id
-        put_body = {
-            'router': {
-                'routes': None
-            }
-        }
-        return self.update_resource(uri, put_body)
diff --git a/tempest/services/network/json/routers_client.py b/tempest/services/network/json/routers_client.py
new file mode 100644
index 0000000..18442cf
--- /dev/null
+++ b/tempest/services/network/json/routers_client.py
@@ -0,0 +1,116 @@
+#    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 base
+
+
+class RoutersClient(base.BaseNetworkClient):
+
+    def create_router(self, name, admin_state_up=True, **kwargs):
+        post_body = {'router': kwargs}
+        post_body['router']['name'] = name
+        post_body['router']['admin_state_up'] = admin_state_up
+        uri = '/routers'
+        return self.create_resource(uri, post_body)
+
+    def _update_router(self, router_id, set_enable_snat, **kwargs):
+        uri = '/routers/%s' % router_id
+        body = self.show_resource(uri)
+        update_body = {}
+        update_body['name'] = kwargs.get('name', body['router']['name'])
+        update_body['admin_state_up'] = kwargs.get(
+            'admin_state_up', body['router']['admin_state_up'])
+        cur_gw_info = body['router']['external_gateway_info']
+        if cur_gw_info:
+            # TODO(kevinbenton): setting the external gateway info is not
+            # allowed for a regular tenant. If the ability to update is also
+            # merged, a test case for this will need to be added similar to
+            # the SNAT case.
+            cur_gw_info.pop('external_fixed_ips', None)
+            if not set_enable_snat:
+                cur_gw_info.pop('enable_snat', None)
+        update_body['external_gateway_info'] = kwargs.get(
+            'external_gateway_info', body['router']['external_gateway_info'])
+        if 'distributed' in kwargs:
+            update_body['distributed'] = kwargs['distributed']
+        update_body = dict(router=update_body)
+        return self.update_resource(uri, update_body)
+
+    def update_router(self, router_id, **kwargs):
+        """Update a router leaving enable_snat to its default value."""
+        # If external_gateway_info contains enable_snat the request will fail
+        # with 404 unless executed with admin client, and therefore we instruct
+        # _update_router to not set this attribute
+        # NOTE(salv-orlando): The above applies as long as Neutron's default
+        # policy is to restrict enable_snat usage to admins only.
+        return self._update_router(router_id, set_enable_snat=False, **kwargs)
+
+    def show_router(self, router_id, **fields):
+        uri = '/routers/%s' % router_id
+        return self.show_resource(uri, **fields)
+
+    def delete_router(self, router_id):
+        uri = '/routers/%s' % router_id
+        return self.delete_resource(uri)
+
+    def list_routers(self, **filters):
+        uri = '/routers'
+        return self.list_resources(uri, **filters)
+
+    def update_extra_routes(self, router_id, **kwargs):
+        """Update Extra routes.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-networking-v2-ext.html#updateExtraRoutes
+        """
+        uri = '/routers/%s' % router_id
+        put_body = {'router': kwargs}
+        return self.update_resource(uri, put_body)
+
+    def delete_extra_routes(self, router_id):
+        uri = '/routers/%s' % router_id
+        put_body = {
+            'router': {
+                'routes': None
+            }
+        }
+        return self.update_resource(uri, put_body)
+
+    def update_router_with_snat_gw_info(self, router_id, **kwargs):
+        """Update a router passing also the enable_snat attribute.
+
+        This method must be execute with admin credentials, otherwise the API
+        call will return a 404 error.
+        """
+        return self._update_router(router_id, set_enable_snat=True, **kwargs)
+
+    def add_router_interface(self, router_id, **kwargs):
+        """Add router interface.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-networking-v2-ext.html#addRouterInterface
+        """
+        uri = '/routers/%s/add_router_interface' % router_id
+        return self.update_resource(uri, kwargs)
+
+    def remove_router_interface(self, router_id, **kwargs):
+        """Remove router interface.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-networking-v2-ext.html#removeRouterInterface
+        """
+        uri = '/routers/%s/remove_router_interface' % router_id
+        return self.update_resource(uri, kwargs)
+
+    def list_l3_agents_hosting_router(self, router_id):
+        uri = '/routers/%s/l3-agents' % router_id
+        return self.list_resources(uri)
diff --git a/tempest/services/network/json/security_group_rules_client.py b/tempest/services/network/json/security_group_rules_client.py
index b2ba5b2..944eba6 100644
--- a/tempest/services/network/json/security_group_rules_client.py
+++ b/tempest/services/network/json/security_group_rules_client.py
@@ -10,7 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.services.network.json import base
+from tempest.lib.services.network import base
 
 
 class SecurityGroupRulesClient(base.BaseNetworkClient):
diff --git a/tempest/services/network/resources.py b/tempest/services/network/resources.py
index 0a7da92..5512075 100644
--- a/tempest/services/network/resources.py
+++ b/tempest/services/network/resources.py
@@ -39,6 +39,7 @@
         self.client = kwargs.pop('client', None)
         self.network_client = kwargs.pop('network_client', None)
         self.networks_client = kwargs.pop('networks_client', None)
+        self.routers_client = kwargs.pop('routers_client', None)
         self.subnets_client = kwargs.pop('subnets_client', None)
         self.ports_client = kwargs.pop('ports_client', None)
         super(DeletableResource, self).__init__(*args, **kwargs)
@@ -89,12 +90,12 @@
 
     def add_to_router(self, router_id):
         self._router_ids.add(router_id)
-        self.network_client.add_router_interface(router_id,
+        self.routers_client.add_router_interface(router_id,
                                                  subnet_id=self.id)
 
     def delete(self):
         for router_id in self._router_ids.copy():
-            self.network_client.remove_router_interface(router_id,
+            self.routers_client.remove_router_interface(router_id,
                                                         subnet_id=self.id)
             self._router_ids.remove(router_id)
         self.subnets_client.delete_subnet(self.id)
@@ -109,14 +110,14 @@
         return self.update(external_gateway_info=dict())
 
     def update(self, *args, **kwargs):
-        result = self.client.update_router(self.id,
-                                           *args,
-                                           **kwargs)
+        result = self.routers_client.update_router(self.id,
+                                                   *args,
+                                                   **kwargs)
         return super(DeletableRouter, self).update(**result['router'])
 
     def delete(self):
         self.unset_gateway()
-        self.client.delete_router(self.id)
+        self.routers_client.delete_router(self.id)
 
 
 class DeletableFloatingIp(DeletableResource):
diff --git a/tempest/tests/cmd/test_javelin.py b/tempest/tests/cmd/test_javelin.py
index 3380f84..dc7b434 100644
--- a/tempest/tests/cmd/test_javelin.py
+++ b/tempest/tests/cmd/test_javelin.py
@@ -250,7 +250,7 @@
 
     def test_create_router(self):
 
-        self.fake_client.networks.list_routers.return_value = {'routers': []}
+        self.fake_client.routers.list_routers.return_value = {'routers': []}
         self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
                                               return_value=self.fake_client))
 
@@ -260,7 +260,7 @@
         mocked_function.assert_called_once_with(self.fake_object['name'])
 
     def test_create_router_existing(self):
-        self.fake_client.networks.list_routers.return_value = {
+        self.fake_client.routers.list_routers.return_value = {
             'routers': [self.fake_object]}
         self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
                                               return_value=self.fake_client))
@@ -405,7 +405,7 @@
 
         javelin.destroy_routers([self.fake_object])
 
-        mocked_function = self.fake_client.networks.delete_router
+        mocked_function = self.fake_client.routers.delete_router
         mocked_function.assert_called_once_with(
             self.fake_object['router_id'])
 
diff --git a/tempest/tests/cmd/test_tempest_init.py b/tempest/tests/cmd/test_tempest_init.py
index 1048a52..685a0b3 100644
--- a/tempest/tests/cmd/test_tempest_init.py
+++ b/tempest/tests/cmd/test_tempest_init.py
@@ -36,9 +36,8 @@
         testr_conf_file = init.TESTR_CONF % (top_level_path, discover_path)
 
         conf_path = conf_dir.join('.testr.conf')
-        conf_file = open(conf_path, 'r')
-        self.addCleanup(conf_file.close)
-        self.assertEqual(conf_file.read(), testr_conf_file)
+        with open(conf_path, 'r') as conf_file:
+            self.assertEqual(conf_file.read(), testr_conf_file)
 
     def test_generate_sample_config(self):
         local_dir = self.useFixture(fixtures.TempDir())
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index 059269e..be4a6ee 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -18,9 +18,9 @@
 
 from tempest.common import credentials_factory as credentials
 from tempest.common import dynamic_creds
-from tempest.common import service_client
 from tempest import config
 from tempest import exceptions
+from tempest.lib.common import rest_client
 from tempest.lib.services.identity.v2 import token_client as json_token_client
 from tempest.services.identity.v2.json import identity_client as \
     json_iden_client
@@ -31,6 +31,7 @@
 from tempest.services.identity.v2.json import users_client as \
     json_users_client
 from tempest.services.network.json import network_client as json_network_client
+from tempest.services.network.json import routers_client
 from tempest.tests import base
 from tempest.tests import fake_config
 from tempest.tests import fake_http
@@ -74,7 +75,7 @@
         user_fix = self.useFixture(mockpatch.PatchObject(
             json_users_client.UsersClient,
             'create_user',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200, {'user': {'id': id, 'name': name}}))))
         return user_fix
 
@@ -82,7 +83,7 @@
         tenant_fix = self.useFixture(mockpatch.PatchObject(
             json_tenants_client.TenantsClient,
             'create_tenant',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200, {'tenant': {'id': id, 'name': name}}))))
         return tenant_fix
 
@@ -90,7 +91,7 @@
         roles_fix = self.useFixture(mockpatch.PatchObject(
             json_roles_client.RolesClient,
             'list_roles',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200,
                            {'roles': [{'id': id, 'name': name},
                             {'id': '1', 'name': 'FakeRole'},
@@ -101,7 +102,7 @@
         roles_fix = self.useFixture(mockpatch.PatchObject(
             json_roles_client.RolesClient,
             'list_roles',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200,
                            {'roles': [{'id': '1234', 'name': 'role1'},
                             {'id': '1', 'name': 'FakeRole'},
@@ -112,7 +113,7 @@
         tenant_fix = self.useFixture(mockpatch.PatchObject(
             json_roles_client.RolesClient,
             'assign_user_role',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200, {}))))
         return tenant_fix
 
@@ -120,7 +121,7 @@
         roles_fix = self.useFixture(mockpatch.PatchObject(
             json_roles_client.RolesClient,
             'list_roles',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200, {'roles': [{'id': '1',
                                  'name': 'FakeRole'}]}))))
         return roles_fix
@@ -129,7 +130,7 @@
         ec2_creds_fix = self.useFixture(mockpatch.PatchObject(
             json_users_client.UsersClient,
             'list_user_ec2_credentials',
-            return_value=(service_client.ResponseBody
+            return_value=(rest_client.ResponseBody
                           (200, {'credentials': [{
                                  'access': 'fake_access',
                                  'secret': 'fake_secret',
@@ -154,7 +155,7 @@
 
     def _mock_router_create(self, id, name):
         router_fix = self.useFixture(mockpatch.PatchObject(
-            json_network_client.NetworkClient,
+            routers_client.RoutersClient,
             'create_router',
             return_value={'router': {'id': id, 'name': name}}))
         return router_fix
@@ -295,7 +296,7 @@
         subnet = mock.patch.object(creds.subnets_admin_client,
                                    'delete_subnet')
         subnet_mock = subnet.start()
-        router = mock.patch.object(creds.network_admin_client,
+        router = mock.patch.object(creds.routers_admin_client,
                                    'delete_router')
         router_mock = router.start()
 
@@ -321,7 +322,7 @@
         self._mock_subnet_create(creds, '1234', 'fake_subnet')
         self._mock_router_create('1234', 'fake_router')
         router_interface_mock = self.patch(
-            'tempest.services.network.json.network_client.NetworkClient.'
+            'tempest.services.network.json.routers_client.RoutersClient.'
             'add_router_interface')
         primary_creds = creds.get_primary_creds()
         router_interface_mock.assert_called_once_with('1234', subnet_id='1234')
@@ -353,7 +354,7 @@
         self._mock_subnet_create(creds, '1234', 'fake_subnet')
         self._mock_router_create('1234', 'fake_router')
         router_interface_mock = self.patch(
-            'tempest.services.network.json.network_client.NetworkClient.'
+            'tempest.services.network.json.routers_client.RoutersClient.'
             'add_router_interface')
         creds.get_primary_creds()
         router_interface_mock.assert_called_once_with('1234', subnet_id='1234')
@@ -386,11 +387,11 @@
         subnet = mock.patch.object(creds.subnets_admin_client,
                                    'delete_subnet')
         subnet_mock = subnet.start()
-        router = mock.patch.object(creds.network_admin_client,
+        router = mock.patch.object(creds.routers_admin_client,
                                    'delete_router')
         router_mock = router.start()
         remove_router_interface_mock = self.patch(
-            'tempest.services.network.json.network_client.NetworkClient.'
+            'tempest.services.network.json.routers_client.RoutersClient.'
             'remove_router_interface')
         return_values = ({'status': 200}, {'ports': []})
         port_list_mock = mock.patch.object(creds.ports_admin_client,
@@ -461,7 +462,7 @@
         self._mock_subnet_create(creds, '1234', 'fake_alt_subnet')
         self._mock_router_create('1234', 'fake_alt_router')
         router_interface_mock = self.patch(
-            'tempest.services.network.json.network_client.NetworkClient.'
+            'tempest.services.network.json.routers_client.RoutersClient.'
             'add_router_interface')
         alt_creds = creds.get_alt_creds()
         router_interface_mock.assert_called_once_with('1234', subnet_id='1234')
@@ -485,7 +486,7 @@
         self._mock_subnet_create(creds, '1234', 'fake_admin_subnet')
         self._mock_router_create('1234', 'fake_admin_router')
         router_interface_mock = self.patch(
-            'tempest.services.network.json.network_client.NetworkClient.'
+            'tempest.services.network.json.routers_client.RoutersClient.'
             'add_router_interface')
         self._mock_list_roles('123456', 'admin')
         admin_creds = creds.get_admin_creds()
@@ -521,7 +522,7 @@
         subnet = mock.patch.object(creds.subnets_admin_client,
                                    'delete_subnet')
         subnet_mock = subnet.start()
-        router = mock.patch.object(creds.network_admin_client,
+        router = mock.patch.object(creds.routers_admin_client,
                                    'delete_router')
         router_mock = router.start()
 
diff --git a/tempest/tests/common/test_api_version_request.py b/tempest/tests/lib/common/test_api_version_request.py
similarity index 97%
rename from tempest/tests/common/test_api_version_request.py
rename to tempest/tests/lib/common/test_api_version_request.py
index 38fbfc1..bdaa936 100644
--- a/tempest/tests/common/test_api_version_request.py
+++ b/tempest/tests/lib/common/test_api_version_request.py
@@ -12,9 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.common import api_version_request
-from tempest import exceptions
-from tempest.tests import base
+from tempest.lib.common import api_version_request
+from tempest.lib import exceptions
+from tempest.tests.lib import base
 
 
 class APIVersionRequestTests(base.TestCase):
diff --git a/tempest/tests/common/test_api_version_utils.py b/tempest/tests/lib/common/test_api_version_utils.py
similarity index 97%
rename from tempest/tests/common/test_api_version_utils.py
rename to tempest/tests/lib/common/test_api_version_utils.py
index 501f954..591b87e 100644
--- a/tempest/tests/common/test_api_version_utils.py
+++ b/tempest/tests/lib/common/test_api_version_utils.py
@@ -14,9 +14,9 @@
 
 import testtools
 
-from tempest.common import api_version_utils
-from tempest import exceptions
-from tempest.tests import base
+from tempest.lib.common import api_version_utils
+from tempest.lib import exceptions
+from tempest.tests.lib import base
 
 
 class TestVersionSkipLogic(base.TestCase):
diff --git a/tempest/tests/lib/common/utils/test_data_utils.py b/tempest/tests/lib/common/utils/test_data_utils.py
index 07502d0..493df89 100644
--- a/tempest/tests/lib/common/utils/test_data_utils.py
+++ b/tempest/tests/lib/common/utils/test_data_utils.py
@@ -24,15 +24,15 @@
     def test_rand_uuid(self):
         actual = data_utils.rand_uuid()
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]"
-                                         "{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
+        self.assertRegex(actual, "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]"
+                         "{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
         actual2 = data_utils.rand_uuid()
         self.assertNotEqual(actual, actual2)
 
     def test_rand_uuid_hex(self):
         actual = data_utils.rand_uuid_hex()
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "^[0-9a-f]{32}$")
+        self.assertRegex(actual, "^[0-9a-f]{32}$")
 
         actual2 = data_utils.rand_uuid_hex()
         self.assertNotEqual(actual, actual2)
@@ -52,14 +52,14 @@
     def test_rand_name_with_prefix(self):
         actual = data_utils.rand_name(prefix='prefix-str')
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "^prefix-str-")
+        self.assertRegex(actual, "^prefix-str-")
         actual2 = data_utils.rand_name(prefix='prefix-str')
         self.assertNotEqual(actual, actual2)
 
     def test_rand_password(self):
         actual = data_utils.rand_password()
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "[A-Za-z0-9~!@#$%^&*_=+]{15,}")
+        self.assertRegex(actual, "[A-Za-z0-9~!@#$%^&*_=+]{15,}")
         actual2 = data_utils.rand_password()
         self.assertNotEqual(actual, actual2)
 
@@ -67,7 +67,7 @@
         actual = data_utils.rand_password(8)
         self.assertIsInstance(actual, str)
         self.assertEqual(len(actual), 8)
-        self.assertRegexpMatches(actual, "[A-Za-z0-9~!@#$%^&*_=+]{8}")
+        self.assertRegex(actual, "[A-Za-z0-9~!@#$%^&*_=+]{8}")
         actual2 = data_utils.rand_password(8)
         self.assertNotEqual(actual, actual2)
 
@@ -75,14 +75,14 @@
         actual = data_utils.rand_password(2)
         self.assertIsInstance(actual, str)
         self.assertEqual(len(actual), 3)
-        self.assertRegexpMatches(actual, "[A-Za-z0-9~!@#$%^&*_=+]{3}")
+        self.assertRegex(actual, "[A-Za-z0-9~!@#$%^&*_=+]{3}")
         actual2 = data_utils.rand_password(2)
         self.assertNotEqual(actual, actual2)
 
     def test_rand_url(self):
         actual = data_utils.rand_url()
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "^https://url-[0-9]*\.com$")
+        self.assertRegex(actual, "^https://url-[0-9]*\.com$")
         actual2 = data_utils.rand_url()
         self.assertNotEqual(actual, actual2)
 
@@ -96,8 +96,8 @@
     def test_rand_mac_address(self):
         actual = data_utils.rand_mac_address()
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "^([0-9a-f][0-9a-f]:){5}"
-                                         "[0-9a-f][0-9a-f]$")
+        self.assertRegex(actual, "^([0-9a-f][0-9a-f]:){5}"
+                         "[0-9a-f][0-9a-f]$")
 
         actual2 = data_utils.rand_mac_address()
         self.assertNotEqual(actual, actual2)
@@ -117,12 +117,12 @@
     def test_random_bytes(self):
         actual = data_utils.random_bytes()  # default size=1024
         self.assertIsInstance(actual, str)
-        self.assertRegexpMatches(actual, "^[\x00-\xFF]{1024}")
+        self.assertRegex(actual, "^[\x00-\xFF]{1024}")
         actual2 = data_utils.random_bytes()
         self.assertNotEqual(actual, actual2)
 
         actual = data_utils.random_bytes(size=2048)
-        self.assertRegexpMatches(actual, "^[\x00-\xFF]{2048}")
+        self.assertRegex(actual, "^[\x00-\xFF]{2048}")
 
     def test_get_ipv6_addr_by_EUI64(self):
         actual = data_utils.get_ipv6_addr_by_EUI64('2001:db8::',
diff --git a/tempest/tests/services/compute/test_base_compute_client.py b/tempest/tests/lib/services/compute/test_base_compute_client.py
similarity index 86%
rename from tempest/tests/services/compute/test_base_compute_client.py
rename to tempest/tests/lib/services/compute/test_base_compute_client.py
index 1a78247..f552ef5 100644
--- a/tempest/tests/services/compute/test_base_compute_client.py
+++ b/tempest/tests/lib/services/compute/test_base_compute_client.py
@@ -16,12 +16,11 @@
 import mock
 from oslotest import mockpatch
 
-from tempest.api.compute import api_microversion_fixture
-from tempest import exceptions
 from tempest.lib.common import rest_client
-from tempest.services.compute.json import base_compute_client
-from tempest.tests import fake_auth_provider
-from tempest.tests.services.compute import base
+from tempest.lib import exceptions
+from tempest.lib.services.compute import base_compute_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services.compute import base
 
 
 class TestMicroversionHeaderCheck(base.BaseComputeServiceTest):
@@ -31,7 +30,11 @@
         fake_auth = fake_auth_provider.FakeAuthProvider()
         self.client = base_compute_client.BaseComputeClient(
             fake_auth, 'compute', 'regionOne')
-        self.useFixture(api_microversion_fixture.APIMicroversionFixture('2.2'))
+        base_compute_client.COMPUTE_MICROVERSION = '2.2'
+
+    def tearDown(self):
+        super(TestMicroversionHeaderCheck, self).tearDown()
+        base_compute_client.COMPUTE_MICROVERSION = None
 
     def _check_microverion_header_in_response(self, fake_response):
         def request(*args, **kwargs):
@@ -77,8 +80,11 @@
         super(TestSchemaVersionsNone, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
         self.client = DummyServiceClient1(fake_auth, 'compute', 'regionOne')
-        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
-            self.api_microversion))
+        base_compute_client.COMPUTE_MICROVERSION = self.api_microversion
+
+    def tearDown(self):
+        super(TestSchemaVersionsNone, self).tearDown()
+        base_compute_client.COMPUTE_MICROVERSION = None
 
     def test_schema(self):
         self.assertEqual(self.expected_schema,
@@ -132,8 +138,11 @@
         super(TestSchemaVersionsNotFound, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
         self.client = DummyServiceClient2(fake_auth, 'compute', 'regionOne')
-        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
-            self.api_microversion))
+        base_compute_client.COMPUTE_MICROVERSION = self.api_microversion
+
+    def tearDown(self):
+        super(TestSchemaVersionsNotFound, self).tearDown()
+        base_compute_client.COMPUTE_MICROVERSION = None
 
     def test_schema(self):
         self.assertRaises(exceptions.JSONSchemaNotFound,
@@ -170,7 +179,11 @@
         fake_auth = fake_auth_provider.FakeAuthProvider()
         self.client = base_compute_client.BaseComputeClient(
             fake_auth, 'compute', 'regionOne')
-        self.useFixture(api_microversion_fixture.APIMicroversionFixture('2.2'))
+        base_compute_client.COMPUTE_MICROVERSION = '2.2'
+
+    def tearDown(self):
+        super(TestClientWithMicroversionHeader, self).tearDown()
+        base_compute_client.COMPUTE_MICROVERSION = None
 
     def test_microverion_header(self):
         header = self.client.get_headers()
diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py
index f7bc7e4..6a01490 100644
--- a/tempest/tests/lib/test_auth.py
+++ b/tempest/tests/lib/test_auth.py
@@ -382,6 +382,31 @@
         expected = 'http://fake_url/'
         self._test_base_url_helper(expected, self.filters)
 
+    def test_base_url_with_unversioned_endpoint(self):
+        auth_data = {
+            'serviceCatalog': [
+                {
+                    'type': 'identity',
+                    'endpoints': [
+                        {
+                            'region': 'FakeRegion',
+                            'publicURL': 'http://fake_url'
+                        }
+                    ]
+                }
+            ]
+        }
+
+        filters = {
+            'service': 'identity',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion',
+            'api_version': 'v2.0'
+        }
+
+        expected = 'http://fake_url/v2.0'
+        self._test_base_url_helper(expected, filters, ('token', auth_data))
+
     def test_token_not_expired(self):
         expiry_data = datetime.datetime.utcnow() + datetime.timedelta(days=1)
         self._verify_expiry(expiry_data=expiry_data, should_be_expired=False)
@@ -478,3 +503,70 @@
         expected = self._get_result_url_from_endpoint(
             self._endpoints[0]['endpoints'][2])
         self._test_base_url_helper(expected, self.filters)
+
+    # Overwrites v2 test
+    def test_base_url_with_unversioned_endpoint(self):
+        auth_data = {
+            'catalog': [
+                {
+                    'type': 'identity',
+                    'endpoints': [
+                        {
+                            'region': 'FakeRegion',
+                            'url': 'http://fake_url',
+                            'interface': 'public'
+                        }
+                    ]
+                }
+            ]
+        }
+
+        filters = {
+            'service': 'identity',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion',
+            'api_version': 'v3'
+        }
+
+        expected = 'http://fake_url/v3'
+        self._test_base_url_helper(expected, filters, ('token', auth_data))
+
+
+class TestKeystoneV3Credentials(base.TestCase):
+    def testSetAttrUserDomain(self):
+        creds = auth.KeystoneV3Credentials()
+        creds.user_domain_name = 'user_domain'
+        creds.domain_name = 'domain'
+        self.assertEqual('user_domain', creds.user_domain_name)
+        creds = auth.KeystoneV3Credentials()
+        creds.domain_name = 'domain'
+        creds.user_domain_name = 'user_domain'
+        self.assertEqual('user_domain', creds.user_domain_name)
+
+    def testSetAttrProjectDomain(self):
+        creds = auth.KeystoneV3Credentials()
+        creds.project_domain_name = 'project_domain'
+        creds.domain_name = 'domain'
+        self.assertEqual('project_domain', creds.user_domain_name)
+        creds = auth.KeystoneV3Credentials()
+        creds.domain_name = 'domain'
+        creds.project_domain_name = 'project_domain'
+        self.assertEqual('project_domain', creds.project_domain_name)
+
+    def testProjectTenantNoCollision(self):
+        creds = auth.KeystoneV3Credentials(tenant_id='tenant')
+        self.assertEqual('tenant', creds.project_id)
+        creds = auth.KeystoneV3Credentials(project_id='project')
+        self.assertEqual('project', creds.tenant_id)
+        creds = auth.KeystoneV3Credentials(tenant_name='tenant')
+        self.assertEqual('tenant', creds.project_name)
+        creds = auth.KeystoneV3Credentials(project_name='project')
+        self.assertEqual('project', creds.tenant_name)
+
+    def testProjectTenantCollision(self):
+        attrs = {'tenant_id': 'tenant', 'project_id': 'project'}
+        self.assertRaises(
+            exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs)
+        attrs = {'tenant_name': 'tenant', 'project_name': 'project'}
+        self.assertRaises(
+            exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs)
diff --git a/tempest/tests/test_microversions.py b/tempest/tests/test_microversions.py
index 6738641..cef7975 100644
--- a/tempest/tests/test_microversions.py
+++ b/tempest/tests/test_microversions.py
@@ -17,7 +17,7 @@
 
 from tempest.api.compute import base as compute_base
 from tempest import config
-from tempest import exceptions
+from tempest.lib import exceptions
 from tempest.tests import base
 from tempest.tests import fake_config
 
@@ -64,9 +64,9 @@
                       expected_pass_tests,
                       expected_skip_tests):
         cfg.CONF.set_default('min_microversion',
-                             cfg_min, group='compute-feature-enabled')
+                             cfg_min, group='compute')
         cfg.CONF.set_default('max_microversion',
-                             cfg_max, group='compute-feature-enabled')
+                             cfg_max, group='compute')
         try:
             for test_class in expected_pass_tests:
                 test_class.skip_checks()
@@ -138,16 +138,16 @@
 
     def test_config_invalid_version(self):
         cfg.CONF.set_default('min_microversion',
-                             '2.5', group='compute-feature-enabled')
+                             '2.5', group='compute')
         cfg.CONF.set_default('max_microversion',
-                             '2.1', group='compute-feature-enabled')
+                             '2.1', group='compute')
         self.assertRaises(exceptions.InvalidAPIVersionRange,
                           VersionTestNoneTolatest.skip_checks)
 
     def test_config_version_invalid_test_version(self):
         cfg.CONF.set_default('min_microversion',
-                             None, group='compute-feature-enabled')
+                             None, group='compute')
         cfg.CONF.set_default('max_microversion',
-                             '2.13', group='compute-feature-enabled')
+                             '2.13', group='compute')
         self.assertRaises(exceptions.InvalidAPIVersionRange,
                           InvalidVersionTest.skip_checks)
diff --git a/tools/skip_tracker.py b/tools/skip_tracker.py
index a47e217..b554514 100755
--- a/tools/skip_tracker.py
+++ b/tools/skip_tracker.py
@@ -73,21 +73,23 @@
     DEF_RE = re.compile(r'\s*def (\w+)\(')
     bug_found = False
     results = []
-    lines = open(path, 'rb').readlines()
-    for x, line in enumerate(lines):
-        if not bug_found:
-            res = BUG_RE.match(line)
-            if res:
-                bug_no = int(res.group(1))
-                debug("Found bug skip %s on line %d", bug_no, x + 1)
-                bug_found = True
-        else:
-            res = DEF_RE.match(line)
-            if res:
-                method = res.group(1)
-                debug("Found test method %s skips for bug %d", method, bug_no)
-                results.append((method, bug_no))
-                bug_found = False
+    with open(path, 'rb') as content:
+        lines = content.readlines()
+        for x, line in enumerate(lines):
+            if not bug_found:
+                res = BUG_RE.match(line)
+                if res:
+                    bug_no = int(res.group(1))
+                    debug("Found bug skip %s on line %d", bug_no, x + 1)
+                    bug_found = True
+            else:
+                res = DEF_RE.match(line)
+                if res:
+                    method = res.group(1)
+                    debug("Found test method %s skips for bug %d",
+                          method, bug_no)
+                    results.append((method, bug_no))
+                    bug_found = False
     return results