Merge "Fix logic in dump_accounts"
diff --git a/.coveragerc b/.coveragerc
index c9b6467..51482d3 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,4 +1,4 @@
 [run]
 branch = True
 source = tempest
-omit = tempest/tests/*,tempest/openstack/*
+omit = tempest/tests/*,tempest/scenario/test_*.py,tempest/api_schema/*,tempest/api/*
diff --git a/requirements.txt b/requirements.txt
index aa304a4..86c8a63 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,27 +1,27 @@
 # The order of packages is significant, because pip processes them in the order
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
-pbr>=1.6
+pbr>=1.6 # Apache-2.0
 cliff>=1.15.0 # Apache-2.0
-anyjson>=0.3.3
-httplib2>=0.7.5
-jsonschema!=2.5.0,<3.0.0,>=2.0.0
-testtools>=1.4.0
-paramiko>=1.13.0
-netaddr!=0.7.16,>=0.7.12
-testrepository>=0.0.18
-pyOpenSSL>=0.14
+anyjson>=0.3.3 # BSD
+httplib2>=0.7.5 # MIT
+jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
+testtools>=1.4.0 # MIT
+paramiko>=1.13.0 # LGPL
+netaddr!=0.7.16,>=0.7.12 # BSD
+testrepository>=0.0.18 # Apache-2.0/BSD
+pyOpenSSL>=0.14 # Apache-2.0
 oslo.concurrency>=2.3.0 # Apache-2.0
 oslo.config>=3.2.0 # Apache-2.0
 oslo.i18n>=1.5.0 # Apache-2.0
 oslo.log>=1.14.0 # Apache-2.0
 oslo.serialization>=1.10.0 # Apache-2.0
-oslo.utils>=3.2.0 # Apache-2.0
-six>=1.9.0
-iso8601>=0.1.9
-fixtures>=1.3.1
-testscenarios>=0.4
-tempest-lib>=0.13.0
-PyYAML>=3.1.0
+oslo.utils>=3.4.0 # Apache-2.0
+six>=1.9.0 # MIT
+iso8601>=0.1.9 # MIT
+fixtures>=1.3.1 # Apache-2.0/BSD
+testscenarios>=0.4 # Apache-2.0/BSD
+tempest-lib>=0.13.0 # Apache-2.0
+PyYAML>=3.1.0 # MIT
 stevedore>=1.5.0 # Apache-2.0
-PrettyTable<0.8,>=0.7
+PrettyTable<0.8,>=0.7 # BSD
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 7c4c30c..653a3cd 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -79,11 +79,6 @@
     def _get_server_status(self, server_id):
         return self._get_server_details(server_id)['status']
 
-    def _create_server(self, volume_backed=False):
-            server = self.create_test_server(wait_until="ACTIVE",
-                                             volume_backed=volume_backed)
-            return server['id']
-
     def _volume_clean_up(self, server_id, volume_id):
         body = self.volumes_client.show_volume(volume_id)['volume']
         if body['status'] == 'in-use':
@@ -103,7 +98,8 @@
                               volume_backed, *block* migration is not used.
         """
         # Live migrate an instance to another host
-        server_id = self._create_server(volume_backed=volume_backed)
+        server_id = self.create_test_server(wait_until="ACTIVE",
+                                            volume_backed=volume_backed)['id']
         actual_host = self._get_host_for_server(server_id)
         target_host = self._get_host_other_than(actual_host)
 
@@ -153,7 +149,7 @@
                       block_migrate_cinder_iscsi,
                       'Block Live migration not configured for iSCSI')
     def test_iscsi_volume(self):
-        server_id = self._create_server()
+        server_id = self.create_test_server(wait_until="ACTIVE")['id']
         actual_host = self._get_host_for_server(server_id)
         target_host = self._get_host_other_than(actual_host)
 
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index fd6f105..49c7318 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -15,6 +15,7 @@
 from tempest_lib import decorators
 
 from tempest.api.compute import base
+from tempest.common import compute
 from tempest.common import fixed_network
 from tempest.common.utils import data_utils
 from tempest.common import waiters
@@ -104,16 +105,14 @@
     def test_list_servers_filter_by_exist_host(self):
         # Filter the list of servers by existent host
         name = data_utils.rand_name('server')
-        flavor = self.flavor_ref
-        image_id = self.image_ref
         network = self.get_tenant_network()
         network_kwargs = fixed_network.set_networks_kwarg(network)
-        test_server = self.client.create_server(name=name, imageRef=image_id,
-                                                flavorRef=flavor,
-                                                **network_kwargs)['server']
+        # We need to create the server as an admin, so we can't use
+        # self.create_test_server() here as this method creates the server
+        # in the "primary" (i.e non-admin) tenant.
+        test_server, _ = compute.create_test_server(
+            self.os_adm, wait_until="ACTIVE", name=name, **network_kwargs)
         self.addCleanup(self.client.delete_server, test_server['id'])
-        waiters.wait_for_server_status(self.client,
-                                       test_server['id'], 'ACTIVE')
         server = self.client.show_server(test_server['id'])['server']
         self.assertEqual(server['status'], 'ACTIVE')
         hostname = server[self._host_key]
diff --git a/tempest/api/compute/keypairs/base.py b/tempest/api/compute/keypairs/base.py
index 15f231b..ebfb724 100644
--- a/tempest/api/compute/keypairs/base.py
+++ b/tempest/api/compute/keypairs/base.py
@@ -27,10 +27,12 @@
     def _delete_keypair(self, keypair_name):
         self.client.delete_keypair(keypair_name)
 
-    def _create_keypair(self, keypair_name, pub_key=None):
+    def _create_keypair(self, keypair_name, pub_key=None, keypair_type=None):
         kwargs = {'name': keypair_name}
         if pub_key:
             kwargs.update({'public_key': pub_key})
+        if keypair_type:
+            kwargs.update({'type': keypair_type})
         body = self.client.create_keypair(**kwargs)['keypair']
         self.addCleanup(self._delete_keypair, keypair_name)
         return body
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index d10bf14..be6f615 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -19,6 +19,8 @@
 
 
 class KeyPairsV2TestJSON(base.BaseKeypairTest):
+    max_microversion = '2.1'
+
     @test.idempotent_id('1d1dbedb-d7a0-432a-9d09-83f543c3c19b')
     def test_keypairs_create_list_delete(self):
         # Keypairs created should be available in the response list
diff --git a/tempest/api/compute/keypairs/test_keypairs_v22.py b/tempest/api/compute/keypairs/test_keypairs_v22.py
new file mode 100644
index 0000000..997ef9b
--- /dev/null
+++ b/tempest/api/compute/keypairs/test_keypairs_v22.py
@@ -0,0 +1,51 @@
+# Copyright 2016 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.api.compute.keypairs import test_keypairs
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+class KeyPairsV22TestJSON(test_keypairs.KeyPairsV2TestJSON):
+    min_microversion = '2.2'
+    max_microversion = 'latest'
+
+    def _check_keypair_type(self, keypair, keypair_type):
+        if keypair_type is None:
+            keypair_type = 'ssh'
+        self.assertEqual(keypair_type, keypair['type'])
+
+    def _test_keypairs_create_list_show(self, keypair_type=None):
+        k_name = data_utils.rand_name('keypair')
+        keypair = self._create_keypair(k_name, keypair_type=keypair_type)
+        # Verify whether 'type' is present in keypair create response of
+        # version 2.2 and it is with default value 'ssh'.
+        self._check_keypair_type(keypair, keypair_type)
+        keypair_detail = self.client.show_keypair(k_name)['keypair']
+        self._check_keypair_type(keypair_detail, keypair_type)
+        fetched_list = self.client.list_keypairs()['keypairs']
+        for keypair in fetched_list:
+            # Verify whether 'type' is present in keypair list response of
+            # version 2.2 and it is with default value 'ssh'.
+            if keypair['keypair']['name'] == k_name:
+                self._check_keypair_type(keypair['keypair'], keypair_type)
+
+    @test.idempotent_id('8726fa85-7f98-4b20-af9e-f710a4f3391c')
+    def test_keypairsv22_create_list_show(self):
+        self._test_keypairs_create_list_show()
+
+    @test.idempotent_id('89d59d43-f735-441a-abcf-0601727f47b6')
+    def test_keypairsv22_create_list_show_with_type(self):
+        keypair_type = 'x509'
+        self._test_keypairs_create_list_show(keypair_type=keypair_type)
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 9aa59f7..38c294b 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -158,7 +158,9 @@
             to_port=to_port2)['security_group_rule']
         rule2_id = rule['id']
         # Delete the Security Group rule2 at the end of this method
-        self.addCleanup(self.client.delete_security_group_rule, rule2_id)
+        self.addCleanup(
+            self.security_group_rules_client.delete_security_group_rule,
+            rule2_id)
 
         # Get rules of the created Security Group
         rules = self.security_groups_client.show_security_group(
diff --git a/tempest/api/identity/admin/v2/test_endpoints.py b/tempest/api/identity/admin/v2/test_endpoints.py
index bff4f91..349edfa 100644
--- a/tempest/api/identity/admin/v2/test_endpoints.py
+++ b/tempest/api/identity/admin/v2/test_endpoints.py
@@ -27,7 +27,7 @@
         s_name = data_utils.rand_name('service')
         s_type = data_utils.rand_name('type')
         s_description = data_utils.rand_name('description')
-        cls.service_data = cls.client.create_service(
+        cls.service_data = cls.services_client.create_service(
             s_name, s_type, description=s_description)['OS-KSADM:service']
         cls.service_id = cls.service_data['id']
         cls.service_ids.append(cls.service_id)
@@ -50,7 +50,7 @@
         for e in cls.setup_endpoints:
             cls.client.delete_endpoint(e['id'])
         for s in cls.service_ids:
-            cls.client.delete_service(s)
+            cls.services_client.delete_service(s)
         super(EndPointsTestJSON, cls).resource_cleanup()
 
     @test.idempotent_id('11f590eb-59d8-4067-8b2b-980c7f387f51')
diff --git a/tempest/api/identity/admin/v2/test_services.py b/tempest/api/identity/admin/v2/test_services.py
index 04e15d2..5685922 100644
--- a/tempest/api/identity/admin/v2/test_services.py
+++ b/tempest/api/identity/admin/v2/test_services.py
@@ -25,9 +25,9 @@
 
     def _del_service(self, service_id):
         # Deleting the service created in this method
-        self.client.delete_service(service_id)
+        self.services_client.delete_service(service_id)
         # Checking whether service is deleted successfully
-        self.assertRaises(lib_exc.NotFound, self.client.show_service,
+        self.assertRaises(lib_exc.NotFound, self.services_client.show_service,
                           service_id)
 
     @test.idempotent_id('84521085-c6e6-491c-9a08-ec9f70f90110')
@@ -37,7 +37,7 @@
         name = data_utils.rand_name('service')
         type = data_utils.rand_name('type')
         description = data_utils.rand_name('description')
-        service_data = self.client.create_service(
+        service_data = self.services_client.create_service(
             name, type, description=description)['OS-KSADM:service']
         self.assertFalse(service_data['id'] is None)
         self.addCleanup(self._del_service, service_data['id'])
@@ -50,8 +50,9 @@
         self.assertIn('description', service_data)
         self.assertEqual(description, service_data['description'])
         # Get service
-        fetched_service = (self.client.show_service(service_data['id'])
-                           ['OS-KSADM:service'])
+        fetched_service = (
+            self.services_client.show_service(service_data['id'])
+            ['OS-KSADM:service'])
         # verifying the existence of service created
         self.assertIn('id', fetched_service)
         self.assertEqual(fetched_service['id'], service_data['id'])
@@ -68,7 +69,8 @@
         # Create a service only with name and type
         name = data_utils.rand_name('service')
         type = data_utils.rand_name('type')
-        service = self.client.create_service(name, type)['OS-KSADM:service']
+        service = self.services_client.create_service(name,
+                                                      type)['OS-KSADM:service']
         self.assertIn('id', service)
         self.addCleanup(self._del_service, service['id'])
         self.assertIn('name', service)
@@ -85,17 +87,17 @@
             name = data_utils.rand_name('service')
             type = data_utils.rand_name('type')
             description = data_utils.rand_name('description')
-            service = self.client.create_service(
+            service = self.services_client.create_service(
                 name, type, description=description)['OS-KSADM:service']
             services.append(service)
         service_ids = map(lambda x: x['id'], services)
 
         def delete_services():
             for service_id in service_ids:
-                self.client.delete_service(service_id)
+                self.services_client.delete_service(service_id)
 
         self.addCleanup(delete_services)
         # List and Verify Services
-        body = self.client.list_services()['OS-KSADM:services']
+        body = self.services_client.list_services()['OS-KSADM:services']
         found = [serv for serv in body if serv['id'] in service_ids]
         self.assertEqual(len(found), len(services), 'Services not found')
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 1ad8b92..e317ed0 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -104,6 +104,7 @@
         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
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/api/network/admin/test_dhcp_agent_scheduler.py b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
index 5ff465b..fcb6fce 100644
--- a/tempest/api/network/admin/test_dhcp_agent_scheduler.py
+++ b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
@@ -84,7 +84,7 @@
             self._remove_network_from_dhcp_agent(network_id, agent)
 
     def _remove_network_from_dhcp_agent(self, network_id, agent):
-        self.admin_agents_client.remove_network_from_dhcp_agent(
+        self.admin_agents_client.delete_network_from_dhcp_agent(
             agent_id=agent['id'],
             network_id=network_id)
         self.assertFalse(self._check_network_in_dhcp_agent(
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index c64cf77..5d12e17 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -110,7 +110,7 @@
     @test.idempotent_id('9464e5e7-8625-49c3-8fd1-89c52be59d66')
     def test_add_list_remove_router_on_l3_agent(self):
         l3_agent_ids = list()
-        self.admin_agents_client.add_router_to_l3_agent(
+        self.admin_agents_client.create_router_on_l3_agent(
             self.agent['id'],
             router_id=self.router['id'])
         body = (
@@ -120,7 +120,7 @@
             self.assertIn('agent_type', agent)
             self.assertEqual('L3 agent', agent['agent_type'])
         self.assertIn(self.agent['id'], l3_agent_ids)
-        body = self.admin_agents_client.remove_router_from_l3_agent(
+        body = self.admin_agents_client.delete_router_from_l3_agent(
             self.agent['id'],
             self.router['id'])
         # NOTE(afazekas): The deletion not asserted, because neutron
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 81337f3..14a6358 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -76,6 +76,8 @@
         cls.quotas_client = cls.os.network_quotas_client
         cls.floating_ips_client = cls.os.floating_ips_client
         cls.security_groups_client = cls.os.security_groups_client
+        cls.security_group_rules_client = (
+            cls.os.security_group_rules_client)
 
     @classmethod
     def resource_setup(cls):
diff --git a/tempest/api/network/base_security_groups.py b/tempest/api/network/base_security_groups.py
index 1525e19..3ea3aea 100644
--- a/tempest/api/network/base_security_groups.py
+++ b/tempest/api/network/base_security_groups.py
@@ -40,10 +40,11 @@
         self.assertNotIn(secgroup_id, secgroup_list)
 
     def _delete_security_group_rule(self, rule_id):
-        self.client.delete_security_group_rule(rule_id)
+        self.security_group_rules_client.delete_security_group_rule(rule_id)
         # Asserting that the security group is not found in the list
         # after deletion
-        list_body = self.client.list_security_group_rules()
+        list_body = (
+            self.security_group_rules_client.list_security_group_rules())
         rules_list = list()
         for rule in list_body['security_group_rules']:
             rules_list.append(rule['id'])
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index cf45328..7d0765e 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -41,7 +41,8 @@
                                            remote_ip_prefix=None):
         # Create Security Group rule with the input params and validate
         # that SG rule is created with the same parameters.
-        rule_create_body = self.client.create_security_group_rule(
+        sec_group_rules_client = self.security_group_rules_client
+        rule_create_body = sec_group_rules_client.create_security_group_rule(
             security_group_id=sg_id,
             direction=direction,
             ethertype=ethertype,
@@ -116,8 +117,9 @@
 
         # Create rules for each protocol
         protocols = ['tcp', 'udp', 'icmp']
+        client = self.security_group_rules_client
         for protocol in protocols:
-            rule_create_body = self.client.create_security_group_rule(
+            rule_create_body = client.create_security_group_rule(
                 security_group_id=group_create_body['security_group']['id'],
                 protocol=protocol,
                 direction='ingress',
@@ -125,7 +127,7 @@
             )
 
             # Show details of the created security rule
-            show_rule_body = self.client.show_security_group_rule(
+            show_rule_body = client.show_security_group_rule(
                 rule_create_body['security_group_rule']['id']
             )
             create_dict = rule_create_body['security_group_rule']
@@ -135,7 +137,8 @@
                                  "%s does not match." % key)
 
             # List rules and verify created rule is in response
-            rule_list_body = self.client.list_security_group_rules()
+            rule_list_body = (
+                self.security_group_rules_client.list_security_group_rules())
             rule_list = [rule['id']
                          for rule in rule_list_body['security_group_rules']]
             self.assertIn(rule_create_body['security_group_rule']['id'],
@@ -223,7 +226,8 @@
         direction = 'ingress'
         protocol = 17
         security_group_id = group_create_body['security_group']['id']
-        rule_create_body = self.client.create_security_group_rule(
+        client = self.security_group_rules_client
+        rule_create_body = client.create_security_group_rule(
             security_group_id=security_group_id,
             direction=direction,
             protocol=protocol
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index 58e39e9..ff38e9e 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -46,9 +46,10 @@
     @test.idempotent_id('4c094c09-000b-4e41-8100-9617600c02a6')
     def test_show_non_existent_security_group_rule(self):
         non_exist_id = str(uuid.uuid4())
-        self.assertRaises(lib_exc.NotFound,
-                          self.client.show_security_group_rule,
-                          non_exist_id)
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.security_group_rules_client.show_security_group_rule,
+            non_exist_id)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('1f1bb89d-5664-4956-9fcd-83ee0fa603df')
@@ -67,7 +68,8 @@
         # Create rule with bad protocol name
         pname = 'bad_protocol_name'
         self.assertRaises(
-            lib_exc.BadRequest, self.client.create_security_group_rule,
+            lib_exc.BadRequest,
+            self.security_group_rules_client.create_security_group_rule,
             security_group_id=group_create_body['security_group']['id'],
             protocol=pname, direction='ingress', ethertype=self.ethertype)
 
@@ -80,7 +82,8 @@
         prefix = ['192.168.1./24', '192.168.1.1/33', 'bad_prefix', '256']
         for remote_ip_prefix in prefix:
             self.assertRaises(
-                lib_exc.BadRequest, self.client.create_security_group_rule,
+                lib_exc.BadRequest,
+                self.security_group_rules_client.create_security_group_rule,
                 security_group_id=group_create_body['security_group']['id'],
                 protocol='tcp', direction='ingress', ethertype=self.ethertype,
                 remote_ip_prefix=remote_ip_prefix)
@@ -95,7 +98,8 @@
         group_ids = ['bad_group_id', non_exist_id]
         for remote_group_id in group_ids:
             self.assertRaises(
-                lib_exc.NotFound, self.client.create_security_group_rule,
+                lib_exc.NotFound,
+                self.security_group_rules_client.create_security_group_rule,
                 security_group_id=group_create_body['security_group']['id'],
                 protocol='tcp', direction='ingress', ethertype=self.ethertype,
                 remote_group_id=remote_group_id)
@@ -109,7 +113,8 @@
         # Create rule specifying both remote_ip_prefix and remote_group_id
         prefix = self._tenant_network_cidr
         self.assertRaises(
-            lib_exc.BadRequest, self.client.create_security_group_rule,
+            lib_exc.BadRequest,
+            self.security_group_rules_client.create_security_group_rule,
             security_group_id=sg1_body['security_group']['id'],
             protocol='tcp', direction='ingress',
             ethertype=self.ethertype, remote_ip_prefix=prefix,
@@ -123,7 +128,8 @@
         # Create rule with bad ethertype
         ethertype = 'bad_ethertype'
         self.assertRaises(
-            lib_exc.BadRequest, self.client.create_security_group_rule,
+            lib_exc.BadRequest,
+            self.security_group_rules_client.create_security_group_rule,
             security_group_id=group_create_body['security_group']['id'],
             protocol='udp', direction='ingress', ethertype=ethertype)
 
@@ -140,7 +146,8 @@
                   (-16, 65536, 'Invalid value for port')]
         for pmin, pmax, msg in states:
             ex = self.assertRaises(
-                lib_exc.BadRequest, self.client.create_security_group_rule,
+                lib_exc.BadRequest,
+                self.security_group_rules_client.create_security_group_rule,
                 security_group_id=group_create_body['security_group']['id'],
                 protocol='tcp', port_range_min=pmin, port_range_max=pmax,
                 direction='ingress', ethertype=self.ethertype)
@@ -152,7 +159,8 @@
                   (300, 1, 'Invalid value for ICMP type')]
         for pmin, pmax, msg in states:
             ex = self.assertRaises(
-                lib_exc.BadRequest, self.client.create_security_group_rule,
+                lib_exc.BadRequest,
+                self.security_group_rules_client.create_security_group_rule,
                 security_group_id=group_create_body['security_group']['id'],
                 protocol='icmp', port_range_min=pmin, port_range_max=pmax,
                 direction='ingress', ethertype=self.ethertype)
@@ -176,7 +184,7 @@
         min_port = 66
         max_port = 67
         # Create a rule with valid params
-        self.client.create_security_group_rule(
+        self.security_group_rules_client.create_security_group_rule(
             security_group_id=body['security_group']['id'],
             direction='ingress',
             ethertype=self.ethertype,
@@ -187,7 +195,8 @@
 
         # Try creating the same security group rule, it should fail
         self.assertRaises(
-            lib_exc.Conflict, self.client.create_security_group_rule,
+            lib_exc.Conflict,
+            self.security_group_rules_client.create_security_group_rule,
             security_group_id=body['security_group']['id'],
             protocol='tcp', direction='ingress', ethertype=self.ethertype,
             port_range_min=min_port, port_range_max=max_port)
@@ -197,10 +206,11 @@
     def test_create_security_group_rule_with_non_existent_security_group(self):
         # Create security group rules with not existing security group.
         non_existent_sg = str(uuid.uuid4())
-        self.assertRaises(lib_exc.NotFound,
-                          self.client.create_security_group_rule,
-                          security_group_id=non_existent_sg,
-                          direction='ingress', ethertype=self.ethertype)
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.security_group_rules_client.create_security_group_rule,
+            security_group_id=non_existent_sg,
+            direction='ingress', ethertype=self.ethertype)
 
 
 class NegativeSecGroupIPv6Test(NegativeSecGroupTest):
@@ -221,7 +231,7 @@
             self.assertRaisesRegexp(
                 lib_exc.BadRequest,
                 "Conflicting value ethertype",
-                self.client.create_security_group_rule,
+                self.security_group_rules_client.create_security_group_rule,
                 security_group_id=group_create_body['security_group']['id'],
                 protocol='tcp', direction='ingress',
                 ethertype=pair['ethertype'],
diff --git a/tempest/api_schema/response/compute/v2_2/__init__.py b/tempest/api_schema/response/compute/v2_2/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/api_schema/response/compute/v2_2/__init__.py
diff --git a/tempest/api_schema/response/compute/v2_2/keypairs.py b/tempest/api_schema/response/compute/v2_2/keypairs.py
new file mode 100644
index 0000000..5d8d24d
--- /dev/null
+++ b/tempest/api_schema/response/compute/v2_2/keypairs.py
@@ -0,0 +1,41 @@
+# Copyright 2016 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.
+
+import copy
+
+from tempest.api_schema.response.compute.v2_1 import keypairs
+
+get_keypair = copy.deepcopy(keypairs.get_keypair)
+get_keypair['response_body']['properties']['keypair'][
+    'properties'].update({'type': {'type': 'string'}})
+get_keypair['response_body']['properties']['keypair'][
+    'required'].append('type')
+
+create_keypair = copy.deepcopy(keypairs.create_keypair)
+create_keypair['status_code'] = [201]
+create_keypair['response_body']['properties']['keypair'][
+    'properties'].update({'type': {'type': 'string'}})
+create_keypair['response_body']['properties']['keypair'][
+    'required'].append('type')
+
+delete_keypair = {
+    'status_code': [204],
+}
+
+list_keypairs = copy.deepcopy(keypairs.list_keypairs)
+list_keypairs['response_body']['properties']['keypairs'][
+    'items']['properties']['keypair'][
+    'properties'].update({'type': {'type': 'string'}})
+list_keypairs['response_body']['properties']['keypairs'][
+    'items']['properties']['keypair']['required'].append('type')
diff --git a/tempest/clients.py b/tempest/clients.py
index 2c40d0c..7f89914 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -98,6 +98,8 @@
     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 \
@@ -124,6 +126,8 @@
 from tempest.services.network.json.network_client import NetworkClient
 from tempest.services.network.json.quotas_client import QuotasClient \
     as NetworkQuotasClient
+from tempest.services.network.json.security_group_rules_client import \
+    SecurityGroupRulesClient
 from tempest.services.network.json.security_groups_client import \
     SecurityGroupsClient
 from tempest.services.network.json.subnetpools_client import SubnetpoolsClient
@@ -310,6 +314,14 @@
             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,
+            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_groups_client = SecurityGroupsClient(
             self.auth_provider,
             CONF.network.catalog_type,
@@ -488,6 +500,8 @@
                                         **params_v2_admin)
         self.users_client = UsersClient(self.auth_provider,
                                         **params_v2_admin)
+        self.services_v2_client = ServicesV2Client(self.auth_provider,
+                                                   **params_v2_admin)
         params_v2_public = params.copy()
         params_v2_public['endpoint_type'] = (
             CONF.identity.v2_public_endpoint_type)
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index d57bae3..73505e6 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -29,7 +29,8 @@
 
 def create_test_server(clients, validatable=False, validation_resources=None,
                        tenant_network=None, wait_until=None,
-                       volume_backed=False, **kwargs):
+                       volume_backed=False, name=None, flavor=None,
+                       image_id=None, **kwargs):
     """Common wrapper utility returning a test server.
 
     This method is a common wrapper returning a test server that can be
@@ -48,9 +49,16 @@
 
     # TODO(jlanoux) add support of wait_until PINGABLE/SSHABLE
 
-    name = kwargs.pop('name', data_utils.rand_name(__name__ + "-instance"))
-    flavor = kwargs.pop('flavor', CONF.compute.flavor_ref)
-    image_id = kwargs.pop('image_id', CONF.compute.image_ref)
+    name = name
+    flavor = flavor
+    image_id = image_id
+
+    if name is None:
+        name = data_utils.rand_name(__name__ + "-instance")
+    if flavor is None:
+        flavor = CONF.compute.flavor_ref
+    if image_id is None:
+        image_id = CONF.compute.image_ref
 
     kwargs = fixed_network.set_networks_kwarg(
         tenant_network, kwargs) or {}
diff --git a/tempest/hacking/ignored_list_T111.txt b/tempest/hacking/ignored_list_T111.txt
index 8130c85..20d58d2 100644
--- a/tempest/hacking/ignored_list_T111.txt
+++ b/tempest/hacking/ignored_list_T111.txt
@@ -1,3 +1,2 @@
 ./tempest/services/baremetal/base.py
-./tempest/services/network/json/agents_client.py
 ./tempest/services/network/json/quotas_client.py
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index bb4e521..f4e2185 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -69,6 +69,8 @@
         cls.subnets_client = cls.manager.subnets_client
         cls.floating_ips_client = cls.manager.floating_ips_client
         cls.security_groups_client = cls.manager.security_groups_client
+        cls.security_group_rules_client = (
+            cls.manager.security_group_rules_client)
         # Heat client
         cls.orchestration_client = cls.manager.orchestration_client
 
@@ -160,7 +162,7 @@
         self.addCleanup(client.delete_keypair, name)
         return body['keypair']
 
-    def create_server(self, name=None, image=None, flavor=None,
+    def create_server(self, name=None, image_id=None, flavor=None,
                       validatable=False, wait_until=None,
                       wait_on_delete=True, clients=None, **kwargs):
         """Wrapper utility that returns a test server.
@@ -240,7 +242,8 @@
             clients,
             tenant_network=tenant_network,
             wait_until=wait_until,
-            **kwargs)
+            name=name, flavor=flavor,
+            image_id=image_id, **kwargs)
 
         # TODO(jlanoux) Move wait_on_delete in compute.py
         if wait_on_delete:
@@ -939,11 +942,12 @@
                                             CONF.validation.ping_timeout,
                                             1)
 
-    def _create_security_group(self, client=None, tenant_id=None,
+    def _create_security_group(self, security_group_rules_client=None,
+                               tenant_id=None,
                                namestart='secgroup-smoke',
                                security_groups_client=None):
-        if client is None:
-            client = self.network_client
+        if security_group_rules_client is None:
+            security_group_rules_client = self.security_group_rules_client
         if security_groups_client is None:
             security_groups_client = self.security_groups_client
         if tenant_id is None:
@@ -954,7 +958,8 @@
 
         # Add rules to the security group
         rules = self._create_loginable_secgroup_rule(
-            client=client, secgroup=secgroup,
+            security_group_rules_client=security_group_rules_client,
+            secgroup=secgroup,
             security_groups_client=security_groups_client)
         for rule in rules:
             self.assertEqual(tenant_id, rule.tenant_id)
@@ -1010,7 +1015,8 @@
         return net_resources.DeletableSecurityGroup(client=client,
                                                     **sgs[0])
 
-    def _create_security_group_rule(self, secgroup=None, client=None,
+    def _create_security_group_rule(self, secgroup=None,
+                                    sec_group_rules_client=None,
                                     tenant_id=None,
                                     security_groups_client=None, **kwargs):
         """Create a rule from a dictionary of rule parameters.
@@ -1030,8 +1036,8 @@
                     port_range_max: 22
                     }
         """
-        if client is None:
-            client = self.network_client
+        if sec_group_rules_client is None:
+            sec_group_rules_client = self.security_group_rules_client
         if security_groups_client is None:
             security_groups_client = self.security_groups_client
         if not tenant_id:
@@ -1044,9 +1050,9 @@
                        tenant_id=secgroup.tenant_id)
         ruleset.update(kwargs)
 
-        sg_rule = client.create_security_group_rule(**ruleset)
+        sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
         sg_rule = net_resources.DeletableSecurityGroupRule(
-            client=client,
+            client=sec_group_rules_client,
             **sg_rule['security_group_rule']
         )
         self.addCleanup(self.delete_wrapper, sg_rule.delete)
@@ -1055,7 +1061,8 @@
 
         return sg_rule
 
-    def _create_loginable_secgroup_rule(self, client=None, secgroup=None,
+    def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
+                                        secgroup=None,
                                         security_groups_client=None):
         """Create loginable security group rule
 
@@ -1065,8 +1072,8 @@
         belonging to the same security group.
         """
 
-        if client is None:
-            client = self.network_client
+        if security_group_rules_client is None:
+            security_group_rules_client = self.security_group_rules_client
         if security_groups_client is None:
             security_groups_client = self.security_groups_client
         rules = []
@@ -1087,12 +1094,14 @@
                 ethertype='IPv6',
             )
         ]
+        sec_group_rules_client = security_group_rules_client
         for ruleset in rulesets:
             for r_direction in ['ingress', 'egress']:
                 ruleset['direction'] = r_direction
                 try:
                     sg_rule = self._create_security_group_rule(
-                        client=client, secgroup=secgroup,
+                        sec_group_rules_client=sec_group_rules_client,
+                        secgroup=secgroup,
                         security_groups_client=security_groups_client,
                         **ruleset)
                 except lib_exc.Conflict as ex:
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index cb6b968..5d4f7b3 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -97,9 +97,13 @@
         req = request.Request(login_url)
         req.add_header('Content-type', 'application/x-www-form-urlencoded')
         req.add_header('Referer', CONF.dashboard.dashboard_url)
+
+        # Pass the default domain name regardless of the auth version in order
+        # to test the scenario of when horizon is running with keystone v3
         params = {'username': username,
                   'password': password,
                   'region': parser.region,
+                  'domain': CONF.auth.default_credentials_domain_name,
                   'csrfmiddlewaretoken': parser.csrf_token}
         self.opener.open(req, parse.urlencode(params))
 
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index b8bec16..349ef11 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -684,9 +684,9 @@
         list_hosts = (self.admin_manager.network_client.
                       list_l3_agents_hosting_router)
         schedule_router = (self.admin_manager.network_agents_client.
-                           add_router_to_l3_agent)
+                           create_router_on_l3_agent)
         unschedule_router = (self.admin_manager.network_agents_client.
-                             remove_router_from_l3_agent)
+                             delete_router_from_l3_agent)
 
         agent_list = set(a["id"] for a in
                          self._list_agents(agent_type="L3 agent"))
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 8375d05..1bf4089 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -191,9 +191,11 @@
             port_range_max=22,
             direction='ingress',
         )
-        self._create_security_group_rule(secgroup=access_sg,
-                                         client=tenant.manager.network_client,
-                                         **ssh_rule)
+        sec_group_rules_client = tenant.manager.security_group_rules_client
+        self._create_security_group_rule(
+            secgroup=access_sg,
+            sec_group_rules_client=sec_group_rules_client,
+            **ssh_rule)
 
     def _verify_network_details(self, tenant):
         # Checks that we see the newly created network/subnet/router via
@@ -371,9 +373,11 @@
             protocol='icmp',
             direction='ingress'
         )
+        sec_group_rules_client = (
+            dest_tenant.manager.security_group_rules_client)
         self._create_security_group_rule(
             secgroup=dest_tenant.security_groups['default'],
-            client=dest_tenant.manager.network_client,
+            sec_group_rules_client=sec_group_rules_client,
             **ruleset
         )
         access_point_ssh = self._connect_to_access_point(source_tenant)
@@ -385,9 +389,11 @@
         self._test_cross_tenant_block(dest_tenant, source_tenant)
 
         # allow reverse traffic and check
+        sec_group_rules_client = (
+            source_tenant.manager.security_group_rules_client)
         self._create_security_group_rule(
             secgroup=source_tenant.security_groups['default'],
-            client=source_tenant.manager.network_client,
+            sec_group_rules_client=sec_group_rules_client,
             **ruleset
         )
 
@@ -468,9 +474,10 @@
             protocol='icmp',
             direction='ingress',
         )
+        sec_group_rules_client = new_tenant.manager.security_group_rules_client
         self._create_security_group_rule(
             secgroup=new_sg,
-            client=new_tenant.manager.network_client,
+            sec_group_rules_client=sec_group_rules_client,
             **icmp_rule)
         new_tenant.security_groups.update(new_sg=new_sg)
 
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 81ecda0..7b88025 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -70,7 +70,7 @@
         create_kwargs.update(self._get_bdm(
             vol_id, delete_on_termination=delete_on_termination))
         return self.create_server(
-            image='',
+            image_id='',
             wait_until='ACTIVE',
             **create_kwargs)
 
diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py
index 2e22bc6..e956100 100644
--- a/tempest/services/compute/json/keypairs_client.py
+++ b/tempest/services/compute/json/keypairs_client.py
@@ -15,21 +15,28 @@
 
 from oslo_serialization import jsonutils as json
 
-from tempest.api_schema.response.compute.v2_1 import keypairs as schema
+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.common import service_client
+from tempest.services.compute.json import base
 
 
-class KeyPairsClient(service_client.ServiceClient):
+class KeyPairsClient(base.BaseComputeClient):
+
+    schema_versions_info = [{'min': None, 'max': '2.1', 'schema': schemav21},
+                            {'min': '2.2', 'max': None, 'schema': schemav22}]
 
     def list_keypairs(self):
         resp, body = self.get("os-keypairs")
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.list_keypairs, resp, body)
         return service_client.ResponseBody(resp, body)
 
     def show_keypair(self, keypair_name):
         resp, body = self.get("os-keypairs/%s" % keypair_name)
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.get_keypair, resp, body)
         return service_client.ResponseBody(resp, body)
 
@@ -37,10 +44,12 @@
         post_body = json.dumps({'keypair': kwargs})
         resp, body = self.post("os-keypairs", body=post_body)
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.create_keypair, resp, body)
         return service_client.ResponseBody(resp, body)
 
     def delete_keypair(self, keypair_name):
         resp, body = self.delete("os-keypairs/%s" % keypair_name)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.delete_keypair, resp, body)
         return service_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v2/json/identity_client.py b/tempest/services/identity/v2/json/identity_client.py
index 0ff59d5..db334a6 100644
--- a/tempest/services/identity/v2/json/identity_client.py
+++ b/tempest/services/identity/v2/json/identity_client.py
@@ -39,41 +39,6 @@
         self.expected_success(204, resp.status)
         return service_client.ResponseBody(resp, body)
 
-    def create_service(self, name, type, **kwargs):
-        """Create a service."""
-        post_body = {
-            'name': name,
-            'type': type,
-            'description': kwargs.get('description')
-        }
-        post_body = json.dumps({'OS-KSADM:service': post_body})
-        resp, body = self.post('/OS-KSADM/services', post_body)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def show_service(self, service_id):
-        """Get Service."""
-        url = '/OS-KSADM/services/%s' % service_id
-        resp, body = self.get(url)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def list_services(self):
-        """List Service - Returns Services."""
-        resp, body = self.get('/OS-KSADM/services')
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return service_client.ResponseBody(resp, body)
-
-    def delete_service(self, service_id):
-        """Delete Service."""
-        url = '/OS-KSADM/services/%s' % service_id
-        resp, body = self.delete(url)
-        self.expected_success(204, resp.status)
-        return service_client.ResponseBody(resp, body)
-
     def create_endpoint(self, service_id, region_id, **kwargs):
         """Create an endpoint for service."""
         post_body = {
diff --git a/tempest/services/identity/v2/json/services_client.py b/tempest/services/identity/v2/json/services_client.py
new file mode 100644
index 0000000..436d00d
--- /dev/null
+++ b/tempest/services/identity/v2/json/services_client.py
@@ -0,0 +1,56 @@
+# Copyright 2015 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.common import service_client
+
+
+class ServicesClient(service_client.ServiceClient):
+    api_version = "v2.0"
+
+    def create_service(self, name, type, **kwargs):
+        """Create a service."""
+        post_body = {
+            'name': name,
+            'type': type,
+            'description': kwargs.get('description')
+        }
+        post_body = json.dumps({'OS-KSADM:service': post_body})
+        resp, body = self.post('/OS-KSADM/services', post_body)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return service_client.ResponseBody(resp, body)
+
+    def show_service(self, service_id):
+        """Get Service."""
+        url = '/OS-KSADM/services/%s' % service_id
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return service_client.ResponseBody(resp, body)
+
+    def list_services(self):
+        """List Service - Returns Services."""
+        resp, body = self.get('/OS-KSADM/services')
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return service_client.ResponseBody(resp, body)
+
+    def delete_service(self, service_id):
+        """Delete Service."""
+        url = '/OS-KSADM/services/%s' % service_id
+        resp, body = self.delete(url)
+        self.expected_success(204, resp.status)
+        return service_client.ResponseBody(resp, body)
diff --git a/tempest/services/image/v1/json/images_client.py b/tempest/services/image/v1/json/images_client.py
index 5b6a394..af2e68c 100644
--- a/tempest/services/image/v1/json/images_client.py
+++ b/tempest/services/image/v1/json/images_client.py
@@ -180,21 +180,27 @@
         self.expected_success(200, resp.status)
         return service_client.ResponseBody(resp, body)
 
-    def list_images(self, detail=False, properties=dict(),
-                    changes_since=None, **kwargs):
+    def list_images(self, detail=False, **kwargs):
+        """Return a list of all images filtered by input parameters.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-image-v1.html#listImage-v1
+
+        Most parameters except the following are passed to the API without
+        any changes.
+        :param changes_since: The name is changed to changes-since
+        """
         url = 'v1/images'
 
         if detail:
             url += '/detail'
 
-        params = {}
-        for key, value in properties.items():
-            params['property-%s' % key] = value
+        properties = kwargs.pop('properties', {})
+        for key, value in six.iteritems(properties):
+            kwargs['property-%s' % key] = value
 
-        kwargs.update(params)
-
-        if changes_since is not None:
-            kwargs['changes-since'] = changes_since
+        if kwargs.get('changes_since'):
+            kwargs['changes-since'] = kwargs.pop('changes_since')
 
         if len(kwargs) > 0:
             url += '?%s' % urllib.urlencode(kwargs)
diff --git a/tempest/services/network/json/agents_client.py b/tempest/services/network/json/agents_client.py
index 07f93b2..8bec847 100644
--- a/tempest/services/network/json/agents_client.py
+++ b/tempest/services/network/json/agents_client.py
@@ -38,7 +38,7 @@
         uri = '/agents/%s/l3-routers' % agent_id
         return self.list_resources(uri)
 
-    def add_router_to_l3_agent(self, agent_id, **kwargs):
+    def create_router_on_l3_agent(self, agent_id, **kwargs):
         # TODO(piyush): Current api-site doesn't contain this API description.
         # After fixing the api-site, we need to fix here also for putting the
         # link to api-site.
@@ -46,7 +46,7 @@
         uri = '/agents/%s/l3-routers' % agent_id
         return self.create_resource(uri, kwargs)
 
-    def remove_router_from_l3_agent(self, agent_id, router_id):
+    def delete_router_from_l3_agent(self, agent_id, router_id):
         uri = '/agents/%s/l3-routers/%s' % (agent_id, router_id)
         return self.delete_resource(uri)
 
@@ -54,7 +54,7 @@
         uri = '/agents/%s/dhcp-networks' % agent_id
         return self.list_resources(uri)
 
-    def remove_network_from_dhcp_agent(self, agent_id, network_id):
+    def delete_network_from_dhcp_agent(self, agent_id, network_id):
         uri = '/agents/%s/dhcp-networks/%s' % (agent_id,
                                                network_id)
         return self.delete_resource(uri)
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index e8e21d2..1e944a6 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -35,23 +35,6 @@
     quotas
     """
 
-    def create_security_group_rule(self, **kwargs):
-        uri = '/security-group-rules'
-        post_data = {'security_group_rule': kwargs}
-        return self.create_resource(uri, post_data)
-
-    def show_security_group_rule(self, security_group_rule_id, **fields):
-        uri = '/security-group-rules/%s' % security_group_rule_id
-        return self.show_resource(uri, **fields)
-
-    def delete_security_group_rule(self, security_group_rule_id):
-        uri = '/security-group-rules/%s' % security_group_rule_id
-        return self.delete_resource(uri)
-
-    def list_security_group_rules(self, **filters):
-        uri = '/security-group-rules'
-        return self.list_resources(uri, **filters)
-
     def show_extension(self, ext_alias, **fields):
         uri = '/extensions/%s' % ext_alias
         return self.show_resource(uri, **fields)
diff --git a/tempest/services/network/json/security_group_rules_client.py b/tempest/services/network/json/security_group_rules_client.py
new file mode 100644
index 0000000..b2ba5b2
--- /dev/null
+++ b/tempest/services/network/json/security_group_rules_client.py
@@ -0,0 +1,33 @@
+#    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.services.network.json import base
+
+
+class SecurityGroupRulesClient(base.BaseNetworkClient):
+
+    def create_security_group_rule(self, **kwargs):
+        uri = '/security-group-rules'
+        post_data = {'security_group_rule': kwargs}
+        return self.create_resource(uri, post_data)
+
+    def show_security_group_rule(self, security_group_rule_id, **fields):
+        uri = '/security-group-rules/%s' % security_group_rule_id
+        return self.show_resource(uri, **fields)
+
+    def delete_security_group_rule(self, security_group_rule_id):
+        uri = '/security-group-rules/%s' % security_group_rule_id
+        return self.delete_resource(uri)
+
+    def list_security_group_rules(self, **filters):
+        uri = '/security-group-rules'
+        return self.list_resources(uri, **filters)
diff --git a/test-requirements.txt b/test-requirements.txt
index 5b01ea9..eb43f31 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -3,10 +3,10 @@
 # process, which may cause wedges in the gate later.
 hacking<0.11,>=0.10.0
 # needed for doc build
-sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
-python-subunit>=0.0.18
+sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD
+python-subunit>=0.0.18 # Apache-2.0/BSD
 oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
-mox>=0.5.3
-mock>=1.2
-coverage>=3.6
+mox>=0.5.3 # Apache-2.0
+mock>=1.2 # BSD
+coverage>=3.6 # Apache-2.0
 oslotest>=1.10.0 # Apache-2.0
diff --git a/tools/install_venv_common.py b/tools/install_venv_common.py
index e279159..d1643f8 100644
--- a/tools/install_venv_common.py
+++ b/tools/install_venv_common.py
@@ -113,7 +113,7 @@
 
         # First things first, make sure our venv has the latest pip and
         # setuptools and pbr
-        self.pip_install('pip>=1.4')
+        self.pip_install('pip<8,>=1.4')
         self.pip_install('setuptools')
         self.pip_install('pbr')
 
diff --git a/tox.ini b/tox.ini
index 832a7b3..95f2cf1 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
 [tox]
 envlist = pep8,py34,py27
-minversion = 1.6
+minversion = 2.3.1
 skipsdist = True
 
 [tempestenv]