Fallback to `node_uuid` if`node_name` is not present

IPE fails to write the nodefile if the node doesn't have
`node_name`, if not present `node_uuid` will be used.
Updated tests and code logic to identify when `node_name` is
not present.

Changed tox.ini to ignore W503

Co-Authored: Iury Gregory Melo Ferreira <iurygregory@gmail.com>
Change-Id: I0c780584f53a9867dab6b0e6b3428c29f0a763b6
Task: 39557
Story: 2007593
(cherry picked from commit 6e6f218eb8)
This commit is contained in:
tanghang 2020-04-26 16:16:38 +08:00 committed by Iury Gregory Melo Ferreira
parent 66dc3e29d0
commit 3a1fd72dda
13 changed files with 2615 additions and 9 deletions

View File

@ -56,9 +56,10 @@ class PrometheusFileDriver(notifier.Driver):
elif event_type == 'hardware.redfish.metrics':
redfish.category_registry(node_message, registry)
field = (node_message.get('node_name')
or node_message.get('node_uuid'))
nodeFile = os.path.join(
self.location,
node_message['node_name'] + '-' + event_type)
self.location, field + '-' + event_type)
write_to_textfile(nodeFile, registry)
except Exception as e:

View File

@ -18,11 +18,12 @@ from ironic_prometheus_exporter import utils as ipe_utils
from ironic_prometheus_exporter.parsers import descriptions
def timestamp_registry(node_information, ipmi_metric_registry):
def timestamp_registry(node_information, metric_registry):
metric = 'baremetal_last_payload_timestamp_seconds'
labels = {'node_name': node_information['node_name'],
'node_uuid': node_information['node_uuid'],
labels = {'node_uuid': node_information['node_uuid'],
'instance_uuid': node_information['instance_uuid']}
if node_information['node_name']:
labels['node_name'] = node_information['node_name']
dt_1970 = datetime(1970, 1, 1, 0, 0, 0)
dt_timestamp = datetime.strptime(node_information['timestamp'],
'%Y-%m-%dT%H:%M:%S.%f')
@ -32,7 +33,7 @@ def timestamp_registry(node_information, ipmi_metric_registry):
g = Gauge(
metric, desc, labelnames=labels,
registry=ipmi_metric_registry)
registry=metric_registry)
valid_labels = ipe_utils.update_instance_uuid(labels)
g.labels(**valid_labels).set(value)

View File

@ -163,6 +163,8 @@ def extract_labels(entries, category_info):
'instance_uuid': category_info['instance_uuid'],
'entity_id': category_info['data'][entries[0]]['Entity ID'],
'sensor_id': category_info['data'][entries[0]]['Sensor ID']}
if not category_info['node_name']:
del labels['node_name']
if status:
labels['status'] = status
return {entries[0]: labels}
@ -177,6 +179,8 @@ def extract_labels(entries, category_info):
'instance_uuid': category_info['instance_uuid'],
'entity_id': entity_id,
'sensor_id': sensor_id}
if not category_info['node_name']:
del metric_label['node_name']
if status:
metric_label['status'] = status
entries_labels[entry] = metric_label

View File

@ -23,9 +23,11 @@ LOG = logging.getLogger(__name__)
def _build_labels(node_message):
fields = ['node_name', 'node_uuid', 'instance_uuid']
if not node_message['node_name']:
fields.remove('node_name')
return {
k: node_message[k]
for k in ('node_name', 'node_uuid', 'instance_uuid')
k: node_message[k] for k in fields
}

View File

@ -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":"85d6b2c8-fe57-432d-868a-330e0e28cf34",
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
"event_type": "hardware.redfish.metrics.update",
"timestamp": "2019-03-29T20:12:22.989020",
"node_name": "",
"message_id": "330e0e28-fe43-5786-2d8a-85d6b2c8cf34",
"payload": {
}
},
"message_id": "2c0da1e8-1958-484f-9bdd-9117d717f7fa"
}

View File

@ -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": "85d6b2c8-fe57-432d-868a-330e0e28cf34" ,
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
"event_type": "hardware.redfish.metrics.update",
"timestamp": "2019-03-29T20:12:22.989020",
"node_name": null,
"message_id": "85d6b2c8-fe57-432d-868a-330e0e28cf34",
"payload": {
}
},
"message_id": "2c0da1e8-1958-484f-9bdd-9117d717f7fa"
}

View File

@ -0,0 +1,67 @@
{
"priority": "INFO",
"event_type": "hardware.redfish.metrics",
"timestamp": "2019-03-29 20:12:26.885347",
"publisher_id": "None.localhost.localdomain",
"payload": {
"instance_uuid": "85d6b2c8-fe57-432d-868a-330e0e28cf34",
"node_uuid": "c2bd00b9-9881-4179-8b7b-bf786ec3696b",
"event_type": "hardware.redfish.metrics.update",
"timestamp": "2019-03-29T20:12:22.989020",
"node_name": null,
"message_id": "85d6b2c8-fe57-432d-868a-330e0e28cf34",
"payload": {
"Temperature": {
"XXX-YYY-ZZZ@ZZZ-YYY-XXX": {
"identity": "XXX-YYY-ZZZ",
"max_reading_range_temp": 120,
"min_reading_range_temp": 0,
"physical_context": "CPU",
"reading_celsius": 62,
"sensor_number": 1,
"health": "OK",
"state": "enabled"
}
},
"Power": {
"0:Power@ZZZ-YYY-XXX": {
"health": "OK",
"last_power_output_watts": 650,
"line_input_voltage": 220,
"maximum_frequency_hz": 63,
"maximum_voltage": 250,
"minimum_frequency_hz": 47,
"minimum_voltage": 185,
"output_wattage": 1450,
"power_capacity_watts": 1450,
"serial_number": "SN010203040506",
"state": "enabled"
}
},
"Fan": {
"XXX-YYY-ZZZ@ZZZ-YYY-XXX": {
"identity": "XXX-YYY-ZZZ",
"max_reading_range": 10000,
"min_reading_range": 0,
"physical_context": "CPU",
"reading": 6000,
"reading_units": "RPM",
"serial_number": "SN010203040506",
"health": "OK",
"state": "enabled"
}
},
"Drive": {
"32ADF365C6C1B7BD:XXX-YYY-ZZZ@ZZZ-YYY-XXX": {
"capacity_bytes": 3750000000,
"failure_predicted": true,
"health": "OK",
"identity": "32ADF365C6C1B7BD",
"model": "IBM 350A",
"state": "enabled"
}
}
}
},
"message_id": "2c0da1e8-1958-484f-9bdd-9117d717f7fa"
}

View File

@ -65,3 +65,31 @@ class TestPayloadsParser(unittest.TestCase):
'node_uuid': msg2['payload']['node_uuid'],
'instance_uuid': msg2['payload']['node_uuid']}
))
def test_none_for_node_name(self):
sample_file_2 = os.path.join(
os.path.dirname(ironic_prometheus_exporter.__file__),
'tests', 'json_samples', 'notification-none-node_name.json')
msg2 = json.load(open(sample_file_2))
self.assertIsNone(msg2['payload']['node_name'])
header.timestamp_registry(msg2['payload'], self.metric_registry)
self.assertEqual(1553890342.0, self.metric_registry.get_sample_value(
'baremetal_last_payload_timestamp_seconds',
{'node_uuid': msg2['payload']['node_uuid'],
'instance_uuid': msg2['payload']['instance_uuid']}
))
def test_empty_for_node_name(self):
sample_file_2 = os.path.join(
os.path.dirname(ironic_prometheus_exporter.__file__),
'tests', 'json_samples', 'notification-empty-node_name.json')
msg2 = json.load(open(sample_file_2))
self.assertEqual(msg2['payload']['node_name'], "")
header.timestamp_registry(msg2['payload'], self.metric_registry)
self.assertEqual(1553890342.0, self.metric_registry.get_sample_value(
'baremetal_last_payload_timestamp_seconds',
{'node_uuid': msg2['payload']['node_uuid'],
'instance_uuid': msg2['payload']['instance_uuid']}
))

View File

@ -955,3 +955,88 @@ class TestPayloadsParser(unittest.TestCase):
'instance_uuid': msg2['payload']['node_uuid'],
'entity_id': '7.1 (System Board)',
'sensor_id': 'Front LED Panel (0x23)'}))
class TestPayloadsParserNoneNodeName(unittest.TestCase):
def setUp(self):
sample_file = os.path.join(
os.path.dirname(ironic_prometheus_exporter.__file__),
'tests', 'json_samples',
'notification-ipmi-none-node_name.json')
msg = json.load(open(sample_file))
self.node_message = msg['payload']
self.node_name = msg['payload']['node_name']
self.node_uuid = msg['payload']['node_uuid']
self.instance_uuid = msg['payload']['instance_uuid']
self.timestamp = msg['payload']['timestamp']
self.payload = msg['payload']['payload']
self.metric_registry = CollectorRegistry()
def test_management_parser(self):
management_category_info = ipmi.CATEGORY_PARAMS['management'].copy()
management_category_info['data'] = \
self.node_message['payload']['Management'].copy()
management_category_info['node_name'] = self.node_name
management_category_info['node_uuid'] = self.node_uuid
management_category_info['instance_uuid'] = self.instance_uuid
management_metrics_name = ipmi.metric_names(management_category_info)
self.assertEqual(len(management_metrics_name), 1)
self.assertIn('baremetal_front_led_panel', management_metrics_name)
ipmi.prometheus_format(management_category_info,
self.metric_registry,
management_metrics_name)
self.assertEqual(0.0, self.metric_registry.get_sample_value(
'baremetal_front_led_panel',
{'node_uuid': self.node_uuid,
'instance_uuid': self.instance_uuid,
'entity_id': '7.1 (System Board)',
'sensor_id': 'Front LED Panel (0x23)'}))
def test_temperature_parser(self):
temperature_category_info = ipmi.CATEGORY_PARAMS['temperature'].copy()
temperature_category_info['data'] = \
self.node_message['payload']['Temperature'].copy()
temperature_category_info['node_name'] = self.node_name
temperature_category_info['node_uuid'] = self.node_uuid
temperature_category_info['instance_uuid'] = self.instance_uuid
temperature_metrics_name = ipmi.metric_names(temperature_category_info)
self.assertEqual(len(temperature_metrics_name), 3)
self.assertIn('baremetal_temp_celsius', temperature_metrics_name)
self.assertIn('baremetal_exhaust_temp_celsius',
temperature_metrics_name)
self.assertIn('baremetal_inlet_temp_celsius', temperature_metrics_name)
ipmi.prometheus_format(temperature_category_info,
self.metric_registry,
temperature_metrics_name)
self.assertEqual(21.0, self.metric_registry.get_sample_value(
'baremetal_inlet_temp_celsius',
{'node_uuid': self.node_uuid,
'instance_uuid': self.instance_uuid,
'entity_id': '7.1 (System Board)',
'sensor_id': 'Inlet Temp (0x5)',
'status': 'ok'}
))
self.assertEqual(36.0, self.metric_registry.get_sample_value(
'baremetal_exhaust_temp_celsius',
{'node_uuid': self.node_uuid,
'instance_uuid': self.instance_uuid,
'entity_id': '7.1 (System Board)',
'sensor_id': 'Exhaust Temp (0x6)',
'status': 'ok'}))
self.assertEqual(44.0, self.metric_registry.get_sample_value(
'baremetal_temp_celsius', {'sensor_id': 'Temp (0x1)',
'node_uuid': self.node_uuid,
'instance_uuid': self.instance_uuid,
'entity_id': '3.1 (Processor)',
'status': 'ok'}))
self.assertEqual(43.0, self.metric_registry.get_sample_value(
'baremetal_temp_celsius', {'sensor_id': 'Temp (0x2)',
'node_uuid': self.node_uuid,
'instance_uuid': self.instance_uuid,
'entity_id': '3.2 (Processor)',
'status': 'ok'}))

View File

@ -151,3 +151,35 @@ class TestPayloadsParser(unittest.TestCase):
self.assertEqual(
expected_labels, metrics[expected_metric][0][1])
class TestPayloadsParserNoneNodeName(unittest.TestCase):
def setUp(self):
sample_file_none = os.path.join(
os.path.dirname(ironic_prometheus_exporter.__file__),
'tests', 'json_samples',
'notification-redfish-none-node_name.json')
msg = json.load(open(sample_file_none))
self.node_message = msg['payload']
self.node_uuid = msg['payload']['node_uuid']
self.instance_uuid = msg['payload']['instance_uuid']
def test_build_temperature_metrics(self):
metrics = redfish.build_temperature_metrics(self.node_message)
expected_metric = 'baremetal_temp_cpu_celsius'
self.assertIn(expected_metric, metrics)
self.assertEqual(62, metrics[expected_metric][0][0])
expected_labels = {
'entity_id': 'CPU',
'instance_uuid': '85d6b2c8-fe57-432d-868a-330e0e28cf34',
'node_uuid': 'c2bd00b9-9881-4179-8b7b-bf786ec3696b',
'sensor_id': 1
}
self.assertEqual(
expected_labels, metrics[expected_metric][0][1])

View File

@ -0,0 +1,4 @@
---
fixes:
- |
Fix an issue where IPE fails if the node does not have `node_name` set

View File

@ -53,7 +53,7 @@ deps =
commands = {posargs}
[flake8]
ignore = E129
ignore = E129,W503
show-source = True
builtins = _
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build