summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2017-11-21 11:13:55 +0000
committerGerrit Code Review <review@openstack.org>2017-11-21 11:13:55 +0000
commitf1f2f8c29ada82f9aba37be8eebf4011904fa508 (patch)
tree63e793b99c72b8d6a4a779ebeec57320da7d5fcc
parent3b340a54d426acd0ded516c8d4f08d66fed9d4a9 (diff)
parentbce179882a3c5329290aac359aeb8278c3e8a8e3 (diff)
Merge "Adds metrics collection scenario"
-rw-r--r--oswin_tempest_plugin/config.py20
-rw-r--r--oswin_tempest_plugin/tests/_mixins/migrate.py4
-rw-r--r--oswin_tempest_plugin/tests/_mixins/optional_feature.py2
-rw-r--r--oswin_tempest_plugin/tests/_mixins/resize.py2
-rw-r--r--oswin_tempest_plugin/tests/scenario/test_cluster.py2
-rw-r--r--oswin_tempest_plugin/tests/scenario/test_disks.py2
-rw-r--r--oswin_tempest_plugin/tests/scenario/test_metrics_collection.py181
-rw-r--r--oswin_tempest_plugin/tests/test_base.py7
8 files changed, 214 insertions, 6 deletions
diff --git a/oswin_tempest_plugin/config.py b/oswin_tempest_plugin/config.py
index 082147f..4782a13 100644
--- a/oswin_tempest_plugin/config.py
+++ b/oswin_tempest_plugin/config.py
@@ -14,6 +14,7 @@
14# under the License. 14# under the License.
15 15
16from oslo_config import cfg 16from oslo_config import cfg
17from oslo_config import types
17from tempest import config 18from tempest import config
18 19
19CONF = config.CONF 20CONF = config.CONF
@@ -61,6 +62,25 @@ HyperVGroup = [
61 help="The maximum number of NUMA cells the compute nodes " 62 help="The maximum number of NUMA cells the compute nodes "
62 "have. If it's less than 2, resize negative tests for " 63 "have. If it's less than 2, resize negative tests for "
63 "vNUMA will be skipped."), 64 "vNUMA will be skipped."),
65 cfg.ListOpt('collected_metrics',
66 item_type=types.String(
67 choices=('cpu', 'network.outgoing.bytes',
68 'disk.read.bytes')),
69 default=[],
70 help="The ceilometer metrics to check. If this config value "
71 "is empty, the telemetry tests are skipped. This config "
72 "option assumes that the compute nodes are configured "
73 "and capable of collecting ceilometer metrics. WARNING: "
74 "neutron-ovs-agent is not capable of enabling network "
75 "metrics collection."),
76 cfg.IntOpt('polled_metrics_delay',
77 default=620,
78 help="The number of seconds to wait for the metrics to be "
79 "published by the compute node's ceilometer-polling "
80 "agent. The value must be greater by ~15-20 seconds "
81 "than the agent's publish interval, defined in its "
82 "pipeline.yaml file (typically, the intervals are 600 "
83 "seconds)."),
64] 84]
65 85
66hyperv_host_auth_group = cfg.OptGroup(name='hyperv_host_auth', 86hyperv_host_auth_group = cfg.OptGroup(name='hyperv_host_auth',
diff --git a/oswin_tempest_plugin/tests/_mixins/migrate.py b/oswin_tempest_plugin/tests/_mixins/migrate.py
index 9dad6e1..d5135c2 100644
--- a/oswin_tempest_plugin/tests/_mixins/migrate.py
+++ b/oswin_tempest_plugin/tests/_mixins/migrate.py
@@ -43,7 +43,7 @@ class _MigrateMixin(object):
43 def test_migration(self): 43 def test_migration(self):
44 server_tuple = self._create_server() 44 server_tuple = self._create_server()
45 self._migrate_server(server_tuple) 45 self._migrate_server(server_tuple)
46 self._check_server_connectivity(server_tuple) 46 self._check_scenario(server_tuple)
47 47
48 48
49class _LiveMigrateMixin(object): 49class _LiveMigrateMixin(object):
@@ -104,4 +104,4 @@ class _LiveMigrateMixin(object):
104 def test_live_migration(self): 104 def test_live_migration(self):
105 server_tuple = self._create_server() 105 server_tuple = self._create_server()
106 self._live_migrate_server(server_tuple) 106 self._live_migrate_server(server_tuple)
107 self._check_server_connectivity(server_tuple) 107 self._check_scenario(server_tuple)
diff --git a/oswin_tempest_plugin/tests/_mixins/optional_feature.py b/oswin_tempest_plugin/tests/_mixins/optional_feature.py
index 11651ee..7ae1ea4 100644
--- a/oswin_tempest_plugin/tests/_mixins/optional_feature.py
+++ b/oswin_tempest_plugin/tests/_mixins/optional_feature.py
@@ -71,7 +71,7 @@ class _OptionalFeatureMixin(resize._ResizeUtils):
71 71
72 def test_feature(self): 72 def test_feature(self):
73 server_tuple = self._create_server() 73 server_tuple = self._create_server()
74 self._check_server_connectivity(server_tuple) 74 self._check_scenario(server_tuple)
75 75
76 @testtools.skipUnless(CONF.compute_feature_enabled.resize, 76 @testtools.skipUnless(CONF.compute_feature_enabled.resize,
77 'Resize is not available.') 77 'Resize is not available.')
diff --git a/oswin_tempest_plugin/tests/_mixins/resize.py b/oswin_tempest_plugin/tests/_mixins/resize.py
index d8f16cb..b4c4b91 100644
--- a/oswin_tempest_plugin/tests/_mixins/resize.py
+++ b/oswin_tempest_plugin/tests/_mixins/resize.py
@@ -77,7 +77,7 @@ class _ResizeUtils(object):
77 77
78 # assert that the server is still reachable, even if the resize 78 # assert that the server is still reachable, even if the resize
79 # failed. 79 # failed.
80 self._check_server_connectivity(server_tuple) 80 self._check_scenario(server_tuple)
81 81
82 82
83class _ResizeMixin(_ResizeUtils): 83class _ResizeMixin(_ResizeUtils):
diff --git a/oswin_tempest_plugin/tests/scenario/test_cluster.py b/oswin_tempest_plugin/tests/scenario/test_cluster.py
index c6e10be..fd3022a 100644
--- a/oswin_tempest_plugin/tests/scenario/test_cluster.py
+++ b/oswin_tempest_plugin/tests/scenario/test_cluster.py
@@ -150,4 +150,4 @@ class HyperVClusterTest(migrate._MigrateMixin,
150 150
151 def test_clustered_vm(self): 151 def test_clustered_vm(self):
152 server_tuple = self._create_server() 152 server_tuple = self._create_server()
153 self._check_server_connectivity(server_tuple) 153 self._check_scenario(server_tuple)
diff --git a/oswin_tempest_plugin/tests/scenario/test_disks.py b/oswin_tempest_plugin/tests/scenario/test_disks.py
index d78b992..cd44ade 100644
--- a/oswin_tempest_plugin/tests/scenario/test_disks.py
+++ b/oswin_tempest_plugin/tests/scenario/test_disks.py
@@ -49,7 +49,7 @@ class _BaseDiskTestMixin(migrate._MigrateMixin,
49 49
50 def test_disk(self): 50 def test_disk(self):
51 server_tuple = self._create_server() 51 server_tuple = self._create_server()
52 self._check_server_connectivity(server_tuple) 52 self._check_scenario(server_tuple)
53 53
54 @testtools.skipUnless(CONF.compute_feature_enabled.resize, 54 @testtools.skipUnless(CONF.compute_feature_enabled.resize,
55 'Resize is not available.') 55 'Resize is not available.')
diff --git a/oswin_tempest_plugin/tests/scenario/test_metrics_collection.py b/oswin_tempest_plugin/tests/scenario/test_metrics_collection.py
new file mode 100644
index 0000000..1375388
--- /dev/null
+++ b/oswin_tempest_plugin/tests/scenario/test_metrics_collection.py
@@ -0,0 +1,181 @@
1# Copyright 2017 Cloudbase Solutions
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import time
17
18try:
19 # NOTE(claudiub): ceilometer might not be installed, it is not mandatory.
20 from ceilometer.tests.tempest.service import client as telemetry_client
21except Exception:
22 telemetry_client = None
23
24from oslo_log import log as logging
25from tempest import clients
26
27from oswin_tempest_plugin import config
28from oswin_tempest_plugin.tests import test_base
29
30CONF = config.CONF
31LOG = logging.getLogger(__name__)
32
33
34class ClientManager(clients.Manager):
35
36 def __init__(self, *args, **kwargs):
37 super(ClientManager, self).__init__(*args, **kwargs)
38
39 self._set_telemetry_clients()
40
41 def _set_telemetry_clients(self):
42 self.telemetry_client = telemetry_client.TelemetryClient(
43 self.auth_provider, **telemetry_client.Manager.telemetry_params)
44
45
46class MetricsCollectionTestCase(test_base.TestBase):
47 """Adds metrics collection scenario tests.
48
49 This test suite verifies that the instance metrics are properly published
50 and collected and have non-zero values. The verification is done via the
51 ceilometer API.
52
53 setup:
54 1. spins a new instance.
55 2. waits until the instance was created succesfully (ACTIVE status).
56 3. wait an interval of time which represents the polling period of the
57 ceilometer-polling agent.
58
59 Waiting for the ceilometer-polling agent to poll the resources is crucial,
60 otherwise the test suite will fail due to the fact that no samples
61 would be found published before checking the samples.
62
63 The test suite's polled_metrics_delay must have a greater value than the
64 ceilometer agent's polling interval. This can be done in two ways:
65 a. Configure tempest's polled_metric_delay, by adding the
66 following line in tempest.conf, in the hyperv section:
67 polled_metrics_delay = <desired value>
68 b. Set the interval value in pipeline.yaml on the compute node to
69 the desired value and restart the ceilometer polling agent. The
70 interval value is set either for the 'meter_source' or for each
71 of the following: 'cpu_source', 'disk_source', 'network_source'.
72
73 Note: If the polled_metrics_delay value is too low, the tests might not
74 find any samples and fail because of this. As a recommandation,
75 polled_metrics_delay's value should be:
76 polled_metric_delay = <pipeline.yaml interval value> + <15-20 seconds>
77
78 tests:
79 1. test_metrics - tests values for the following metrics:
80 - cpu
81 - network.outgoing.bytes
82 - disk.read.bytes
83
84 assumptions:
85 1. Ceilometer agent on the compute node is running.
86 2. Ceilometer agent on the compute node has the polling interval
87 defined in pipeline.yaml lower than the polled_metrics_delay defined
88 in this test suite.
89 3. The compute nodes' nova-compute and neutron-hyperv-agent services
90 have been configured to enable metrics collection.
91 """
92
93 client_manager = ClientManager
94
95 @classmethod
96 def skip_checks(cls):
97 super(MetricsCollectionTestCase, cls).skip_checks()
98
99 if (not CONF.service_available.ceilometer or
100 not CONF.telemetry.deprecated_api_enabled):
101 raise cls.skipException("Ceilometer API support is required.")
102
103 if not CONF.hyperv.collected_metrics:
104 raise cls.skipException("Collected metrics not configured.")
105
106 @classmethod
107 def setup_clients(cls):
108 super(MetricsCollectionTestCase, cls).setup_clients()
109
110 # Telemetry client
111 cls.telemetry_client = cls.os_primary.telemetry_client
112
113 def _telemetry_check_samples(self, resource_id, meter_name):
114 LOG.info("Checking %(meter_name)s for resource %(resource_id)s" % {
115 'meter_name': meter_name, 'resource_id': resource_id})
116
117 samples = self.telemetry_client.list_samples(meter_name)
118 self.assertNotEmpty(samples,
119 'Telemetry client returned no samples.')
120
121 resource_samples = [s for s in samples if
122 s['resource_id'] == resource_id]
123 self.assertNotEmpty(
124 resource_samples,
125 'No meter %(meter_name)s samples for resource '
126 '%(resource_id)s found.' % {'meter_name': meter_name,
127 'resource_id': resource_id})
128
129 non_zero_valued_samples = [s for s in resource_samples if
130 s['counter_volume'] > 0]
131 self.assertNotEmpty(
132 non_zero_valued_samples,
133 'All meter %(meter_name)s samples for resource '
134 '%(resource_id)s are 0.' % {'meter_name': meter_name,
135 'resource_id': resource_id})
136
137 def _get_instance_cpu_resource_id(self, server):
138 return server['id']
139
140 def _get_instance_disk_resource_id(self, server):
141 return server['id']
142
143 def _get_instance_port_resource_id(self, server):
144 # Note(claudiub): the format for the instance_port_resource_id is:
145 # %(OS-EXT-SRV-ATTR:instance_name)s-%(instance_id)s-%(port_id)s
146 # the instance returned by self.servers_client does not contain the
147 # OS-EXT-SRV-ATTR:instance_name field. Which means that the resource_id
148 # must be found in ceilometer's resources.
149 start_res_id = server['id']
150 resources = self.telemetry_client.list_resources()
151 res_ids = [r['resource_id'] for r in resources
152 if r['resource_id'].startswith('instance-') and
153 start_res_id in r['resource_id']]
154
155 self.assertEqual(1, len(res_ids))
156 return res_ids[0]
157
158 def _check_scenario(self, server_tuple):
159 server = server_tuple.server
160 LOG.info("Waiting %s seconds for the ceilometer compute agents to "
161 "publish the samples.", CONF.hyperv.polled_metrics_delay)
162 time.sleep(CONF.hyperv.polled_metrics_delay)
163
164 # TODO(claudiub): Add more metrics.
165
166 if 'cpu' in CONF.hyperv.collected_metrics:
167 cpu_res_id = self._get_instance_cpu_resource_id(server)
168 self._telemetry_check_samples(cpu_res_id, 'cpu')
169
170 if 'network.outgoing.bytes' in CONF.hyperv.collected_metrics:
171 port_res_id = self._get_instance_port_resource_id(server)
172 self._telemetry_check_samples(port_res_id,
173 'network.outgoing.bytes')
174
175 if 'disk.read.bytes' in CONF.hyperv.collected_metrics:
176 disk_resource_id = self._get_instance_disk_resource_id(server)
177 self._telemetry_check_samples(disk_resource_id, 'disk.read.bytes')
178
179 def test_metrics(self):
180 server_tuple = self._create_server()
181 self._check_scenario(server_tuple)
diff --git a/oswin_tempest_plugin/tests/test_base.py b/oswin_tempest_plugin/tests/test_base.py
index 7999742..87ccfce 100644
--- a/oswin_tempest_plugin/tests/test_base.py
+++ b/oswin_tempest_plugin/tests/test_base.py
@@ -284,3 +284,10 @@ class TestBase(tempest.test.BaseTestCase):
284 def _check_server_connectivity(self, server_tuple): 284 def _check_server_connectivity(self, server_tuple):
285 # if server connectivity works, an SSH client can be opened. 285 # if server connectivity works, an SSH client can be opened.
286 self._get_server_client(server_tuple) 286 self._get_server_client(server_tuple)
287
288 def _check_scenario(self, server_tuple):
289 # NOTE(claudiub): This method is to be used when verifying a
290 # particular scenario. If a scenario test case needs to perform
291 # different validation steps (e.g.: metrics collection), it should
292 # overwrite this method.
293 self._check_server_connectivity(server_tuple)