Merge "Use relative path in data_files in setup.cfg"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 1f8c889..c97eb97 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -5,12 +5,14 @@
 #
 
 # Print debugging output (set logging level to DEBUG instead of
-# default WARNING level). (boolean value)
+# default INFO level). (boolean value)
 #debug = false
 
-# Print more verbose output (set logging level to INFO instead of
-# default WARNING level). (boolean value)
-#verbose = false
+# If set to false, will disable INFO logging level, making WARNING the
+# default. (boolean value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+#verbose = true
 
 # The name of a logging configuration file. This file is appended to
 # any existing logging configuration files. For details about logging
@@ -376,6 +378,10 @@
 # value)
 #live_migration = true
 
+# Does the test environment support metadata service? Ignored unless
+# validation.run_validation=true. (boolean value)
+#metadata_service = true
+
 # Does the test environment use block devices for live migration
 # (boolean value)
 #block_migration_for_live_migration = false
@@ -498,18 +504,29 @@
 # From tempest.config
 #
 
-# A regex to determine which requests should be traced.  This is a
-# regex to match the caller for rest client requests to be able to
+# A regex to determine which requests should be traced.
+#
+# This is a regex to match the caller for rest client requests to be
+# able to
 # selectively trace calls out of specific classes and methods. It
-# largely exists for test development, and is not expected to be used
-# in a real deploy of tempest. This will be matched against the
-# discovered ClassName:method in the test environment.  Expected
-# values for this field are:   * ClassName:test_method_name - traces
-# one test_method  * ClassName:setUp(Class) - traces specific setup
-# functions  * ClassName:tearDown(Class) - traces specific teardown
-# functions  * ClassName:_run_cleanups - traces the cleanup functions
+# largely
+# exists for test development, and is not expected to be used in a
+# real deploy
+# of tempest. This will be matched against the discovered
+# ClassName:method
+# in the test environment.
+#
+# Expected values for this field are:
+#
+#  * ClassName:test_method_name - traces one test_method
+#  * ClassName:setUp(Class) - traces specific setup functions
+#  * ClassName:tearDown(Class) - traces specific teardown functions
+#  * ClassName:_run_cleanups - traces the cleanup functions
+#
 # If nothing is specified, this feature is not enabled. To trace
-# everything specify .* as the regex.  (string value)
+# everything
+# specify .* as the regex.
+#  (string value)
 #trace_requests =
 
 
@@ -1098,6 +1115,16 @@
 #too_slow_to_test = true
 
 
+[telemetry-feature-enabled]
+
+#
+# From tempest.config
+#
+
+# Runs Ceilometer event-related tests (boolean value)
+#events = false
+
+
 [validation]
 
 #
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 45eaa97..9243fdf 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -31,7 +31,10 @@
         self.client.delete_keypair(keypair_name)
 
     def _create_keypair(self, keypair_name, pub_key=None):
-        body = self.client.create_keypair(keypair_name, pub_key)
+        kwargs = {'name': keypair_name}
+        if pub_key:
+            kwargs.update({'public_key': pub_key})
+        body = self.client.create_keypair(**kwargs)
         self.addCleanup(self._delete_keypair, keypair_name)
         return body
 
diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py
index 54b07f0..3e6d400 100644
--- a/tempest/api/compute/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/keypairs/test_keypairs_negative.py
@@ -29,7 +29,10 @@
         cls.client = cls.keypairs_client
 
     def _create_keypair(self, keypair_name, pub_key=None):
-        self.client.create_keypair(keypair_name, pub_key)
+        kwargs = {'name': keypair_name}
+        if pub_key:
+            kwargs.update({'public_key': pub_key})
+        self.client.create_keypair(**kwargs)
         self.addCleanup(self.client.delete_keypair, keypair_name)
 
     @test.attr(type=['negative'])
@@ -72,7 +75,7 @@
     def test_create_keypair_with_duplicate_name(self):
         # Keypairs with duplicate names should not be created
         k_name = data_utils.rand_name('keypair')
-        self.client.create_keypair(k_name)
+        self.client.create_keypair(name=k_name)
         # Now try the same keyname to create another key
         self.assertRaises(lib_exc.Conflict, self._create_keypair,
                           k_name)
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index 2c1e69c..c243adf 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -63,7 +63,7 @@
         # Specify a keypair while creating a server
 
         key_name = data_utils.rand_name('key')
-        self.keypairs_client.create_keypair(key_name)
+        self.keypairs_client.create_keypair(name=key_name)
         self.addCleanup(self.keypairs_client.delete_keypair, key_name)
         self.keypairs_client.list_keypairs()
         server = self.create_test_server(key_name=key_name)
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 8ee8ad4..7e2868e 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -78,7 +78,7 @@
         cls.image = cls.images_client.show_image(image_id)
 
         cls.keypairname = data_utils.rand_name('keypair')
-        cls.keypairs_client.create_keypair(cls.keypairname)
+        cls.keypairs_client.create_keypair(name=cls.keypairname)
 
         name = data_utils.rand_name('security')
         description = data_utils.rand_name('description')
@@ -209,7 +209,8 @@
             resp = {}
             resp['status'] = None
             self.assertRaises(lib_exc.BadRequest,
-                              self.alt_keypairs_client.create_keypair, k_name)
+                              self.alt_keypairs_client.create_keypair,
+                              name=k_name)
         finally:
             # Next request the base_url is back to normal
             if (resp['status'] is not None):
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index 266f726..6578680 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -96,7 +96,7 @@
     @classmethod
     def _create_keypair(cls, name_start='keypair-heat-'):
         kp_name = data_utils.rand_name(name_start)
-        body = cls.keypairs_client.create_keypair(kp_name)
+        body = cls.keypairs_client.create_keypair(name=kp_name)
         cls.keypairs.append(kp_name)
         return body
 
diff --git a/tempest/api/telemetry/base.py b/tempest/api/telemetry/base.py
index 3be807b..0f9b7dd 100644
--- a/tempest/api/telemetry/base.py
+++ b/tempest/api/telemetry/base.py
@@ -121,3 +121,27 @@
             'Sample for metric:%s with query:%s has not been added to the '
             'database within %d seconds' % (metric, query,
                                             CONF.compute.build_timeout))
+
+
+class BaseTelemetryAdminTest(BaseTelemetryTest):
+    """Base test case class for admin Telemetry API tests."""
+
+    credentials = ['primary', 'admin']
+
+    @classmethod
+    def setup_clients(cls):
+        super(BaseTelemetryAdminTest, cls).setup_clients()
+        cls.telemetry_admin_client = cls.os_adm.telemetry_client
+
+    def await_events(self, query):
+        timeout = CONF.compute.build_timeout
+        start = timeutils.utcnow()
+        while timeutils.delta_seconds(start, timeutils.utcnow()) < timeout:
+            body = self.telemetry_admin_client.list_events(query)
+            if body:
+                return body
+            time.sleep(CONF.compute.build_interval)
+
+        raise exceptions.TimeoutException(
+            'Event with query:%s has not been added to the '
+            'database within %d seconds' % (query, CONF.compute.build_timeout))
diff --git a/tempest/api/telemetry/test_telemetry_notification_api.py b/tempest/api/telemetry/test_telemetry_notification_api.py
index 52793c8..71a00c9 100644
--- a/tempest/api/telemetry/test_telemetry_notification_api.py
+++ b/tempest/api/telemetry/test_telemetry_notification_api.py
@@ -10,6 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest_lib import decorators
 import testtools
 
 from tempest.api.telemetry import base
@@ -29,8 +30,7 @@
                                     "is disabled")
 
     @test.idempotent_id('d7f8c1c8-d470-4731-8604-315d3956caad')
-    @testtools.skipIf(not CONF.service_available.nova,
-                      "Nova is not available.")
+    @test.services('compute')
     def test_check_nova_notification(self):
 
         body = self.create_server()
@@ -71,3 +71,28 @@
 
         for metric in self.glance_v2_notifications:
             self.await_samples(metric, query)
+
+
+class TelemetryNotificationAdminAPITestJSON(base.BaseTelemetryAdminTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(TelemetryNotificationAdminAPITestJSON, cls).skip_checks()
+        if CONF.telemetry.too_slow_to_test:
+            raise cls.skipException("Ceilometer feature for fast work mysql "
+                                    "is disabled")
+
+    @test.idempotent_id('29604198-8b45-4fc0-8af8-1cae4f94ebe9')
+    @test.services('compute')
+    @decorators.skip_because(bug='1480490')
+    def test_check_nova_notification_event_and_meter(self):
+
+        body = self.create_server()
+
+        if CONF.telemetry_feature_enabled.events:
+            query = ('instance_id', 'eq', body['id'])
+            self.await_events(query)
+
+        query = ('resource', 'eq', body['id'])
+        for metric in self.nova_notifications:
+            self.await_samples(metric, query)
diff --git a/tempest/clients.py b/tempest/clients.py
index 20cefbc..e32d401 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -42,9 +42,9 @@
 from tempest.services.compute.json.fixed_ips_client import FixedIPsClient
 from tempest.services.compute.json.flavors_client import FlavorsClient
 from tempest.services.compute.json.floating_ip_pools_client import \
-    FloatingIpPoolsClient
+    FloatingIPPoolsClient
 from tempest.services.compute.json.floating_ips_bulk_client import \
-    FloatingIpsBulkClient
+    FloatingIPsBulkClient
 from tempest.services.compute.json.floating_ips_client import \
     FloatingIPsClient
 from tempest.services.compute.json.hosts_client import HostsClient
@@ -282,9 +282,9 @@
         self.flavors_client = FlavorsClient(self.auth_provider, **params)
         self.extensions_client = ExtensionsClient(self.auth_provider,
                                                   **params)
-        self.floating_ip_pools_client = FloatingIpPoolsClient(
+        self.floating_ip_pools_client = FloatingIPPoolsClient(
             self.auth_provider, **params)
-        self.floating_ips_bulk_client = FloatingIpsBulkClient(
+        self.floating_ips_bulk_client = FloatingIPsBulkClient(
             self.auth_provider, **params)
         self.floating_ips_client = FloatingIPsClient(self.auth_provider,
                                                      **params)
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index dcdf7c5..2e96c81 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -76,12 +76,12 @@
                   CONF.identity.alt_username]
 
     if IS_NEUTRON:
-        CONF_PRIV_NETWORK = _get_priv_net_id(CONF.compute.fixed_network_name,
-                                             CONF.identity.tenant_name)
+        CONF_PRIV_NETWORK = _get_network_id(CONF.compute.fixed_network_name,
+                                            CONF.identity.tenant_name)
         CONF_NETWORKS = [CONF_PUB_NETWORK, CONF_PRIV_NETWORK]
 
 
-def _get_priv_net_id(prv_net_name, tenant_name):
+def _get_network_id(net_name, tenant_name):
     am = clients.AdminManager()
     net_cl = am.network_client
     id_cl = am.identity_client
@@ -91,7 +91,7 @@
     t_id = tenant['id']
     n_id = None
     for net in networks['networks']:
-        if (net['tenant_id'] == t_id and net['name'] == prv_net_name):
+        if (net['tenant_id'] == t_id and net['name'] == net_name):
             n_id = net['id']
             break
     return n_id
@@ -103,6 +103,10 @@
         for key, value in kwargs.items():
             setattr(self, key, value)
 
+        self.tenant_filter = {}
+        if hasattr(self, 'tenant_id'):
+            self.tenant_filter['tenant_id'] = self.tenant_id
+
     def _filter_by_tenant_id(self, item_list):
         if (item_list is None
                 or len(item_list) == 0
@@ -387,8 +391,8 @@
 
     def list(self):
         client = self.client
-        networks = client.list_networks()
-        networks = self._filter_by_tenant_id(networks['networks'])
+        networks = client.list_networks(**self.tenant_filter)
+        networks = networks['networks']
         # filter out networks declared in tempest.conf
         if self.is_preserve:
             networks = [network for network in networks
@@ -414,9 +418,8 @@
 
     def list(self):
         client = self.client
-        flips = client.list_floatingips()
+        flips = client.list_floatingips(**self.tenant_filter)
         flips = flips['floatingips']
-        flips = self._filter_by_tenant_id(flips)
         LOG.debug("List count, %s Network Floating IPs" % len(flips))
         return flips
 
@@ -438,9 +441,8 @@
 
     def list(self):
         client = self.client
-        routers = client.list_routers()
+        routers = client.list_routers(**self.tenant_filter)
         routers = routers['routers']
-        routers = self._filter_by_tenant_id(routers)
         if self.is_preserve:
             routers = [router for router in routers
                        if router['id'] != CONF_PUB_ROUTER]
@@ -454,11 +456,12 @@
         for router in routers:
             try:
                 rid = router['id']
-                ports = client.list_router_interfaces(rid)
-                ports = ports['ports']
+                ports = [port for port
+                         in client.list_router_interfaces(rid)['ports']
+                         if port["device_owner"] == "network:router_interface"]
                 for port in ports:
-                    subid = port['fixed_ips'][0]['subnet_id']
-                    client.remove_router_interface_with_subnet_id(rid, subid)
+                    client.remove_router_interface_with_port_id(rid,
+                                                                port['id'])
                 client.delete_router(rid)
             except Exception:
                 LOG.exception("Delete Router exception.")
@@ -616,11 +619,14 @@
 
     def list(self):
         client = self.client
-        ports = client.list_ports()
-        ports = ports['ports']
-        ports = self._filter_by_tenant_id(ports)
+        ports = [port for port in
+                 client.list_ports(**self.tenant_filter)['ports']
+                 if port["device_owner"] == "" or
+                 port["device_owner"].startswith("compute:")]
+
         if self.is_preserve:
             ports = self._filter_by_conf_networks(ports)
+
         LOG.debug("List count, %s Ports" % len(ports))
         return ports
 
@@ -638,13 +644,40 @@
         self.data['ports'] = ports
 
 
+class NetworkSecGroupService(NetworkService):
+    def list(self):
+        client = self.client
+        filter = self.tenant_filter
+        # cannot delete default sec group so never show it.
+        secgroups = [secgroup for secgroup in
+                     client.list_security_groups(**filter)['security_groups']
+                     if secgroup['name'] != 'default']
+
+        if self.is_preserve:
+            secgroups = self._filter_by_conf_networks(secgroups)
+        LOG.debug("List count, %s securtiy_groups" % len(secgroups))
+        return secgroups
+
+    def delete(self):
+        client = self.client
+        secgroups = self.list()
+        for secgroup in secgroups:
+            try:
+                client.delete_secgroup(secgroup['id'])
+            except Exception:
+                LOG.exception("Delete security_group exception.")
+
+    def dry_run(self):
+        secgroups = self.list()
+        self.data['secgroups'] = secgroups
+
+
 class NetworkSubnetService(NetworkService):
 
     def list(self):
         client = self.client
-        subnets = client.list_subnets()
+        subnets = client.list_subnets(**self.tenant_filter)
         subnets = subnets['subnets']
-        subnets = self._filter_by_tenant_id(subnets)
         if self.is_preserve:
             subnets = self._filter_by_conf_networks(subnets)
         LOG.debug("List count, %s Subnets" % len(subnets))
@@ -761,8 +794,8 @@
         self.data['images'] = images
 
     def save_state(self):
-        images = self.list()
         self.data['images'] = {}
+        images = self.list()
         for image in images:
             self.data['images'][image['id']] = image['name']
 
@@ -928,7 +961,6 @@
 
 def get_tenant_cleanup_services():
     tenant_services = []
-
     if IS_CEILOMETER:
         tenant_services.append(TelemetryAlarmService)
     if IS_NOVA:
@@ -942,14 +974,15 @@
     if IS_HEAT:
         tenant_services.append(StackService)
     if IS_NEUTRON:
+        tenant_services.append(NetworkFloatingIpService)
         if test.is_extension_enabled('metering', 'network'):
             tenant_services.append(NetworkMeteringLabelRuleService)
             tenant_services.append(NetworkMeteringLabelService)
         tenant_services.append(NetworkRouterService)
-        tenant_services.append(NetworkFloatingIpService)
         tenant_services.append(NetworkPortService)
         tenant_services.append(NetworkSubnetService)
         tenant_services.append(NetworkService)
+        tenant_services.append(NetworkSecGroupService)
     if IS_CINDER:
         tenant_services.append(SnapshotService)
         tenant_services.append(VolumeService)
diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py
index 18f0b1d..852ee54 100644
--- a/tempest/common/validation_resources.py
+++ b/tempest/common/validation_resources.py
@@ -46,7 +46,7 @@
         if validation_resources['keypair']:
             keypair_name = data_utils.rand_name('keypair')
             validation_data['keypair'] = \
-                os.keypairs_client.create_keypair(keypair_name)
+                os.keypairs_client.create_keypair(name=keypair_name)
             LOG.debug("Validation resource key %s created" % keypair_name)
         add_rule = False
         if validation_resources['security_group']:
diff --git a/tempest/config.py b/tempest/config.py
index 46f84ee..ab503e3 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -331,6 +331,10 @@
                 default=True,
                 help="Does the test environment support live migration "
                      "available?"),
+    cfg.BoolOpt('metadata_service',
+                default=True,
+                help="Does the test environment support metadata service? "
+                     "Ignored unless validation.run_validation=true."),
     cfg.BoolOpt('block_migration_for_live_migration',
                 default=False,
                 help="Does the test environment use block devices for live "
@@ -839,6 +843,16 @@
 ]
 
 
+telemetry_feature_group = cfg.OptGroup(name='telemetry-feature-enabled',
+                                       title='Enabled Ceilometer Features')
+
+TelemetryFeaturesGroup = [
+    cfg.BoolOpt('events',
+                default=False,
+                help="Runs Ceilometer event-related tests"),
+]
+
+
 dashboard_group = cfg.OptGroup(name="dashboard",
                                title="Dashboard options")
 
@@ -1179,6 +1193,7 @@
     (database_group, DatabaseGroup),
     (orchestration_group, OrchestrationGroup),
     (telemetry_group, TelemetryGroup),
+    (telemetry_feature_group, TelemetryFeaturesGroup),
     (dashboard_group, DashboardGroup),
     (data_processing_group, DataProcessingGroup),
     (data_processing_feature_group, DataProcessingFeaturesGroup),
@@ -1246,6 +1261,7 @@
         self.orchestration = _CONF.orchestration
         self.messaging = _CONF.messaging
         self.telemetry = _CONF.telemetry
+        self.telemetry_feature_enabled = _CONF['telemetry-feature-enabled']
         self.dashboard = _CONF.dashboard
         self.data_processing = _CONF.data_processing
         self.data_processing_feature_enabled = _CONF[
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index e77d07c..67052b0 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -140,7 +140,7 @@
             client = self.keypairs_client
         name = data_utils.rand_name(self.__class__.__name__)
         # We don't need to create a keypair by pubkey in scenario
-        body = client.create_keypair(name)
+        body = client.create_keypair(name=name)
         self.addCleanup(client.delete_keypair, name)
         return body
 
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index d9918f3..f61b151 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -37,6 +37,7 @@
      * Add simple permissive rules to the security group
      * Launch an instance
      * Perform ssh to instance
+     * Verify metadata service
      * Terminate the instance
     """
 
@@ -81,19 +82,26 @@
     def verify_ssh(self):
         if self.run_ssh:
             # Obtain a floating IP
-            floating_ip = self.floating_ips_client.create_floating_ip()
+            self.floating_ip = self.floating_ips_client.create_floating_ip()
             self.addCleanup(self.delete_wrapper,
                             self.floating_ips_client.delete_floating_ip,
-                            floating_ip['id'])
+                            self.floating_ip['id'])
             # Attach a floating IP
             self.floating_ips_client.associate_floating_ip_to_server(
-                floating_ip['ip'], self.instance['id'])
+                self.floating_ip['ip'], self.instance['id'])
             # Check ssh
-            self.get_remote_client(
-                server_or_ip=floating_ip['ip'],
+            self.ssh_client = self.get_remote_client(
+                server_or_ip=self.floating_ip['ip'],
                 username=self.image_utils.ssh_user(self.image_ref),
                 private_key=self.keypair['private_key'])
 
+    def verify_metadata(self):
+        if self.run_ssh and CONF.compute_feature_enabled.metadata_service:
+            # Verify metadata service
+            result = self.ssh_client.exec_command(
+                "curl http://169.254.169.254/latest/meta-data/public-ipv4")
+            self.assertEqual(self.floating_ip['ip'], result)
+
     @test.idempotent_id('7fff3fb3-91d8-4fd0-bd7d-0204f1f180ba')
     @test.attr(type='smoke')
     @test.services('compute', 'network')
@@ -102,4 +110,5 @@
         self.security_group = self._create_security_group()
         self.boot_instance()
         self.verify_ssh()
+        self.verify_metadata()
         self.servers_client.delete_server(self.instance['id'])
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 45b7b74..3809831 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -106,8 +106,7 @@
                 floating_ip['ip'], server['id'])
             ip = floating_ip['ip']
         else:
-            network_name_for_ssh = CONF.compute.network_for_ssh
-            ip = server.networks[network_name_for_ssh][0]
+            ip = server
 
         return self.get_remote_client(ip, private_key=keypair['private_key'],
                                       log_console_of_servers=[server])
diff --git a/tempest/services/compute/json/floating_ip_pools_client.py b/tempest/services/compute/json/floating_ip_pools_client.py
index 1cc411b..1e2133b 100644
--- a/tempest/services/compute/json/floating_ip_pools_client.py
+++ b/tempest/services/compute/json/floating_ip_pools_client.py
@@ -21,7 +21,7 @@
 from tempest.common import service_client
 
 
-class FloatingIpPoolsClient(service_client.ServiceClient):
+class FloatingIPPoolsClient(service_client.ServiceClient):
 
     def list_floating_ip_pools(self, params=None):
         """Returns a list of all floating IP Pools."""
diff --git a/tempest/services/compute/json/floating_ips_bulk_client.py b/tempest/services/compute/json/floating_ips_bulk_client.py
index c8e7350..8b1c5a9 100644
--- a/tempest/services/compute/json/floating_ips_bulk_client.py
+++ b/tempest/services/compute/json/floating_ips_bulk_client.py
@@ -19,7 +19,7 @@
 from tempest.common import service_client
 
 
-class FloatingIpsBulkClient(service_client.ServiceClient):
+class FloatingIPsBulkClient(service_client.ServiceClient):
 
     def create_floating_ips_bulk(self, ip_range, pool, interface):
         """Allocate floating IPs in bulk."""
diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py
index 6f819ae..e51671f 100644
--- a/tempest/services/compute/json/keypairs_client.py
+++ b/tempest/services/compute/json/keypairs_client.py
@@ -38,11 +38,8 @@
         self.validate_response(schema.get_keypair, resp, body)
         return service_client.ResponseBody(resp, body['keypair'])
 
-    def create_keypair(self, name, pub_key=None):
-        post_body = {'keypair': {'name': name}}
-        if pub_key:
-            post_body['keypair']['public_key'] = pub_key
-        post_body = json.dumps(post_body)
+    def create_keypair(self, **kwargs):
+        post_body = json.dumps({'keypair': kwargs})
         resp, body = self.post("os-keypairs", body=post_body)
         body = json.loads(body)
         self.validate_response(schema.create_keypair, resp, body)
diff --git a/tempest/services/telemetry/json/telemetry_client.py b/tempest/services/telemetry/json/telemetry_client.py
index 2b1cdc0..1f181e3 100644
--- a/tempest/services/telemetry/json/telemetry_client.py
+++ b/tempest/services/telemetry/json/telemetry_client.py
@@ -84,6 +84,10 @@
         uri = '%s/meters/%s' % (self.uri_prefix, meter_id)
         return self._helper_list(uri, query)
 
+    def list_events(self, query=None):
+        uri = '%s/events' % self.uri_prefix
+        return self._helper_list(uri, query)
+
     def show_resource(self, resource_id):
         uri = '%s/resources/%s' % (self.uri_prefix, resource_id)
         resp, body = self.get(uri)
diff --git a/tempest/stress/actions/volume_attach_verify.py b/tempest/stress/actions/volume_attach_verify.py
index 3ba2a91..c48ad4b 100644
--- a/tempest/stress/actions/volume_attach_verify.py
+++ b/tempest/stress/actions/volume_attach_verify.py
@@ -26,7 +26,7 @@
 
     def _create_keypair(self):
         keyname = data_utils.rand_name("key")
-        self.key = self.manager.keypairs_client.create_keypair(keyname)
+        self.key = self.manager.keypairs_client.create_keypair(name=keyname)
 
     def _delete_keypair(self):
         self.manager.keypairs_client.delete_keypair(self.key['name'])
diff --git a/tempest/tests/common/test_service_clients.py b/tempest/tests/common/test_service_clients.py
index 3a0873c..00b8470 100644
--- a/tempest/tests/common/test_service_clients.py
+++ b/tempest/tests/common/test_service_clients.py
@@ -116,8 +116,8 @@
             extensions_client.ExtensionsClient,
             fixed_ips_client.FixedIPsClient,
             flavors_client.FlavorsClient,
-            floating_ip_pools_client.FloatingIpPoolsClient,
-            floating_ips_bulk_client.FloatingIpsBulkClient,
+            floating_ip_pools_client.FloatingIPPoolsClient,
+            floating_ips_bulk_client.FloatingIPsBulkClient,
             floating_ips_client.FloatingIPsClient,
             hosts_client.HostsClient,
             hypervisor_client.HypervisorClient,