Browse Source

Adds metrics collection scenario

This test suite verifies that the instance metrics are properly published
and collected and have non-zero values. The verification is done via the
ceilometer API.

Waiting for the ceilometer compute agent to poll the resources is crucial,
otherwise the test suite will fail due to the fact that no samples would
be found published before checking the samples.

The ceilometer agent's polling interval should have the same value as
the test suite's polled_metric_delay. This can be done in two ways:
a. Configure tempest's polled_metric_delay, by adding the following
line in tempest.conf, in the telemetry section:
    polled_metric_delay = <desired value>
b. Set the interval value in pipeline.yaml on the compute node to the
desired value and restart the ceilometer compute agent.

The second method is preferred, as the interval value defined in
pipeline.yaml is 600 seconds, which would mean each test would last
at least 10 minutes.

Change-Id: I2ad696c221fba860a30621686b464b8486bea583
tags/0.1.0
Claudiu Belu 1 year ago
parent
commit
bce179882a

+ 20
- 0
oswin_tempest_plugin/config.py View File

@@ -14,6 +14,7 @@
14 14
 #    under the License.
15 15
 
16 16
 from oslo_config import cfg
17
+from oslo_config import types
17 18
 from tempest import config
18 19
 
19 20
 CONF = config.CONF
@@ -61,6 +62,25 @@ HyperVGroup = [
61 62
                help="The maximum number of NUMA cells the compute nodes "
62 63
                     "have. If it's less than 2, resize negative tests for "
63 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
 
66 86
 hyperv_host_auth_group = cfg.OptGroup(name='hyperv_host_auth',

+ 2
- 2
oswin_tempest_plugin/tests/_mixins/migrate.py View File

@@ -43,7 +43,7 @@ class _MigrateMixin(object):
43 43
     def test_migration(self):
44 44
         server_tuple = self._create_server()
45 45
         self._migrate_server(server_tuple)
46
-        self._check_server_connectivity(server_tuple)
46
+        self._check_scenario(server_tuple)
47 47
 
48 48
 
49 49
 class _LiveMigrateMixin(object):
@@ -104,4 +104,4 @@ class _LiveMigrateMixin(object):
104 104
     def test_live_migration(self):
105 105
         server_tuple = self._create_server()
106 106
         self._live_migrate_server(server_tuple)
107
-        self._check_server_connectivity(server_tuple)
107
+        self._check_scenario(server_tuple)

+ 1
- 1
oswin_tempest_plugin/tests/_mixins/optional_feature.py View File

@@ -71,7 +71,7 @@ class _OptionalFeatureMixin(resize._ResizeUtils):
71 71
 
72 72
     def test_feature(self):
73 73
         server_tuple = self._create_server()
74
-        self._check_server_connectivity(server_tuple)
74
+        self._check_scenario(server_tuple)
75 75
 
76 76
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
77 77
                           'Resize is not available.')

+ 1
- 1
oswin_tempest_plugin/tests/_mixins/resize.py View File

@@ -77,7 +77,7 @@ class _ResizeUtils(object):
77 77
 
78 78
         # assert that the server is still reachable, even if the resize
79 79
         # failed.
80
-        self._check_server_connectivity(server_tuple)
80
+        self._check_scenario(server_tuple)
81 81
 
82 82
 
83 83
 class _ResizeMixin(_ResizeUtils):

+ 1
- 1
oswin_tempest_plugin/tests/scenario/test_cluster.py View File

@@ -150,4 +150,4 @@ class HyperVClusterTest(migrate._MigrateMixin,
150 150
 
151 151
     def test_clustered_vm(self):
152 152
         server_tuple = self._create_server()
153
-        self._check_server_connectivity(server_tuple)
153
+        self._check_scenario(server_tuple)

+ 1
- 1
oswin_tempest_plugin/tests/scenario/test_disks.py View File

@@ -49,7 +49,7 @@ class _BaseDiskTestMixin(migrate._MigrateMixin,
49 49
 
50 50
     def test_disk(self):
51 51
         server_tuple = self._create_server()
52
-        self._check_server_connectivity(server_tuple)
52
+        self._check_scenario(server_tuple)
53 53
 
54 54
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
55 55
                           'Resize is not available.')

+ 181
- 0
oswin_tempest_plugin/tests/scenario/test_metrics_collection.py View File

@@ -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
+
16
+import time
17
+
18
+try:
19
+    # NOTE(claudiub): ceilometer might not be installed, it is not mandatory.
20
+    from ceilometer.tests.tempest.service import client as telemetry_client
21
+except Exception:
22
+    telemetry_client = None
23
+
24
+from oslo_log import log as logging
25
+from tempest import clients
26
+
27
+from oswin_tempest_plugin import config
28
+from oswin_tempest_plugin.tests import test_base
29
+
30
+CONF = config.CONF
31
+LOG = logging.getLogger(__name__)
32
+
33
+
34
+class 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
+
46
+class 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)

+ 7
- 0
oswin_tempest_plugin/tests/test_base.py View File

@@ -284,3 +284,10 @@ class TestBase(tempest.test.BaseTestCase):
284 284
     def _check_server_connectivity(self, server_tuple):
285 285
         # if server connectivity works, an SSH client can be opened.
286 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)

Loading…
Cancel
Save