Merge "Updated from global requirements"
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/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..2ff0629 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -124,6 +124,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 +312,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,
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_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/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)