Fixes test_metrics test
Ceilometer API was removed in Queens, meaning that test_metrics has not way to validate the metrics collected by the ceilometer-polling agent. The metrics are instead sent and collected by Gnocchi. This patch adds a Gnocchi client, and updates the test_metrics to use this client properly. Change-Id: Id999d758505de10abb356befb854736e1904f6ee
This commit is contained in:
parent
13506c22a8
commit
dac28d1334
@ -79,7 +79,7 @@ HyperVGroup = [
|
|||||||
"published by the compute node's ceilometer-polling "
|
"published by the compute node's ceilometer-polling "
|
||||||
"agent. The value must be greater by ~15-20 seconds "
|
"agent. The value must be greater by ~15-20 seconds "
|
||||||
"than the agent's publish interval, defined in its "
|
"than the agent's publish interval, defined in its "
|
||||||
"pipeline.yaml file (typically, the intervals are 600 "
|
"polling.yaml file (typically, the intervals are 600 "
|
||||||
"seconds)."),
|
"seconds)."),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -51,3 +51,15 @@ class OSWinTempestPlugin(plugins.TempestPlugin):
|
|||||||
"""
|
"""
|
||||||
return [(group.name, opts)
|
return [(group.name, opts)
|
||||||
for group, opts in project_config.list_opts()]
|
for group, opts in project_config.list_opts()]
|
||||||
|
|
||||||
|
def get_service_clients(self):
|
||||||
|
metric_config = config.service_client_config('metric')
|
||||||
|
metric_v1_params = {
|
||||||
|
'name': 'metric_v1',
|
||||||
|
'service_version': 'metric.v1',
|
||||||
|
'module_path': 'oswin_tempest_plugin.services.gnocchi_client',
|
||||||
|
'client_names': ['GnocchiClient'],
|
||||||
|
}
|
||||||
|
metric_v1_params.update(metric_config)
|
||||||
|
|
||||||
|
return [metric_v1_params]
|
||||||
|
0
oswin_tempest_plugin/services/__init__.py
Normal file
0
oswin_tempest_plugin/services/__init__.py
Normal file
50
oswin_tempest_plugin/services/gnocchi_client.py
Normal file
50
oswin_tempest_plugin/services/gnocchi_client.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# Copyright 2018 Cloudbase Solutions Srl
|
||||||
|
#
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from oslo_serialization import jsonutils as json
|
||||||
|
from tempest.lib.common import rest_client
|
||||||
|
|
||||||
|
from oswin_tempest_plugin import config
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class GnocchiClient(rest_client.RestClient):
|
||||||
|
|
||||||
|
uri_prefix = 'v1'
|
||||||
|
|
||||||
|
def deserialize(self, body):
|
||||||
|
return json.loads(body.replace("\n", ""))
|
||||||
|
|
||||||
|
def _helper_list(self, uri):
|
||||||
|
resp, body = self.get(uri)
|
||||||
|
self.expected_success(200, resp.status)
|
||||||
|
body = self.deserialize(body)
|
||||||
|
return rest_client.ResponseBodyList(resp, body)
|
||||||
|
|
||||||
|
def list_resources(self):
|
||||||
|
uri = '%s/resource/generic' % self.uri_prefix
|
||||||
|
return self._helper_list(uri)
|
||||||
|
|
||||||
|
def list_samples(self, resource_id, meter_name):
|
||||||
|
"""Returns a list of samples for the given resource and meter.
|
||||||
|
|
||||||
|
:returns: list, each item being a list containing the following values
|
||||||
|
in this order: timestamp, granularity, value.
|
||||||
|
"""
|
||||||
|
uri = '%s/resource/generic/%s/metric/%s/measures' % (
|
||||||
|
self.uri_prefix, resource_id, meter_name)
|
||||||
|
return self._helper_list(uri)
|
@ -15,12 +15,6 @@
|
|||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
try:
|
|
||||||
# NOTE(claudiub): ceilometer might not be installed, it is not mandatory.
|
|
||||||
from ceilometer.tests.tempest.service import client as telemetry_client
|
|
||||||
except Exception:
|
|
||||||
telemetry_client = None
|
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from tempest import clients
|
from tempest import clients
|
||||||
|
|
||||||
@ -36,11 +30,10 @@ class ClientManager(clients.Manager):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ClientManager, self).__init__(*args, **kwargs)
|
super(ClientManager, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
self._set_telemetry_clients()
|
self.set_gnocchi_client()
|
||||||
|
|
||||||
def _set_telemetry_clients(self):
|
def set_gnocchi_client(self):
|
||||||
self.telemetry_client = telemetry_client.TelemetryClient(
|
self.gnocchi_client = self.metric_v1.GnocchiClient()
|
||||||
self.auth_provider, **telemetry_client.Manager.telemetry_params)
|
|
||||||
|
|
||||||
|
|
||||||
class MetricsCollectionTestCase(test_base.TestBase):
|
class MetricsCollectionTestCase(test_base.TestBase):
|
||||||
@ -65,7 +58,7 @@ class MetricsCollectionTestCase(test_base.TestBase):
|
|||||||
a. Configure tempest's polled_metric_delay, by adding the
|
a. Configure tempest's polled_metric_delay, by adding the
|
||||||
following line in tempest.conf, in the hyperv section:
|
following line in tempest.conf, in the hyperv section:
|
||||||
polled_metrics_delay = <desired value>
|
polled_metrics_delay = <desired value>
|
||||||
b. Set the interval value in pipeline.yaml on the compute node to
|
b. Set the interval value in polling.yaml on the compute node to
|
||||||
the desired value and restart the ceilometer polling agent. The
|
the desired value and restart the ceilometer polling agent. The
|
||||||
interval value is set either for the 'meter_source' or for each
|
interval value is set either for the 'meter_source' or for each
|
||||||
of the following: 'cpu_source', 'disk_source', 'network_source'.
|
of the following: 'cpu_source', 'disk_source', 'network_source'.
|
||||||
@ -73,7 +66,7 @@ class MetricsCollectionTestCase(test_base.TestBase):
|
|||||||
Note: If the polled_metrics_delay value is too low, the tests might not
|
Note: If the polled_metrics_delay value is too low, the tests might not
|
||||||
find any samples and fail because of this. As a recommandation,
|
find any samples and fail because of this. As a recommandation,
|
||||||
polled_metrics_delay's value should be:
|
polled_metrics_delay's value should be:
|
||||||
polled_metric_delay = <pipeline.yaml interval value> + <15-20 seconds>
|
polled_metric_delay = <polling.yaml interval value> + <15-20 seconds>
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
1. test_metrics - tests values for the following metrics:
|
1. test_metrics - tests values for the following metrics:
|
||||||
@ -84,7 +77,7 @@ class MetricsCollectionTestCase(test_base.TestBase):
|
|||||||
assumptions:
|
assumptions:
|
||||||
1. Ceilometer agent on the compute node is running.
|
1. Ceilometer agent on the compute node is running.
|
||||||
2. Ceilometer agent on the compute node has the polling interval
|
2. Ceilometer agent on the compute node has the polling interval
|
||||||
defined in pipeline.yaml lower than the polled_metrics_delay defined
|
defined in polling.yaml lower than the polled_metrics_delay defined
|
||||||
in this test suite.
|
in this test suite.
|
||||||
3. The compute nodes' nova-compute and neutron-hyperv-agent services
|
3. The compute nodes' nova-compute and neutron-hyperv-agent services
|
||||||
have been configured to enable metrics collection.
|
have been configured to enable metrics collection.
|
||||||
@ -96,9 +89,9 @@ class MetricsCollectionTestCase(test_base.TestBase):
|
|||||||
def skip_checks(cls):
|
def skip_checks(cls):
|
||||||
super(MetricsCollectionTestCase, cls).skip_checks()
|
super(MetricsCollectionTestCase, cls).skip_checks()
|
||||||
|
|
||||||
if (not CONF.service_available.ceilometer or
|
for service in ['ceilometer', 'gnocchi']:
|
||||||
not CONF.telemetry.deprecated_api_enabled):
|
if not getattr(CONF.service_available, service):
|
||||||
raise cls.skipException("Ceilometer API support is required.")
|
raise cls.skipException("%s service is required." % service)
|
||||||
|
|
||||||
if not CONF.hyperv.collected_metrics:
|
if not CONF.hyperv.collected_metrics:
|
||||||
raise cls.skipException("Collected metrics not configured.")
|
raise cls.skipException("Collected metrics not configured.")
|
||||||
@ -108,26 +101,20 @@ class MetricsCollectionTestCase(test_base.TestBase):
|
|||||||
super(MetricsCollectionTestCase, cls).setup_clients()
|
super(MetricsCollectionTestCase, cls).setup_clients()
|
||||||
|
|
||||||
# Telemetry client
|
# Telemetry client
|
||||||
cls.telemetry_client = cls.os_primary.telemetry_client
|
cls.telemetry_client = cls.os_primary.gnocchi_client
|
||||||
|
|
||||||
def _telemetry_check_samples(self, resource_id, meter_name):
|
def _check_samples(self, resource_id, meter_name):
|
||||||
LOG.info("Checking %(meter_name)s for resource %(resource_id)s" % {
|
LOG.info("Checking %(meter_name)s for resource %(resource_id)s" % {
|
||||||
'meter_name': meter_name, 'resource_id': resource_id})
|
'meter_name': meter_name, 'resource_id': resource_id})
|
||||||
|
|
||||||
samples = self.telemetry_client.list_samples(meter_name)
|
samples = self.telemetry_client.list_samples(resource_id, meter_name)
|
||||||
self.assertNotEmpty(samples,
|
|
||||||
'Telemetry client returned no samples.')
|
|
||||||
|
|
||||||
resource_samples = [s for s in samples if
|
|
||||||
s['resource_id'] == resource_id]
|
|
||||||
self.assertNotEmpty(
|
self.assertNotEmpty(
|
||||||
resource_samples,
|
samples,
|
||||||
'No meter %(meter_name)s samples for resource '
|
'Client returned no samples for the given resource '
|
||||||
'%(resource_id)s found.' % {'meter_name': meter_name,
|
'"%(resource_id)s" and meter "%(meter_name)s".' % {
|
||||||
'resource_id': resource_id})
|
'resource_id': resource_id, 'meter_name': meter_name})
|
||||||
|
|
||||||
non_zero_valued_samples = [s for s in resource_samples if
|
non_zero_valued_samples = [s for s in samples if s[2] > 0]
|
||||||
s['counter_volume'] > 0]
|
|
||||||
self.assertNotEmpty(
|
self.assertNotEmpty(
|
||||||
non_zero_valued_samples,
|
non_zero_valued_samples,
|
||||||
'All meter %(meter_name)s samples for resource '
|
'All meter %(meter_name)s samples for resource '
|
||||||
@ -145,12 +132,12 @@ class MetricsCollectionTestCase(test_base.TestBase):
|
|||||||
# %(OS-EXT-SRV-ATTR:instance_name)s-%(instance_id)s-%(port_id)s
|
# %(OS-EXT-SRV-ATTR:instance_name)s-%(instance_id)s-%(port_id)s
|
||||||
# the instance returned by self.servers_client does not contain the
|
# the instance returned by self.servers_client does not contain the
|
||||||
# OS-EXT-SRV-ATTR:instance_name field. Which means that the resource_id
|
# OS-EXT-SRV-ATTR:instance_name field. Which means that the resource_id
|
||||||
# must be found in ceilometer's resources.
|
# must be found in gnocchi's resources.
|
||||||
start_res_id = server['id']
|
start_res_id = server['id']
|
||||||
resources = self.telemetry_client.list_resources()
|
resources = self.telemetry_client.list_resources()
|
||||||
res_ids = [r['resource_id'] for r in resources
|
res_ids = [r['id'] for r in resources
|
||||||
if r['resource_id'].startswith('instance-') and
|
if r['original_resource_id'].startswith('instance-') and
|
||||||
start_res_id in r['resource_id']]
|
start_res_id in r['original_resource_id']]
|
||||||
|
|
||||||
self.assertEqual(1, len(res_ids))
|
self.assertEqual(1, len(res_ids))
|
||||||
return res_ids[0]
|
return res_ids[0]
|
||||||
@ -162,19 +149,17 @@ class MetricsCollectionTestCase(test_base.TestBase):
|
|||||||
time.sleep(CONF.hyperv.polled_metrics_delay)
|
time.sleep(CONF.hyperv.polled_metrics_delay)
|
||||||
|
|
||||||
# TODO(claudiub): Add more metrics.
|
# TODO(claudiub): Add more metrics.
|
||||||
|
|
||||||
if 'cpu' in CONF.hyperv.collected_metrics:
|
if 'cpu' in CONF.hyperv.collected_metrics:
|
||||||
cpu_res_id = self._get_instance_cpu_resource_id(server)
|
cpu_res_id = self._get_instance_cpu_resource_id(server)
|
||||||
self._telemetry_check_samples(cpu_res_id, 'cpu')
|
self._check_samples(cpu_res_id, 'cpu')
|
||||||
|
|
||||||
if 'network.outgoing.bytes' in CONF.hyperv.collected_metrics:
|
if 'network.outgoing.bytes' in CONF.hyperv.collected_metrics:
|
||||||
port_res_id = self._get_instance_port_resource_id(server)
|
port_res_id = self._get_instance_port_resource_id(server)
|
||||||
self._telemetry_check_samples(port_res_id,
|
self._check_samples(port_res_id, 'network.outgoing.bytes')
|
||||||
'network.outgoing.bytes')
|
|
||||||
|
|
||||||
if 'disk.read.bytes' in CONF.hyperv.collected_metrics:
|
if 'disk.read.bytes' in CONF.hyperv.collected_metrics:
|
||||||
disk_resource_id = self._get_instance_disk_resource_id(server)
|
disk_resource_id = self._get_instance_disk_resource_id(server)
|
||||||
self._telemetry_check_samples(disk_resource_id, 'disk.read.bytes')
|
self._check_samples(disk_resource_id, 'disk.read.bytes')
|
||||||
|
|
||||||
def test_metrics(self):
|
def test_metrics(self):
|
||||||
server_tuple = self._create_server()
|
server_tuple = self._create_server()
|
||||||
|
Loading…
Reference in New Issue
Block a user