From 656687695b4733624ca56aa7ee55582814baa781 Mon Sep 17 00:00:00 2001 From: John Garbutt Date: Wed, 10 Sep 2025 14:42:21 +0100 Subject: [PATCH 1/3] Gather api performance metrics Signed-off-by: John Garbutt --- os_capacity/api_test.py | 134 ++++++++++++++++++++++++++++++++++++++ os_capacity/prometheus.py | 5 +- 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 os_capacity/api_test.py diff --git a/os_capacity/api_test.py b/os_capacity/api_test.py new file mode 100644 index 0000000..f3d81dc --- /dev/null +++ b/os_capacity/api_test.py @@ -0,0 +1,134 @@ +# 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. +import openstack +from prometheus_client import core as prom_core + +RETRY_COUNT = 3 + + +class OpenStackAPITestCollector(object): + def __init__(self): + openstack.connect() + print("got openstack connection\n") + + def _check_compute(self, conn): + for i in range(RETRY_COUNT): + flavors = list(conn.compute.flavors()) + flavor_count = prom_core.GaugeMetricFamily( + "openstack_flavor_count", + "The number of flavors in the OpenStack deployment.", + labels=["project_id"], + ) + flavor_count.add_metric([conn.current_project_id], len(flavors)) + + for i in range(RETRY_COUNT): + servers = list(conn.compute.servers()) + server_count = prom_core.GaugeMetricFamily( + "openstack_server_count", + "The number of servers in the OpenStack deployment.", + labels=["project_id"], + ) + server_count.add_metric([conn.current_project_id], len(servers)) + return [flavor_count, server_count] + + def _check_images(self, conn): + for i in range(RETRY_COUNT): + images = list(conn.image.images()) + image_count = prom_core.GaugeMetricFamily( + "openstack_image_count", + "The number of images in the OpenStack deployment.", + labels=["project_id"], + ) + image_count.add_metric([conn.current_project_id], len(images)) + return [image_count] + + def _check_volumes(self, conn): + for i in range(RETRY_COUNT): + volumes = list(conn.block_storage.volumes()) + volume_count = prom_core.GaugeMetricFamily( + "openstack_volume_count", + "The number of volumes in the OpenStack deployment.", + labels=["project_id"], + ) + volume_count.add_metric([conn.current_project_id], len(volumes)) + return [volume_count] + + def _check_ironic(self, conn): + for i in range(RETRY_COUNT): + nodes = list(conn.bare_metal.nodes()) + ironic_node_count = prom_core.GaugeMetricFamily( + "openstack_ironic_node_count", + "The number of ironic nodes in the OpenStack deployment.", + labels=["project_id"], + ) + ironic_node_count.add_metric([conn.current_project_id], len(nodes)) + return [ironic_node_count] + + def _check_identity(self, conn): + user = conn.current_user_id + for i in range(RETRY_COUNT): + projects = list(conn.identity.user_projects(user)) + project_count = prom_core.GaugeMetricFamily( + "openstack_project_count", + "The number of projects in the OpenStack deployment.", + labels=["project_id"], + ) + project_count.add_metric([conn.current_project_id], len(projects)) + return [project_count] + + def _check_network(self, conn): + for i in range(RETRY_COUNT): + networks = list(conn.network.networks()) + network_count = prom_core.GaugeMetricFamily( + "openstack_network_count", + "The number of networks in the OpenStack deployment.", + labels=["project_id"], + ) + network_count.add_metric([], len(networks)) + + for i in range(RETRY_COUNT): + ports = list(conn.network.ports()) + port_count = prom_core.GaugeMetricFamily( + "openstack_port_count", + "The number of ports in the OpenStack deployment.", + labels=["project_id"], + ) + port_count.add_metric([conn.current_project_id], len(ports)) + return [network_count, port_count] + + def _check_load_balancer(self, conn): + for i in range(RETRY_COUNT): + lbs = list(conn.load_balancer.load_balancers()) + lb_count = prom_core.GaugeMetricFamily( + "openstack_load_balancer_count", + "The number of load balancers in the OpenStack deployment.", + labels=["project_id"], + ) + lb_count.add_metric([conn.current_project_id], len(lbs)) + return [lb_count] + + def collect(self): + openstack.enable_logging(debug=False) + conn = openstack.connect() + print("collecting api test metrics\n") + guages = [] + + guages += self._check_compute(conn) + guages += self._check_images(conn) + guages += self._check_volumes(conn) + guages += self._check_ironic(conn) + guages += self._check_identity(conn) + guages += self._check_network(conn) + guages += self._check_load_balancer(conn) + + print("finished collecting metrics\n") + return guages diff --git a/os_capacity/prometheus.py b/os_capacity/prometheus.py index 9e0ac7d..df7eece 100755 --- a/os_capacity/prometheus.py +++ b/os_capacity/prometheus.py @@ -20,6 +20,8 @@ import prometheus_client as prom_client from prometheus_client import core as prom_core +from os_capacity import api_test + RESOURCE_PROVIDER_AGGREGATE_CACHE = {} @@ -391,7 +393,8 @@ def main(): } prom_client.start_http_server(**kwargs) - prom_core.REGISTRY.register(OpenStackCapacityCollector()) + # prom_core.REGISTRY.register(OpenStackCapacityCollector()) + prom_core.REGISTRY.register(api_test.OpenStackAPITestCollector()) # there must be a better way! while True: time.sleep(5000) From a57397c4c44fa8ecb840ae2994d44ddb456a75cb Mon Sep 17 00:00:00 2001 From: John Garbutt Date: Wed, 10 Sep 2025 14:44:06 +0100 Subject: [PATCH 2/3] Update prometheus.py --- os_capacity/prometheus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os_capacity/prometheus.py b/os_capacity/prometheus.py index df7eece..dc26ce3 100755 --- a/os_capacity/prometheus.py +++ b/os_capacity/prometheus.py @@ -393,7 +393,7 @@ def main(): } prom_client.start_http_server(**kwargs) - # prom_core.REGISTRY.register(OpenStackCapacityCollector()) + prom_core.REGISTRY.register(OpenStackCapacityCollector()) prom_core.REGISTRY.register(api_test.OpenStackAPITestCollector()) # there must be a better way! while True: From e2c8ad77a974d773d95694fbb3a95a61bd81ab04 Mon Sep 17 00:00:00 2001 From: John Garbutt Date: Wed, 10 Sep 2025 14:45:39 +0100 Subject: [PATCH 3/3] Fix up tox --- os_capacity/api_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/os_capacity/api_test.py b/os_capacity/api_test.py index f3d81dc..3f16a0b 100644 --- a/os_capacity/api_test.py +++ b/os_capacity/api_test.py @@ -50,7 +50,7 @@ def _check_images(self, conn): ) image_count.add_metric([conn.current_project_id], len(images)) return [image_count] - + def _check_volumes(self, conn): for i in range(RETRY_COUNT): volumes = list(conn.block_storage.volumes()) @@ -61,7 +61,7 @@ def _check_volumes(self, conn): ) volume_count.add_metric([conn.current_project_id], len(volumes)) return [volume_count] - + def _check_ironic(self, conn): for i in range(RETRY_COUNT): nodes = list(conn.bare_metal.nodes()) @@ -72,7 +72,7 @@ def _check_ironic(self, conn): ) ironic_node_count.add_metric([conn.current_project_id], len(nodes)) return [ironic_node_count] - + def _check_identity(self, conn): user = conn.current_user_id for i in range(RETRY_COUNT): @@ -84,7 +84,7 @@ def _check_identity(self, conn): ) project_count.add_metric([conn.current_project_id], len(projects)) return [project_count] - + def _check_network(self, conn): for i in range(RETRY_COUNT): networks = list(conn.network.networks()) @@ -104,7 +104,7 @@ def _check_network(self, conn): ) port_count.add_metric([conn.current_project_id], len(ports)) return [network_count, port_count] - + def _check_load_balancer(self, conn): for i in range(RETRY_COUNT): lbs = list(conn.load_balancer.load_balancers())