From 46e50fb56f8370a4ef47af115a441a71e0d7b3b2 Mon Sep 17 00:00:00 2001 From: Ilya Etingof Date: Thu, 5 Sep 2019 16:32:05 +0200 Subject: [PATCH] Move timestamp registry to a sharable 'header' module The timestamp registry is going to be used by other parsers in the future. Thus it seems reasonable to move if from ipmi to something sharable. Conceptually, `timestamp_registry` operates on Oslo message header - perhaps we can have a dedicated parser module for such common things - 'header'. Change-Id: I2ba2f0ae28f09dbccd818c82005d47c7a515dfd4 --- ironic_prometheus_exporter/messaging.py | 3 +- ironic_prometheus_exporter/parsers/header.py | 28 +++++++++++ ironic_prometheus_exporter/parsers/ipmi.py | 15 ------ .../json_samples/notification-header.json | 17 +++++++ .../tests/test_header_parser.py | 48 +++++++++++++++++++ .../tests/test_ipmi_parser.py | 10 ---- 6 files changed, 95 insertions(+), 26 deletions(-) create mode 100644 ironic_prometheus_exporter/parsers/header.py create mode 100644 ironic_prometheus_exporter/tests/json_samples/notification-header.json create mode 100644 ironic_prometheus_exporter/tests/test_header_parser.py diff --git a/ironic_prometheus_exporter/messaging.py b/ironic_prometheus_exporter/messaging.py index 1edb57a..13f7c81 100644 --- a/ironic_prometheus_exporter/messaging.py +++ b/ironic_prometheus_exporter/messaging.py @@ -14,6 +14,7 @@ import logging import os from ironic_prometheus_exporter.parsers import ipmi +from ironic_prometheus_exporter.parsers import header from oslo_config import cfg from oslo_messaging.notify import notifier from prometheus_client import write_to_textfile, CollectorRegistry @@ -45,7 +46,7 @@ class PrometheusFileDriver(notifier.Driver): if message['event_type'] == 'hardware.ipmi.metrics': registry = CollectorRegistry() node_message = message['payload'] - ipmi.timestamp_registry(node_message, registry) + header.timestamp_registry(node_message, registry) ipmi.category_registry(node_message, registry) nodeFile = os.path.join(self.location, node_message['node_name']) diff --git a/ironic_prometheus_exporter/parsers/header.py b/ironic_prometheus_exporter/parsers/header.py new file mode 100644 index 0000000..036c965 --- /dev/null +++ b/ironic_prometheus_exporter/parsers/header.py @@ -0,0 +1,28 @@ +# 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 datetime import datetime +from prometheus_client import Gauge + + +def timestamp_registry(node_information, ipmi_metric_registry): + metric = 'baremetal_last_payload_timestamp_seconds' + labels = {'node_name': node_information['node_name'], + 'node_uuid': node_information['node_uuid'], + 'instance_uuid': node_information['instance_uuid']} + dt_1970 = datetime(1970, 1, 1, 0, 0, 0) + dt_timestamp = datetime.strptime(node_information['timestamp'], + '%Y-%m-%dT%H:%M:%S.%f') + value = int((dt_timestamp - dt_1970).total_seconds()) + g = Gauge(metric, 'Timestamp of the last received payload', + labelnames=labels.keys(), registry=ipmi_metric_registry) + g.labels(**labels).set(value) diff --git a/ironic_prometheus_exporter/parsers/ipmi.py b/ironic_prometheus_exporter/parsers/ipmi.py index 017da3a..2b8fc0c 100644 --- a/ironic_prometheus_exporter/parsers/ipmi.py +++ b/ironic_prometheus_exporter/parsers/ipmi.py @@ -15,7 +15,6 @@ import logging import pkg_resources import re -from datetime import datetime from prometheus_client import Gauge # NOTE (iurygregory): most of the sensor readings come in the ipmi format @@ -243,19 +242,5 @@ def category_registry(node_message, ipmi_metric_registry): available_metrics) -def timestamp_registry(node_information, ipmi_metric_registry): - metric = 'baremetal_last_payload_timestamp_seconds' - labels = {'node_name': node_information['node_name'], - 'node_uuid': node_information['node_uuid'], - 'instance_uuid': node_information['instance_uuid']} - dt_1970 = datetime(1970, 1, 1, 0, 0, 0) - dt_timestamp = datetime.strptime(node_information['timestamp'], - '%Y-%m-%dT%H:%M:%S.%f') - value = int((dt_timestamp - dt_1970).total_seconds()) - g = Gauge(metric, get_metric_description(metric), - labelnames=list(labels), registry=ipmi_metric_registry) - g.labels(**labels).set(value) - - def get_metric_description(metric_name): return IPMI_METRICS_DESCRIPTION.get(metric_name, '') diff --git a/ironic_prometheus_exporter/tests/json_samples/notification-header.json b/ironic_prometheus_exporter/tests/json_samples/notification-header.json new file mode 100644 index 0000000..3ada7c8 --- /dev/null +++ b/ironic_prometheus_exporter/tests/json_samples/notification-header.json @@ -0,0 +1,17 @@ +{ + "priority": "INFO", + "event_type": "hardware.redfish.metrics", + "timestamp": "2019-03-29 20:12:26.885347", + "publisher_id": "None.localhost.localdomain", + "payload": { + "instance_uuid": "ac2aa2fd-6e1a-41c8-a114-2084c8705228", + "node_uuid": "ac2aa2fd-6e1a-41c8-a114-2084c8705228", + "event_type": "hardware.redfish.metrics.update", + "timestamp": "2019-03-29T20:12:22.989020", + "node_name": "knilab-master-u9", + "message_id": "85d6b2c8-fe57-432d-868a-330e0e28cf34", + "payload": { + } + }, + "message_id": "2c0da1e8-1958-484f-9bdd-9117d717f7fa" +} diff --git a/ironic_prometheus_exporter/tests/test_header_parser.py b/ironic_prometheus_exporter/tests/test_header_parser.py new file mode 100644 index 0000000..d9c294d --- /dev/null +++ b/ironic_prometheus_exporter/tests/test_header_parser.py @@ -0,0 +1,48 @@ +# 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 json +import os +import unittest + +import ironic_prometheus_exporter +from ironic_prometheus_exporter.parsers import header +from prometheus_client import CollectorRegistry + + +sample_file = os.path.join( + os.path.dirname(ironic_prometheus_exporter.__file__), + 'tests', 'json_samples', 'notification-header.json') + +DATA = json.load(open(sample_file)) + + +class TestPayloadsParser(unittest.TestCase): + + def setUp(self): + self.node_message = DATA['payload'] + self.node_name = DATA['payload']['node_name'] + self.node_uuid = DATA['payload']['node_uuid'] + self.instance_uuid = DATA['payload']['instance_uuid'] + self.timestamp = DATA['payload']['timestamp'] + self.payload = DATA['payload']['payload'] + self.metric_registry = CollectorRegistry() + + def test_timestamp_metric(self): + header.timestamp_registry(self.node_message, self.metric_registry) + + self.assertEqual(1553890342.0, self.metric_registry.get_sample_value( + 'baremetal_last_payload_timestamp_seconds', + {'node_name': self.node_name, + 'node_uuid': self.node_uuid, + 'instance_uuid': self.instance_uuid} + )) diff --git a/ironic_prometheus_exporter/tests/test_ipmi_parser.py b/ironic_prometheus_exporter/tests/test_ipmi_parser.py index 5eca521..73a01d9 100644 --- a/ironic_prometheus_exporter/tests/test_ipmi_parser.py +++ b/ironic_prometheus_exporter/tests/test_ipmi_parser.py @@ -559,16 +559,6 @@ class TestPayloadsParser(unittest.TestCase): 'entity_id': '7.1 (System Board)', 'status': 'ok'})) - def test_timestamp_metric(self): - ipmi.timestamp_registry(self.node_message, self.metric_registry) - - self.assertEqual(1553890342.0, self.metric_registry.get_sample_value( - 'baremetal_last_payload_timestamp_seconds', - {'node_name': self.node_name, - 'node_uuid': self.node_uuid, - 'instance_uuid': self.instance_uuid} - )) - def test_voltage_manager(self): voltage_category_info = ipmi.CATEGORY_PARAMS['voltage'].copy() voltage_category_info['data'] = \