Skip to content

Commit 9923a44

Browse files
MOS CIGerrit Code Review
authored andcommitted
Merge "[Exporter] Add metrics for instances in verify_resize state"
2 parents 755fe94 + 28bc12a commit 9923a44

File tree

5 files changed

+189
-4
lines changed

5 files changed

+189
-4
lines changed

rockoon/exporter/collectors/openstack/nova.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ def init_families(self):
171171
"Total number of instances in active state",
172172
labels=[],
173173
),
174+
"verify_resize_instances": GaugeMetricFamily(
175+
f"{self._name}_verify_resize_instances",
176+
"Total number of instances in VERIFY_RESIZE status",
177+
labels=[],
178+
),
174179
"hypervisor_instances": GaugeMetricFamily(
175180
f"{self._name}_hypervisor_instances",
176181
"Total number of instances per hypervisor",
@@ -206,6 +211,11 @@ def init_families(self):
206211
"Total number of instances on all compute hosts in host aggregate.",
207212
labels=["name"],
208213
),
214+
"instance_status": GaugeMetricFamily(
215+
f"{self._name}_instance_status",
216+
"Instance status (currently only VERIFY_RESIZE instances are exposed)",
217+
labels=["name", "id", "status"],
218+
),
209219
}
210220
for resource_class in self.hypervisor_resource_classes:
211221
res[f"hypervisor_{resource_class}"] = GaugeMetricFamily(
@@ -414,9 +424,15 @@ def update_service_samples(self):
414424

415425
@utils.timeit
416426
def update_instances_samples(self):
417-
instances = {"total": 0, "active": 0, "error": 0}
427+
instances = {
428+
"total": 0,
429+
"active": 0,
430+
"error": 0,
431+
"verify_resize": 0,
432+
}
418433
hypervisor_instances = {}
419434
availability_zone_instances_total = {}
435+
instance_status_samples = []
420436
for zone in self.cache.get("availability_zones", []):
421437
availability_zone_instances_total[zone["name"]] = 0
422438
for instance in self.oc.oc.compute.servers(all_projects=True):
@@ -428,13 +444,28 @@ def update_instances_samples(self):
428444
instances[status] += 1
429445
hypervisor_instances.setdefault(host, {"total": 0})
430446
hypervisor_instances[host]["total"] += 1
447+
if status == "verify_resize":
448+
instance_status_samples.append(
449+
(
450+
[
451+
instance["name"],
452+
instance["id"],
453+
status,
454+
],
455+
1,
456+
)
457+
)
431458
if zone:
432459
availability_zone_instances_total.setdefault(zone, 0)
433460
availability_zone_instances_total[zone] += 1
434461

435462
self.set_samples("instances", [([], instances["total"])])
436-
for key in ["error", "active"]:
463+
for key in ["error", "active", "verify_resize"]:
437464
self.set_samples(f"{key}_instances", [([], instances[key])])
465+
self.set_samples(
466+
"instance_status",
467+
instance_status_samples,
468+
)
438469

439470
availability_zone_instances_samples = []
440471
for zone, total in availability_zone_instances_total.items():

rockoon/tests/functional/base.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,19 @@ def server_reset_state(self, server, status, wait=True):
284284
if wait is True:
285285
waiters.wait_for_server_status(self.ocm, server, status=status)
286286

287+
def get_flavor_id(self, flavor_name):
288+
return self.ocm.oc.compute.find_flavor(flavor_name).id
289+
290+
def resize_server(self, server, flavor_id, wait=True):
291+
self.ocm.oc.compute.resize_server(server.id, flavor_id)
292+
if wait is True:
293+
waiters.wait_for_server_status(
294+
self.ocm,
295+
server,
296+
status="VERIFY_RESIZE",
297+
timeout=CONF.SERVER_RESIZE_TIMEOUT,
298+
)
299+
287300
@classmethod
288301
def lb_bundle_create(
289302
cls,

rockoon/tests/functional/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def __init__(self):
2525
self.CIRROS_TEST_IMAGE_NAME = self.get_cirros_image()
2626
self.UBUNTU_TEST_IMAGE_NAME = "Ubuntu-18.04"
2727
self.TEST_FLAVOR_SMALL_NAME = "m1.small"
28+
self.TEST_FLAVOR_TINY_NAME = "m1.tiny"
2829
self.TEST_FLAVOR_NAME = "m1.extra_tiny_test"
2930
self.TEST_SUBNET_RANGE = "10.20.30.0/24"
3031
self.TEST_SUBNET_RANGE_ALT = "10.20.31.0/24"
@@ -50,6 +51,8 @@ def __init__(self):
5051

5152
# Time in seconds to wait for a server to change a status. Default is 60 seconds.
5253
self.SERVER_TIMEOUT = 60
54+
# Time in seconds to wait for a server to resize. Default is 180 seconds.
55+
self.SERVER_RESIZE_TIMEOUT = 60 * 3
5356
# Interval in seconds to check the server status. Default is 1 second.
5457
self.SERVER_READY_INTERVAL = 1
5558

rockoon/tests/functional/exporter/parallel/test_nova_collector.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
from rockoon.tests.functional.exporter import base
88
from rockoon.tests.functional import data_utils
99
from rockoon.tests.functional.base import LOG
10+
from rockoon.tests.functional import config
11+
12+
CONF = config.Config()
1013

1114

1215
class NovaCollectorFunctionalTestCase(base.BaseFunctionalExporterTestCase):
@@ -16,6 +19,10 @@ class NovaCollectorFunctionalTestCase(base.BaseFunctionalExporterTestCase):
1619
"osdpl_nova_instances": {"labels": []},
1720
"osdpl_nova_active_instances": {"labels": []},
1821
"osdpl_nova_error_instances": {"labels": []},
22+
"osdpl_nova_verify_resize_instances": {"labels": []},
23+
# "osdpl_nova_instance_status": {
24+
# "labels": ["name", "id", "status"]
25+
# },
1926
"osdpl_nova_hypervisor_instances": {"labels": ["host", "zone"]},
2027
# "osdpl_nova_aggregate_hosts": {"labels": ["name"]},
2128
# "osdpl_nova_host_aggregate_info": {"labels": ["hosts", "name"]},
@@ -218,6 +225,136 @@ def test_nova_error_instances(self):
218225
f"Expected numbers of error servers: {len(error_servers)}.",
219226
)
220227

228+
def test_nova_verify_resize_instances(self):
229+
"""Total number of instances in VERIFY_RESIZE status.
230+
231+
**Steps**
232+
233+
#. Get exporter metric `osdpl_nova_verify_resize_instances` with initial value
234+
#. Create test instance
235+
#. Resize instance and wait until it reaches VERIFY_RESIZE status
236+
#. Check that number of VERIFY_RESIZE instances increased in exporter metrics
237+
#. Confirm resize and delete test instance
238+
#. Check that number of VERIFY_RESIZE instances decreased in exporter metrics
239+
"""
240+
241+
metric_name = "osdpl_nova_verify_resize_instances"
242+
243+
initial_metric = self.get_metric_after_refresh(
244+
metric_name, self.scrape_collector
245+
)
246+
initial_servers = self.ocm.compute_get_all_servers(
247+
status="VERIFY_RESIZE"
248+
)
249+
250+
self.assertEqual(
251+
int(initial_metric.samples[0].value),
252+
len(initial_servers),
253+
f"Current number of VERIFY_RESIZE servers in exporter's metrics is "
254+
f"{int(initial_metric.samples[0].value)}. "
255+
f"Expected number of VERIFY_RESIZE servers: {len(initial_servers)}.",
256+
)
257+
# Create a server with a smaller flavor to test resize
258+
flavor_id = self.get_flavor_id(CONF.TEST_FLAVOR_TINY_NAME)
259+
resize_flavor_id = self.get_flavor_id(CONF.TEST_FLAVOR_NAME)
260+
server = self.server_create(flavorRef=flavor_id)
261+
self.resize_server(server, resize_flavor_id)
262+
263+
metric_after_resize = self.get_metric_after_refresh(
264+
metric_name, self.scrape_collector
265+
)
266+
servers_after_resize = self.ocm.compute_get_all_servers(
267+
status="VERIFY_RESIZE"
268+
)
269+
270+
self.assertEqual(
271+
int(metric_after_resize.samples[0].value),
272+
len(servers_after_resize),
273+
f"Current number of VERIFY_RESIZE servers in exporter's metrics is "
274+
f"{int(metric_after_resize.samples[0].value)}. "
275+
f"Expected number of VERIFY_RESIZE servers: {len(servers_after_resize)}.",
276+
)
277+
278+
self.server_delete(server)
279+
280+
metric = self.get_metric_after_refresh(
281+
metric_name, self.scrape_collector
282+
)
283+
self.assertEqual(
284+
int(metric.samples[0].value),
285+
len(servers_after_resize) - 1,
286+
f"Current number of VERIFY_RESIZE servers in exporter's metrics is "
287+
f"{int(metric.samples[0].value)}. "
288+
f"Expected number of VERIFY_RESIZE servers: {len(servers_after_resize) - 1}.",
289+
)
290+
291+
def test_instance_status(self):
292+
"""Check that instance_status metric appears when VM is in VERIFY_RESIZE status.
293+
294+
**Steps:**
295+
296+
#. Create a test instance
297+
#. Get initial samples for metric `osdpl_nova_instance_status`
298+
#. Check that metric doesn't have sample for the test instance
299+
#. Resize test instance
300+
#. Refresh metric and check that a new sample with the VM's name, id and status appears
301+
#. Delete the test instance
302+
#. Refresh metric and check that the sample disappears
303+
"""
304+
metric_name = "osdpl_nova_instance_status"
305+
306+
# Create a server with a smaller flavor to test resize
307+
flavor_id = self.get_flavor_id(CONF.TEST_FLAVOR_TINY_NAME)
308+
resize_flavor_id = self.get_flavor_id(CONF.TEST_FLAVOR_NAME)
309+
server = self.server_create(flavorRef=flavor_id)
310+
metric = self.get_metric_after_refresh(
311+
metric_name, self.scrape_collector
312+
)
313+
labels = {
314+
"id": server["id"],
315+
"name": server["name"],
316+
"status": server["status"].lower(),
317+
}
318+
samples = self.filter_metric_samples(metric, labels)
319+
self.assertEqual(
320+
len(samples),
321+
0,
322+
f"Instance_status metric contain sample for VM {server['name']}",
323+
)
324+
325+
self.resize_server(server, resize_flavor_id)
326+
server = self.ocm.oc.get_server(server.id)
327+
labels = {
328+
"id": server["id"],
329+
"name": server["name"],
330+
"status": server["status"].lower(),
331+
}
332+
metric = self.get_metric_after_refresh(
333+
metric_name, self.scrape_collector
334+
)
335+
samples = self.filter_metric_samples(metric, labels)
336+
self.assertEqual(
337+
len(samples),
338+
1,
339+
f"Instance_status metric does not contain sample for VM {server['name']}",
340+
)
341+
self.assertCountEqual(
342+
["name", "id", "status"],
343+
samples[0].labels.keys(),
344+
)
345+
self.server_delete(server)
346+
metric_after_delete = self.get_metric_after_refresh(
347+
metric_name, self.scrape_collector
348+
)
349+
deleted_samples = self.filter_metric_samples(
350+
metric_after_delete, labels
351+
)
352+
self.assertEqual(
353+
len(deleted_samples),
354+
0,
355+
f"Instance_status metric sample for VM {server['name']} still exists after deletion",
356+
)
357+
221358

222359
@pytest.mark.xdist_group("exporter-compute-network")
223360
class NovaAvailabilityZonesTestCase(base.BaseFunctionalExporterTestCase):

rockoon/tests/functional/waiters.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ def wait_for_service_status_state(
4848
raise TimeoutError(message)
4949

5050

51-
def wait_for_server_status(openstack_client, server, status):
51+
def wait_for_server_status(
52+
openstack_client, server, status, timeout=CONF.SERVER_TIMEOUT
53+
):
5254
start_time = int(time.time())
53-
timeout = CONF.SERVER_TIMEOUT
5455
while True:
5556
server = openstack_client.oc.get_server(server.id)
5657
if server.status.upper() == status.upper():

0 commit comments

Comments
 (0)