diff options
18 files changed, 1358 insertions, 817 deletions
diff --git a/ceilometer/cmd/agent_ipmi.py b/ceilometer/cmd/agent_ipmi.py new file mode 100644 index 00000000..eb57e75b --- /dev/null +++ b/ceilometer/cmd/agent_ipmi.py @@ -0,0 +1,23 @@ +# +# Copyright 2014 OpenStack Foundation +# +# 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 ceilometer.ipmi import manager +from ceilometer.openstack.common import service as os_service +from ceilometer import service + + +def main(): + service.prepare_service() + os_service.launch(manager.AgentManager()).wait() diff --git a/ceilometer/ipmi/manager.py b/ceilometer/ipmi/manager.py new file mode 100644 index 00000000..6fbb1ec6 --- /dev/null +++ b/ceilometer/ipmi/manager.py @@ -0,0 +1,23 @@ +# Copyright 2014 Intel +# +# Author: Zhai Edwin <edwin.zhai@intel.com> +# +# 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 ceilometer import agent + + +class AgentManager(agent.AgentManager): + + def __init__(self): + super(AgentManager, self).__init__('ipmi') diff --git a/ceilometer/hardware/notifications/__init__.py b/ceilometer/ipmi/notifications/__init__.py index e69de29b..e69de29b 100644 --- a/ceilometer/hardware/notifications/__init__.py +++ b/ceilometer/ipmi/notifications/__init__.py diff --git a/ceilometer/hardware/notifications/ipmi.py b/ceilometer/ipmi/notifications/ironic.py index deb69ce9..4e37eeaa 100644 --- a/ceilometer/hardware/notifications/ipmi.py +++ b/ceilometer/ipmi/notifications/ironic.py @@ -44,6 +44,25 @@ UNIT_MAP = { } +def validate_reading(data): + """Some sensors read "Disabled".""" + return data != 'Disabled' + + +def transform_id(data): + return data.lower().replace(' ', '_') + + +def parse_reading(data): + try: + volume, unit = data.split(' ', 1) + unit = unit.rsplit(' ', 1)[-1] + return float(volume), UNIT_MAP.get(unit, unit) + except ValueError: + raise InvalidSensorData('unable to parse sensor reading: %s' % + data) + + class InvalidSensorData(ValueError): pass @@ -76,25 +95,6 @@ class SensorNotification(plugin.NotificationBase): except KeyError: return [] - @staticmethod - def _validate_reading(data): - """Some sensors read "Disabled".""" - return data != 'Disabled' - - @staticmethod - def _transform_id(data): - return data.lower().replace(' ', '_') - - @staticmethod - def _parse_reading(data): - try: - volume, unit = data.split(' ', 1) - unit = unit.rsplit(' ', 1)[-1] - return float(volume), UNIT_MAP.get(unit, unit) - except ValueError: - raise InvalidSensorData('unable to parse sensor reading: %s' % - data) - def _package_payload(self, message, payload): # NOTE(chdent): How much of the payload should we keep? info = {'publisher_id': message['publisher_id'], @@ -125,7 +125,7 @@ class SensorNotification(plugin.NotificationBase): try: resource_id = '%(nodeid)s-%(sensorid)s' % { 'nodeid': message['payload']['node_uuid'], - 'sensorid': self._transform_id(payload['Sensor ID']) + 'sensorid': transform_id(payload['Sensor ID']) } except KeyError as exc: raise InvalidSensorData('missing key in payload: %s' % exc) @@ -139,8 +139,8 @@ class SensorNotification(plugin.NotificationBase): "missing 'Sensor Reading' in payload" ) - if self._validate_reading(sensor_reading): - volume, unit = self._parse_reading(sensor_reading) + if validate_reading(sensor_reading): + volume, unit = parse_reading(sensor_reading) yield sample.Sample.from_notification( name='hardware.ipmi.%s' % self.metric.lower(), type=sample.TYPE_GAUGE, diff --git a/ceilometer/tests/hardware/notifications/__init__.py b/ceilometer/ipmi/pollsters/__init__.py index e69de29b..e69de29b 100644 --- a/ceilometer/tests/hardware/notifications/__init__.py +++ b/ceilometer/ipmi/pollsters/__init__.py diff --git a/ceilometer/ipmi/pollsters/node.py b/ceilometer/ipmi/pollsters/node.py new file mode 100644 index 00000000..a04c3750 --- /dev/null +++ b/ceilometer/ipmi/pollsters/node.py @@ -0,0 +1,77 @@ +# Copyright 2014 Intel +# +# Author: Zhai Edwin <edwin.zhai@intel.com> +# +# 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 abc + +from oslo.config import cfg +from oslo.utils import timeutils +import six + +from ceilometer.ipmi.platform import intel_node_manager as node_manager +from ceilometer import plugin +from ceilometer import sample + +CONF = cfg.CONF +CONF.import_opt('host', 'ceilometer.service') + + +@six.add_metaclass(abc.ABCMeta) +class _Base(plugin.PollsterBase): + def __init__(self): + self.nodemanager = node_manager.NodeManager() + + @property + def default_discovery(self): + return None + + @abc.abstractmethod + def read_data(self): + """Return data sample for IPMI.""" + + def get_samples(self, manager, cache, resources): + stats = self.read_data() + + if stats: + data = node_manager._hex(stats["Current_value"]) + + yield sample.Sample( + name=self.NAME, + type=self.TYPE, + unit=self.UNIT, + volume=data, + user_id=None, + project_id=None, + resource_id=CONF.host, + timestamp=timeutils.utcnow().isoformat(), + resource_metadata=None) + + +class TemperaturePollster(_Base): + NAME = "hardware.ipmi.node.temperature" + TYPE = sample.TYPE_GAUGE + UNIT = "C" + + def read_data(self): + return self.nodemanager.read_temperature_all() + + +class PowerPollster(_Base): + NAME = "hardware.ipmi.node.power" + TYPE = sample.TYPE_GAUGE + UNIT = "W" + + def read_data(self): + return self.nodemanager.read_power_all() diff --git a/ceilometer/ipmi/pollsters/sensor.py b/ceilometer/ipmi/pollsters/sensor.py new file mode 100644 index 00000000..837aec3a --- /dev/null +++ b/ceilometer/ipmi/pollsters/sensor.py @@ -0,0 +1,97 @@ +# Copyright 2014 Intel +# +# Author: Zhai Edwin <edwin.zhai@intel.com> +# +# 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 oslo.config import cfg +from oslo.utils import timeutils + +from ceilometer.ipmi.notifications import ironic as parser +from ceilometer.ipmi.platform import ipmi_sensor +from ceilometer import plugin +from ceilometer import sample + +CONF = cfg.CONF +CONF.import_opt('host', 'ceilometer.service') + + +class InvalidSensorData(ValueError): + pass + + +class SensorPollster(plugin.PollsterBase): + + METRIC = None + + def __init__(self): + self.ipmi = ipmi_sensor.IPMISensor() + + @property + def default_discovery(self): + return None + + def _get_sensor_types(self, data, sensor_type): + try: + return (sensor_type_data for _, sensor_type_data + in data[sensor_type].items()) + except KeyError: + return [] + + def get_samples(self, manager, cache, resources): + stats = self.ipmi.read_sensor_any(self.METRIC) + + sensor_type_data = self._get_sensor_types(stats, self.METRIC) + + for sensor_data in sensor_type_data: + try: + sensor_reading = sensor_data['Sensor Reading'] + except KeyError: + raise InvalidSensorData("missing 'Sensor Reading'") + + if not parser.validate_reading(sensor_reading): + continue + + volume, unit = parser.parse_reading(sensor_reading) + + resource_id = '%(host)s-%(sensor-id)s' % { + 'host': CONF.host, + 'sensor-id': parser.transform_id(sensor_data['Sensor ID']) + } + + yield sample.Sample( + name='hardware.ipmi.%s' % self.METRIC.lower(), + type=sample.TYPE_GAUGE, + unit=unit, + volume=volume, + user_id=None, + project_id=None, + resource_id=resource_id, + timestamp=timeutils.utcnow().isoformat(), + resource_metadata=None) + + +class TemperatureSensorPollster(SensorPollster): + METRIC = 'Temperature' + + +class CurrentSensorPollster(SensorPollster): + METRIC = 'Current' + + +class FanSensorPollster(SensorPollster): + METRIC = 'Fan' + + +class VoltageSensorPollster(SensorPollster): + METRIC = 'Voltage' diff --git a/ceilometer/tests/hardware/notifications/ipmi_test_data.py b/ceilometer/tests/hardware/notifications/ipmi_test_data.py deleted file mode 100644 index 6cd42059..00000000 --- a/ceilometer/tests/hardware/notifications/ipmi_test_data.py +++ /dev/null @@ -1,785 +0,0 @@ -# -# Copyright 2014 Red Hat, Inc -# -# Author: Chris Dent <chdent@redhat.com> -# -# 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. -"""Sample data for test_ipmi. - -This data is provided as a sample of the data expected from the ipmitool -driver in the Ironic project, which is the publisher of the notifications -being tested. -""" - - -SENSOR_DATA = { - 'message_id': 'f22188ca-c068-47ce-a3e5-0e27ffe234c6', - 'publisher_id': 'f23188ca-c068-47ce-a3e5-0e27ffe234c6', - 'payload': { - 'instance_uuid': 'f11251ax-c568-25ca-4582-0x27add644c6', - 'timestamp': '20140223134852', - 'node_uuid': 'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad', - 'event_type': 'hardware.ipmi.metrics.update', - 'payload': { - 'Temperature': { - 'DIMM GH VR Temp (0x3b)': { - 'Status': 'ok', - 'Deassertions Enabled': 'unc+ ucr+ unr+', - 'Sensor Reading': '26 (+/- 0.500) degrees C', - 'Entity ID': '20.6 (Power Module)', - 'Assertions Enabled': 'unc+ ucr+ unr+', - 'Positive Hysteresis': '4.000', - 'Assertion Events': '', - 'Upper non-critical': '95.000', - 'Event Message Control': 'Per-threshold', - 'Upper non-recoverable': '105.000', - 'Normal Maximum': '112.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '100.000', - 'Sensor ID': 'DIMM GH VR Temp (0x3b)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '16.000' - }, - 'CPU1 VR Temp (0x36)': { - 'Status': 'ok', - 'Deassertions Enabled': 'unc+ ucr+ unr+', - 'Sensor Reading': '32 (+/- 0.500) degrees C', - 'Entity ID': '20.1 (Power Module)', - 'Assertions Enabled': 'unc+ ucr+ unr+', - 'Positive Hysteresis': '4.000', - 'Assertion Events': '', - 'Upper non-critical': '95.000', - 'Event Message Control': 'Per-threshold', - 'Upper non-recoverable': '105.000', - 'Normal Maximum': '112.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '100.000', - 'Sensor ID': 'CPU1 VR Temp (0x36)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '16.000' - }, - 'DIMM EF VR Temp (0x3a)': { - 'Status': 'ok', - 'Deassertions Enabled': 'unc+ ucr+ unr+', - 'Sensor Reading': '26 (+/- 0.500) degrees C', - 'Entity ID': '20.5 (Power Module)', - 'Assertions Enabled': 'unc+ ucr+ unr+', - 'Positive Hysteresis': '4.000', - 'Assertion Events': '', - 'Upper non-critical': '95.000', - 'Event Message Control': 'Per-threshold', - 'Upper non-recoverable': '105.000', - 'Normal Maximum': '112.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '100.000', - 'Sensor ID': 'DIMM EF VR Temp (0x3a)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '16.000' - }, - 'CPU2 VR Temp (0x37)': { - 'Status': 'ok', - 'Deassertions Enabled': 'unc+ ucr+ unr+', - 'Sensor Reading': '31 (+/- 0.500) degrees C', - 'Entity ID': '20.2 (Power Module)', - 'Assertions Enabled': 'unc+ ucr+ unr+', - 'Positive Hysteresis': '4.000', - 'Assertion Events': '', - 'Upper non-critical': '95.000', - 'Event Message Control': 'Per-threshold', - 'Upper non-recoverable': '105.000', - 'Normal Maximum': '112.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '100.000', - 'Sensor ID': 'CPU2 VR Temp (0x37)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '16.000' - }, - 'Ambient Temp (0x32)': { - 'Status': 'ok', - 'Sensor Reading': '25 (+/- 0) degrees C', - 'Entity ID': '12.1 (Front Panel Board)', - 'Assertions Enabled': 'unc+ ucr+ unr+', - 'Event Message Control': 'Per-threshold', - 'Assertion Events': '', - 'Upper non-critical': '43.000', - 'Deassertions Enabled': 'unc+ ucr+ unr+', - 'Upper non-recoverable': '50.000', - 'Positive Hysteresis': '4.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '46.000', - 'Sensor ID': 'Ambient Temp (0x32)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '25.000' - }, - 'Mezz Card Temp (0x35)': { - 'Status': 'Disabled', - 'Sensor Reading': 'Disabled', - 'Entity ID': '44.1 (I/O Module)', - 'Event Message Control': 'Per-threshold', - 'Upper non-critical': '70.000', - 'Upper non-recoverable': '85.000', - 'Positive Hysteresis': '4.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '80.000', - 'Sensor ID': 'Mezz Card Temp (0x35)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '25.000' - }, - 'PCH Temp (0x3c)': { - 'Status': 'ok', - 'Deassertions Enabled': 'unc+ ucr+ unr+', - 'Sensor Reading': '46 (+/- 0.500) degrees C', - 'Entity ID': '45.1 (Processor/IO Module)', - 'Assertions Enabled': 'unc+ ucr+ unr+', - 'Positive Hysteresis': '4.000', - 'Assertion Events': '', - 'Upper non-critical': '93.000', - 'Event Message Control': 'Per-threshold', - 'Upper non-recoverable': '103.000', - 'Normal Maximum': '112.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '98.000', - 'Sensor ID': 'PCH Temp (0x3c)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '16.000' - }, - 'DIMM CD VR Temp (0x39)': { - 'Status': 'ok', - 'Deassertions Enabled': 'unc+ ucr+ unr+', - 'Sensor Reading': '27 (+/- 0.500) degrees C', - 'Entity ID': '20.4 (Power Module)', - 'Assertions Enabled': 'unc+ ucr+ unr+', - 'Positive Hysteresis': '4.000', - 'Assertion Events': '', - 'Upper non-critical': '95.000', - 'Event Message Control': 'Per-threshold', - 'Upper non-recoverable': '105.000', - 'Normal Maximum': '112.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '100.000', - 'Sensor ID': 'DIMM CD VR Temp (0x39)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '16.000' - }, - 'PCI Riser 2 Temp (0x34)': { - 'Status': 'ok', - 'Deassertions Enabled': 'unc+ ucr+ unr+', - 'Sensor Reading': '30 (+/- 0) degrees C', - 'Entity ID': '16.2 (System Internal Expansion Board)', - 'Assertions Enabled': 'unc+ ucr+ unr+', - 'Positive Hysteresis': '4.000', - 'Assertion Events': '', - 'Upper non-critical': '70.000', - 'Event Message Control': 'Per-threshold', - 'Upper non-recoverable': '85.000', - 'Normal Maximum': '112.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '80.000', - 'Sensor ID': 'PCI Riser 2 Temp (0x34)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '16.000' - }, - 'DIMM AB VR Temp (0x38)': { - 'Status': 'ok', - 'Deassertions Enabled': 'unc+ ucr+ unr+', - 'Sensor Reading': '28 (+/- 0.500) degrees C', - 'Entity ID': '20.3 (Power Module)', - 'Assertions Enabled': 'unc+ ucr+ unr+', - 'Positive Hysteresis': '4.000', - 'Assertion Events': '', - 'Upper non-critical': '95.000', - 'Event Message Control': 'Per-threshold', - 'Upper non-recoverable': '105.000', - 'Normal Maximum': '112.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '100.000', - 'Sensor ID': 'DIMM AB VR Temp (0x38)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '16.000' - }, - 'PCI Riser 1 Temp (0x33)': { - 'Status': 'ok', - 'Deassertions Enabled': 'unc+ ucr+ unr+', - 'Sensor Reading': '38 (+/- 0) degrees C', - 'Entity ID': '16.1 (System Internal Expansion Board)', - 'Assertions Enabled': 'unc+ ucr+ unr+', - 'Positive Hysteresis': '4.000', - 'Assertion Events': '', - 'Upper non-critical': '70.000', - 'Event Message Control': 'Per-threshold', - 'Upper non-recoverable': '85.000', - 'Normal Maximum': '112.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '80.000', - 'Sensor ID': 'PCI Riser 1 Temp (0x33)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '16.000' - }, - }, - 'Current': { - 'Avg Power (0x2e)': { - 'Status': 'ok', - 'Sensor Reading': '130 (+/- 0) Watts', - 'Entity ID': '21.0 (Power Management)', - 'Assertions Enabled': '', - 'Event Message Control': 'Per-threshold', - 'Readable Thresholds': 'No Thresholds', - 'Positive Hysteresis': 'Unspecified', - 'Sensor Type (Analog)': 'Current', - 'Negative Hysteresis': 'Unspecified', - 'Maximum sensor range': 'Unspecified', - 'Sensor ID': 'Avg Power (0x2e)', - 'Assertion Events': '', - 'Minimum sensor range': '2550.000', - 'Settable Thresholds': 'No Thresholds' - } - }, - 'Fan': { - 'Fan 4A Tach (0x46)': { - 'Status': 'ok', - 'Sensor Reading': '6900 (+/- 0) RPM', - 'Entity ID': '29.4 (Fan Device)', - 'Assertions Enabled': 'lcr-', - 'Normal Minimum': '2580.000', - 'Positive Hysteresis': '120.000', - 'Assertion Events': '', - 'Event Message Control': 'Per-threshold', - 'Normal Maximum': '15300.000', - 'Deassertions Enabled': 'lcr-', - 'Sensor Type (Analog)': 'Fan', - 'Lower critical': '1920.000', - 'Negative Hysteresis': '120.000', - 'Threshold Read Mask': 'lcr', - 'Maximum sensor range': 'Unspecified', - 'Readable Thresholds': 'lcr', - 'Sensor ID': 'Fan 4A Tach (0x46)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '4020.000' - }, - 'Fan 5A Tach (0x48)': { - 'Status': 'ok', - 'Sensor Reading': '7140 (+/- 0) RPM', - 'Entity ID': '29.5 (Fan Device)', - 'Assertions Enabled': 'lcr-', - 'Normal Minimum': '2580.000', - 'Positive Hysteresis': '120.000', - 'Assertion Events': '', - 'Event Message Control': 'Per-threshold', - 'Normal Maximum': '15300.000', - 'Deassertions Enabled': 'lcr-', - 'Sensor Type (Analog)': 'Fan', - 'Lower critical': '1920.000', - 'Negative Hysteresis': '120.000', - 'Threshold Read Mask': 'lcr', - 'Maximum sensor range': 'Unspecified', - 'Readable Thresholds': 'lcr', - 'Sensor ID': 'Fan 5A Tach (0x48)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '4020.000' - }, - 'Fan 3A Tach (0x44)': { - 'Status': 'ok', - 'Sensor Reading': '6900 (+/- 0) RPM', - 'Entity ID': '29.3 (Fan Device)', - 'Assertions Enabled': 'lcr-', - 'Normal Minimum': '2580.000', - 'Positive Hysteresis': '120.000', - 'Assertion Events': '', - 'Event Message Control': 'Per-threshold', - 'Normal Maximum': '15300.000', - 'Deassertions Enabled': 'lcr-', - 'Sensor Type (Analog)': 'Fan', - 'Lower critical': '1920.000', - 'Negative Hysteresis': '120.000', - 'Threshold Read Mask': 'lcr', - 'Maximum sensor range': 'Unspecified', - 'Readable Thresholds': 'lcr', - 'Sensor ID': 'Fan 3A Tach (0x44)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '4020.000' - }, - 'Fan 1A Tach (0x40)': { - 'Status': 'ok', - 'Sensor Reading': '6960 (+/- 0) RPM', - 'Entity ID': '29.1 (Fan Device)', - 'Assertions Enabled': 'lcr-', - 'Normal Minimum': '2580.000', - 'Positive Hysteresis': '120.000', - 'Assertion Events': '', - 'Event Message Control': 'Per-threshold', - 'Normal Maximum': '15300.000', - 'Deassertions Enabled': 'lcr-', - 'Sensor Type (Analog)': 'Fan', - 'Lower critical': '1920.000', - 'Negative Hysteresis': '120.000', - 'Threshold Read Mask': 'lcr', - 'Maximum sensor range': 'Unspecified', - 'Readable Thresholds': 'lcr', - 'Sensor ID': 'Fan 1A Tach (0x40)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '4020.000' - }, - 'Fan 3B Tach (0x45)': { - 'Status': 'ok', - 'Sensor Reading': '7104 (+/- 0) RPM', - 'Entity ID': '29.3 (Fan Device)', - 'Assertions Enabled': 'lcr-', - 'Normal Minimum': '2752.000', - 'Positive Hysteresis': '128.000', - 'Assertion Events': '', - 'Event Message Control': 'Per-threshold', - 'Normal Maximum': '16320.000', - 'Deassertions Enabled': 'lcr-', - 'Sensor Type (Analog)': 'Fan', - 'Lower critical': '1920.000', - 'Negative Hysteresis': '128.000', - 'Threshold Read Mask': 'lcr', - 'Maximum sensor range': 'Unspecified', - 'Readable Thresholds': 'lcr', - 'Sensor ID': 'Fan 3B Tach (0x45)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '3968.000' - }, - 'Fan 2A Tach (0x42)': { - 'Status': 'ok', - 'Sensor Reading': '7080 (+/- 0) RPM', - 'Entity ID': '29.2 (Fan Device)', - 'Assertions Enabled': 'lcr-', - 'Normal Minimum': '2580.000', - 'Positive Hysteresis': '120.000', - 'Assertion Events': '', - 'Event Message Control': 'Per-threshold', - 'Normal Maximum': '15300.000', - 'Deassertions Enabled': 'lcr-', - 'Sensor Type (Analog)': 'Fan', - 'Lower critical': '1920.000', - 'Negative Hysteresis': '120.000', - 'Threshold Read Mask': 'lcr', - 'Maximum sensor range': 'Unspecified', - 'Readable Thresholds': 'lcr', - 'Sensor ID': 'Fan 2A Tach (0x42)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '4020.000' - }, - 'Fan 4B Tach (0x47)': { - 'Status': 'ok', - 'Sensor Reading': '7488 (+/- 0) RPM', - 'Entity ID': '29.4 (Fan Device)', - 'Assertions Enabled': 'lcr-', - 'Normal Minimum': '2752.000', - 'Positive Hysteresis': '128.000', - 'Assertion Events': '', - 'Event Message Control': 'Per-threshold', - 'Normal Maximum': '16320.000', - 'Deassertions Enabled': 'lcr-', - 'Sensor Type (Analog)': 'Fan', - 'Lower critical': '1920.000', - 'Negative Hysteresis': '128.000', - 'Threshold Read Mask': 'lcr', - 'Maximum sensor range': 'Unspecified', - 'Readable Thresholds': 'lcr', - 'Sensor ID': 'Fan 4B Tach (0x47)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '3968.000' - }, - 'Fan 2B Tach (0x43)': { - 'Status': 'ok', - 'Sensor Reading': '7168 (+/- 0) RPM', - 'Entity ID': '29.2 (Fan Device)', - 'Assertions Enabled': 'lcr-', - 'Normal Minimum': '2752.000', - 'Positive Hysteresis': '128.000', - 'Assertion Events': '', - 'Event Message Control': 'Per-threshold', - 'Normal Maximum': '16320.000', - 'Deassertions Enabled': 'lcr-', - 'Sensor Type (Analog)': 'Fan', - 'Lower critical': '1920.000', - 'Negative Hysteresis': '128.000', - 'Threshold Read Mask': 'lcr', - 'Maximum sensor range': 'Unspecified', - 'Readable Thresholds': 'lcr', - 'Sensor ID': 'Fan 2B Tach (0x43)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '3968.000' - }, - 'Fan 5B Tach (0x49)': { - 'Status': 'ok', - 'Sensor Reading': '7296 (+/- 0) RPM', - 'Entity ID': '29.5 (Fan Device)', - 'Assertions Enabled': 'lcr-', - 'Normal Minimum': '2752.000', - 'Positive Hysteresis': '128.000', - 'Assertion Events': '', - 'Event Message Control': 'Per-threshold', - 'Normal Maximum': '16320.000', - 'Deassertions Enabled': 'lcr-', - 'Sensor Type (Analog)': 'Fan', - 'Lower critical': '1920.000', - 'Negative Hysteresis': '128.000', - 'Threshold Read Mask': 'lcr', - 'Maximum sensor range': 'Unspecified', - 'Readable Thresholds': 'lcr', - 'Sensor ID': 'Fan 5B Tach (0x49)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '3968.000' - }, - 'Fan 1B Tach (0x41)': { - 'Status': 'ok', - 'Sensor Reading': '7296 (+/- 0) RPM', - 'Entity ID': '29.1 (Fan Device)', - 'Assertions Enabled': 'lcr-', - 'Normal Minimum': '2752.000', - 'Positive Hysteresis': '128.000', - 'Assertion Events': '', - 'Event Message Control': 'Per-threshold', - 'Normal Maximum': '16320.000', - 'Deassertions Enabled': 'lcr-', - 'Sensor Type (Analog)': 'Fan', - 'Lower critical': '1920.000', - 'Negative Hysteresis': '128.000', - 'Threshold Read Mask': 'lcr', - 'Maximum sensor range': 'Unspecified', - 'Readable Thresholds': 'lcr', - 'Sensor ID': 'Fan 1B Tach (0x41)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '3968.000' - }, - 'Fan 6B Tach (0x4b)': { - 'Status': 'ok', - 'Sensor Reading': '7616 (+/- 0) RPM', - 'Entity ID': '29.6 (Fan Device)', - 'Assertions Enabled': 'lcr-', - 'Normal Minimum': '2752.000', - 'Positive Hysteresis': '128.000', - 'Assertion Events': '', - 'Event Message Control': 'Per-threshold', - 'Normal Maximum': '16320.000', - 'Deassertions Enabled': 'lcr-', - 'Sensor Type (Analog)': 'Fan', - 'Lower critical': '1920.000', - 'Negative Hysteresis': '128.000', - 'Threshold Read Mask': 'lcr', - 'Maximum sensor range': 'Unspecified', - 'Readable Thresholds': 'lcr', - 'Sensor ID': 'Fan 6B Tach (0x4b)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '3968.000' - }, - 'Fan 6A Tach (0x4a)': { - 'Status': 'ok', - 'Sensor Reading': '7080 (+/- 0) RPM', - 'Entity ID': '29.6 (Fan Device)', - 'Assertions Enabled': 'lcr-', - 'Normal Minimum': '2580.000', - 'Positive Hysteresis': '120.000', - 'Assertion Events': '', - 'Event Message Control': 'Per-threshold', - 'Normal Maximum': '15300.000', - 'Deassertions Enabled': 'lcr-', - 'Sensor Type (Analog)': 'Fan', - 'Lower critical': '1920.000', - 'Negative Hysteresis': '120.000', - 'Threshold Read Mask': 'lcr', - 'Maximum sensor range': 'Unspecified', - 'Readable Thresholds': 'lcr', - 'Sensor ID': 'Fan 6A Tach (0x4a)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '4020.000' - } - }, - 'Voltage': { - 'Planar 12V (0x18)': { - 'Status': 'ok', - 'Sensor Reading': '12.312 (+/- 0) Volts', - 'Entity ID': '7.1 (System Board)', - 'Assertions Enabled': 'lcr- ucr+', - 'Event Message Control': 'Per-threshold', - 'Assertion Events': '', - 'Maximum sensor range': 'Unspecified', - 'Positive Hysteresis': '0.108', - 'Deassertions Enabled': 'lcr- ucr+', - 'Sensor Type (Analog)': 'Voltage', - 'Lower critical': '10.692', - 'Negative Hysteresis': '0.108', - 'Threshold Read Mask': 'lcr ucr', - 'Upper critical': '13.446', - 'Readable Thresholds': 'lcr ucr', - 'Sensor ID': 'Planar 12V (0x18)', - 'Settable Thresholds': 'lcr ucr', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '12.042' - }, - 'Planar 3.3V (0x16)': { - 'Status': 'ok', - 'Sensor Reading': '3.309 (+/- 0) Volts', - 'Entity ID': '7.1 (System Board)', - 'Assertions Enabled': 'lcr- ucr+', - 'Event Message Control': 'Per-threshold', - 'Assertion Events': '', - 'Maximum sensor range': 'Unspecified', - 'Positive Hysteresis': '0.028', - 'Deassertions Enabled': 'lcr- ucr+', - 'Sensor Type (Analog)': 'Voltage', - 'Lower critical': '3.039', - 'Negative Hysteresis': '0.028', - 'Threshold Read Mask': 'lcr ucr', - 'Upper critical': '3.564', - 'Readable Thresholds': 'lcr ucr', - 'Sensor ID': 'Planar 3.3V (0x16)', - 'Settable Thresholds': 'lcr ucr', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '3.309' - }, - 'Planar VBAT (0x1c)': { - 'Status': 'ok', - 'Sensor Reading': '3.137 (+/- 0) Volts', - 'Entity ID': '7.1 (System Board)', - 'Assertions Enabled': 'lnc- lcr-', - 'Event Message Control': 'Per-threshold', - 'Assertion Events': '', - 'Readable Thresholds': 'lcr lnc', - 'Positive Hysteresis': '0.025', - 'Deassertions Enabled': 'lnc- lcr-', - 'Sensor Type (Analog)': 'Voltage', - 'Lower critical': '2.095', - 'Negative Hysteresis': '0.025', - 'Lower non-critical': '2.248', - 'Maximum sensor range': 'Unspecified', - 'Sensor ID': 'Planar VBAT (0x1c)', - 'Settable Thresholds': 'lcr lnc', - 'Threshold Read Mask': 'lcr lnc', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '3.010' - }, - 'Planar 5V (0x17)': { - 'Status': 'ok', - 'Sensor Reading': '5.062 (+/- 0) Volts', - 'Entity ID': '7.1 (System Board)', - 'Assertions Enabled': 'lcr- ucr+', - 'Event Message Control': 'Per-threshold', - 'Assertion Events': '', - 'Maximum sensor range': 'Unspecified', - 'Positive Hysteresis': '0.045', - 'Deassertions Enabled': 'lcr- ucr+', - 'Sensor Type (Analog)': 'Voltage', - 'Lower critical': '4.475', - 'Negative Hysteresis': '0.045', - 'Threshold Read Mask': 'lcr ucr', - 'Upper critical': '5.582', - 'Readable Thresholds': 'lcr ucr', - 'Sensor ID': 'Planar 5V (0x17)', - 'Settable Thresholds': 'lcr ucr', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '4.995' - } - } - } - } -} - - -EMPTY_PAYLOAD = { - 'message_id': 'f22188ca-c068-47ce-a3e5-0e27ffe234c6', - 'publisher_id': 'f23188ca-c068-47ce-a3e5-0e27ffe234c6', - 'payload': { - 'instance_uuid': 'f11251ax-c568-25ca-4582-0x27add644c6', - 'timestamp': '20140223134852', - 'node_uuid': 'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad', - 'event_type': 'hardware.ipmi.metrics.update', - 'payload': { - } - } -} - - -MISSING_SENSOR = { - 'message_id': 'f22188ca-c068-47ce-a3e5-0e27ffe234c6', - 'publisher_id': 'f23188ca-c068-47ce-a3e5-0e27ffe234c6', - 'payload': { - 'instance_uuid': 'f11251ax-c568-25ca-4582-0x27add644c6', - 'timestamp': '20140223134852', - 'node_uuid': 'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad', - 'event_type': 'hardware.ipmi.metrics.update', - 'payload': { - 'Temperature': { - 'PCI Riser 1 Temp (0x33)': { - 'Status': 'ok', - 'Deassertions Enabled': 'unc+ ucr+ unr+', - 'Entity ID': '16.1 (System Internal Expansion Board)', - 'Assertions Enabled': 'unc+ ucr+ unr+', - 'Positive Hysteresis': '4.000', - 'Assertion Events': '', - 'Upper non-critical': '70.000', - 'Event Message Control': 'Per-threshold', - 'Upper non-recoverable': '85.000', - 'Normal Maximum': '112.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '80.000', - 'Sensor ID': 'PCI Riser 1 Temp (0x33)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '16.000' - }, - } - } - } -} - - -BAD_SENSOR = { - 'message_id': 'f22188ca-c068-47ce-a3e5-0e27ffe234c6', - 'publisher_id': 'f23188ca-c068-47ce-a3e5-0e27ffe234c6', - 'payload': { - 'instance_uuid': 'f11251ax-c568-25ca-4582-0x27add644c6', - 'timestamp': '20140223134852', - 'node_uuid': 'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad', - 'event_type': 'hardware.ipmi.metrics.update', - 'payload': { - 'Temperature': { - 'PCI Riser 1 Temp (0x33)': { - 'Status': 'ok', - 'Deassertions Enabled': 'unc+ ucr+ unr+', - 'Sensor Reading': 'some bad stuff', - 'Entity ID': '16.1 (System Internal Expansion Board)', - 'Assertions Enabled': 'unc+ ucr+ unr+', - 'Positive Hysteresis': '4.000', - 'Assertion Events': '', - 'Upper non-critical': '70.000', - 'Event Message Control': 'Per-threshold', - 'Upper non-recoverable': '85.000', - 'Normal Maximum': '112.000', - 'Maximum sensor range': 'Unspecified', - 'Sensor Type (Analog)': 'Temperature', - 'Readable Thresholds': 'unc ucr unr', - 'Negative Hysteresis': 'Unspecified', - 'Threshold Read Mask': 'unc ucr unr', - 'Upper critical': '80.000', - 'Sensor ID': 'PCI Riser 1 Temp (0x33)', - 'Settable Thresholds': '', - 'Minimum sensor range': 'Unspecified', - 'Nominal Reading': '16.000' - }, - } - } - } -} - - -NO_SENSOR_ID = { - 'message_id': 'f22188ca-c068-47ce-a3e5-0e27ffe234c6', - 'publisher_id': 'f23188ca-c068-47ce-a3e5-0e27ffe234c6', - 'payload': { - 'instance_uuid': 'f11251ax-c568-25ca-4582-0x27add644c6', - 'timestamp': '20140223134852', - 'node_uuid': 'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad', - 'event_type': 'hardware.ipmi.metrics.update', - 'payload': { - 'Temperature': { - 'PCI Riser 1 Temp (0x33)': { - 'Sensor Reading': '26 C', - }, - } - } - } -} - - -NO_NODE_ID = { - 'message_id': 'f22188ca-c068-47ce-a3e5-0e27ffe234c6', - 'publisher_id': 'f23188ca-c068-47ce-a3e5-0e27ffe234c6', - 'payload': { - 'instance_uuid': 'f11251ax-c568-25ca-4582-0x27add644c6', - 'timestamp': '20140223134852', - 'event_type': 'hardware.ipmi.metrics.update', - 'payload': { - 'Temperature': { - 'PCI Riser 1 Temp (0x33)': { - 'Sensor Reading': '26 C', - 'Sensor ID': 'PCI Riser 1 Temp (0x33)', - }, - } - } - } -} diff --git a/ceilometer/tests/ipmi/notifications/__init__.py b/ceilometer/tests/ipmi/notifications/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ceilometer/tests/ipmi/notifications/__init__.py diff --git a/ceilometer/tests/ipmi/notifications/ipmi_test_data.py b/ceilometer/tests/ipmi/notifications/ipmi_test_data.py new file mode 100644 index 00000000..ec3f455f --- /dev/null +++ b/ceilometer/tests/ipmi/notifications/ipmi_test_data.py @@ -0,0 +1,797 @@ +# +# Copyright 2014 Red Hat, Inc +# +# Author: Chris Dent <chdent@redhat.com> +# +# 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. +"""Sample data for test_ipmi. + +This data is provided as a sample of the data expected from the ipmitool +driver in the Ironic project, which is the publisher of the notifications +being tested. +""" + + +TEMPERATURE_DATA = { + 'DIMM GH VR Temp (0x3b)': { + 'Status': 'ok', + 'Deassertions Enabled': 'unc+ ucr+ unr+', + 'Sensor Reading': '26 (+/- 0.500) degrees C', + 'Entity ID': '20.6 (Power Module)', + 'Assertions Enabled': 'unc+ ucr+ unr+', + 'Positive Hysteresis': '4.000', + 'Assertion Events': '', + 'Upper non-critical': '95.000', + 'Event Message Control': 'Per-threshold', + 'Upper non-recoverable': '105.000', + 'Normal Maximum': '112.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '100.000', + 'Sensor ID': 'DIMM GH VR Temp (0x3b)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '16.000' + }, + 'CPU1 VR Temp (0x36)': { + 'Status': 'ok', + 'Deassertions Enabled': 'unc+ ucr+ unr+', + 'Sensor Reading': '32 (+/- 0.500) degrees C', + 'Entity ID': '20.1 (Power Module)', + 'Assertions Enabled': 'unc+ ucr+ unr+', + 'Positive Hysteresis': '4.000', + 'Assertion Events': '', + 'Upper non-critical': '95.000', + 'Event Message Control': 'Per-threshold', + 'Upper non-recoverable': '105.000', + 'Normal Maximum': '112.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '100.000', + 'Sensor ID': 'CPU1 VR Temp (0x36)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '16.000' + }, + 'DIMM EF VR Temp (0x3a)': { + 'Status': 'ok', + 'Deassertions Enabled': 'unc+ ucr+ unr+', + 'Sensor Reading': '26 (+/- 0.500) degrees C', + 'Entity ID': '20.5 (Power Module)', + 'Assertions Enabled': 'unc+ ucr+ unr+', + 'Positive Hysteresis': '4.000', + 'Assertion Events': '', + 'Upper non-critical': '95.000', + 'Event Message Control': 'Per-threshold', + 'Upper non-recoverable': '105.000', + 'Normal Maximum': '112.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '100.000', + 'Sensor ID': 'DIMM EF VR Temp (0x3a)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '16.000' + }, + 'CPU2 VR Temp (0x37)': { + 'Status': 'ok', + 'Deassertions Enabled': 'unc+ ucr+ unr+', + 'Sensor Reading': '31 (+/- 0.500) degrees C', + 'Entity ID': '20.2 (Power Module)', + 'Assertions Enabled': 'unc+ ucr+ unr+', + 'Positive Hysteresis': '4.000', + 'Assertion Events': '', + 'Upper non-critical': '95.000', + 'Event Message Control': 'Per-threshold', + 'Upper non-recoverable': '105.000', + 'Normal Maximum': '112.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '100.000', + 'Sensor ID': 'CPU2 VR Temp (0x37)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '16.000' + }, + 'Ambient Temp (0x32)': { + 'Status': 'ok', + 'Sensor Reading': '25 (+/- 0) degrees C', + 'Entity ID': '12.1 (Front Panel Board)', + 'Assertions Enabled': 'unc+ ucr+ unr+', + 'Event Message Control': 'Per-threshold', + 'Assertion Events': '', + 'Upper non-critical': '43.000', + 'Deassertions Enabled': 'unc+ ucr+ unr+', + 'Upper non-recoverable': '50.000', + 'Positive Hysteresis': '4.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '46.000', + 'Sensor ID': 'Ambient Temp (0x32)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '25.000' + }, + 'Mezz Card Temp (0x35)': { + 'Status': 'Disabled', + 'Sensor Reading': 'Disabled', + 'Entity ID': '44.1 (I/O Module)', + 'Event Message Control': 'Per-threshold', + 'Upper non-critical': '70.000', + 'Upper non-recoverable': '85.000', + 'Positive Hysteresis': '4.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '80.000', + 'Sensor ID': 'Mezz Card Temp (0x35)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '25.000' + }, + 'PCH Temp (0x3c)': { + 'Status': 'ok', + 'Deassertions Enabled': 'unc+ ucr+ unr+', + 'Sensor Reading': '46 (+/- 0.500) degrees C', + 'Entity ID': '45.1 (Processor/IO Module)', + 'Assertions Enabled': 'unc+ ucr+ unr+', + 'Positive Hysteresis': '4.000', + 'Assertion Events': '', + 'Upper non-critical': '93.000', + 'Event Message Control': 'Per-threshold', + 'Upper non-recoverable': '103.000', + 'Normal Maximum': '112.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '98.000', + 'Sensor ID': 'PCH Temp (0x3c)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '16.000' + }, + 'DIMM CD VR Temp (0x39)': { + 'Status': 'ok', + 'Deassertions Enabled': 'unc+ ucr+ unr+', + 'Sensor Reading': '27 (+/- 0.500) degrees C', + 'Entity ID': '20.4 (Power Module)', + 'Assertions Enabled': 'unc+ ucr+ unr+', + 'Positive Hysteresis': '4.000', + 'Assertion Events': '', + 'Upper non-critical': '95.000', + 'Event Message Control': 'Per-threshold', + 'Upper non-recoverable': '105.000', + 'Normal Maximum': '112.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '100.000', + 'Sensor ID': 'DIMM CD VR Temp (0x39)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '16.000' + }, + 'PCI Riser 2 Temp (0x34)': { + 'Status': 'ok', + 'Deassertions Enabled': 'unc+ ucr+ unr+', + 'Sensor Reading': '30 (+/- 0) degrees C', + 'Entity ID': '16.2 (System Internal Expansion Board)', + 'Assertions Enabled': 'unc+ ucr+ unr+', + 'Positive Hysteresis': '4.000', + 'Assertion Events': '', + 'Upper non-critical': '70.000', + 'Event Message Control': 'Per-threshold', + 'Upper non-recoverable': '85.000', + 'Normal Maximum': '112.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '80.000', + 'Sensor ID': 'PCI Riser 2 Temp (0x34)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '16.000' + }, + 'DIMM AB VR Temp (0x38)': { + 'Status': 'ok', + 'Deassertions Enabled': 'unc+ ucr+ unr+', + 'Sensor Reading': '28 (+/- 0.500) degrees C', + 'Entity ID': '20.3 (Power Module)', + 'Assertions Enabled': 'unc+ ucr+ unr+', + 'Positive Hysteresis': '4.000', + 'Assertion Events': '', + 'Upper non-critical': '95.000', + 'Event Message Control': 'Per-threshold', + 'Upper non-recoverable': '105.000', + 'Normal Maximum': '112.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '100.000', + 'Sensor ID': 'DIMM AB VR Temp (0x38)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '16.000' + }, + 'PCI Riser 1 Temp (0x33)': { + 'Status': 'ok', + 'Deassertions Enabled': 'unc+ ucr+ unr+', + 'Sensor Reading': '38 (+/- 0) degrees C', + 'Entity ID': '16.1 (System Internal Expansion Board)', + 'Assertions Enabled': 'unc+ ucr+ unr+', + 'Positive Hysteresis': '4.000', + 'Assertion Events': '', + 'Upper non-critical': '70.000', + 'Event Message Control': 'Per-threshold', + 'Upper non-recoverable': '85.000', + 'Normal Maximum': '112.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '80.000', + 'Sensor ID': 'PCI Riser 1 Temp (0x33)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '16.000' + }, +} + + +CURRENT_DATA = { + 'Avg Power (0x2e)': { + 'Status': 'ok', + 'Sensor Reading': '130 (+/- 0) Watts', + 'Entity ID': '21.0 (Power Management)', + 'Assertions Enabled': '', + 'Event Message Control': 'Per-threshold', + 'Readable Thresholds': 'No Thresholds', + 'Positive Hysteresis': 'Unspecified', + 'Sensor Type (Analog)': 'Current', + 'Negative Hysteresis': 'Unspecified', + 'Maximum sensor range': 'Unspecified', + 'Sensor ID': 'Avg Power (0x2e)', + 'Assertion Events': '', + 'Minimum sensor range': '2550.000', + 'Settable Thresholds': 'No Thresholds' + } +} + + +FAN_DATA = { + 'Fan 4A Tach (0x46)': { + 'Status': 'ok', + 'Sensor Reading': '6900 (+/- 0) RPM', + 'Entity ID': '29.4 (Fan Device)', + 'Assertions Enabled': 'lcr-', + 'Normal Minimum': '2580.000', + 'Positive Hysteresis': '120.000', + 'Assertion Events': '', + 'Event Message Control': 'Per-threshold', + 'Normal Maximum': '15300.000', + 'Deassertions Enabled': 'lcr-', + 'Sensor Type (Analog)': 'Fan', + 'Lower critical': '1920.000', + 'Negative Hysteresis': '120.000', + 'Threshold Read Mask': 'lcr', + 'Maximum sensor range': 'Unspecified', + 'Readable Thresholds': 'lcr', + 'Sensor ID': 'Fan 4A Tach (0x46)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '4020.000' + }, + 'Fan 5A Tach (0x48)': { + 'Status': 'ok', + 'Sensor Reading': '7140 (+/- 0) RPM', + 'Entity ID': '29.5 (Fan Device)', + 'Assertions Enabled': 'lcr-', + 'Normal Minimum': '2580.000', + 'Positive Hysteresis': '120.000', + 'Assertion Events': '', + 'Event Message Control': 'Per-threshold', + 'Normal Maximum': '15300.000', + 'Deassertions Enabled': 'lcr-', + 'Sensor Type (Analog)': 'Fan', + 'Lower critical': '1920.000', + 'Negative Hysteresis': '120.000', + 'Threshold Read Mask': 'lcr', + 'Maximum sensor range': 'Unspecified', + 'Readable Thresholds': 'lcr', + 'Sensor ID': 'Fan 5A Tach (0x48)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '4020.000' + }, + 'Fan 3A Tach (0x44)': { + 'Status': 'ok', + 'Sensor Reading': '6900 (+/- 0) RPM', + 'Entity ID': '29.3 (Fan Device)', + 'Assertions Enabled': 'lcr-', + 'Normal Minimum': '2580.000', + 'Positive Hysteresis': '120.000', + 'Assertion Events': '', + 'Event Message Control': 'Per-threshold', + 'Normal Maximum': '15300.000', + 'Deassertions Enabled': 'lcr-', + 'Sensor Type (Analog)': 'Fan', + 'Lower critical': '1920.000', + 'Negative Hysteresis': '120.000', + 'Threshold Read Mask': 'lcr', + 'Maximum sensor range': 'Unspecified', + 'Readable Thresholds': 'lcr', + 'Sensor ID': 'Fan 3A Tach (0x44)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '4020.000' + }, + 'Fan 1A Tach (0x40)': { + 'Status': 'ok', + 'Sensor Reading': '6960 (+/- 0) RPM', + 'Entity ID': '29.1 (Fan Device)', + 'Assertions Enabled': 'lcr-', + 'Normal Minimum': '2580.000', + 'Positive Hysteresis': '120.000', + 'Assertion Events': '', + 'Event Message Control': 'Per-threshold', + 'Normal Maximum': '15300.000', + 'Deassertions Enabled': 'lcr-', + 'Sensor Type (Analog)': 'Fan', + 'Lower critical': '1920.000', + 'Negative Hysteresis': '120.000', + 'Threshold Read Mask': 'lcr', + 'Maximum sensor range': 'Unspecified', + 'Readable Thresholds': 'lcr', + 'Sensor ID': 'Fan 1A Tach (0x40)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '4020.000' + }, + 'Fan 3B Tach (0x45)': { + 'Status': 'ok', + 'Sensor Reading': '7104 (+/- 0) RPM', + 'Entity ID': '29.3 (Fan Device)', + 'Assertions Enabled': 'lcr-', + 'Normal Minimum': '2752.000', + 'Positive Hysteresis': '128.000', + 'Assertion Events': '', + 'Event Message Control': 'Per-threshold', + 'Normal Maximum': '16320.000', + 'Deassertions Enabled': 'lcr-', + 'Sensor Type (Analog)': 'Fan', + 'Lower critical': '1920.000', + 'Negative Hysteresis': '128.000', + 'Threshold Read Mask': 'lcr', + 'Maximum sensor range': 'Unspecified', + 'Readable Thresholds': 'lcr', + 'Sensor ID': 'Fan 3B Tach (0x45)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '3968.000' + }, + 'Fan 2A Tach (0x42)': { + 'Status': 'ok', + 'Sensor Reading': '7080 (+/- 0) RPM', + 'Entity ID': '29.2 (Fan Device)', + 'Assertions Enabled': 'lcr-', + 'Normal Minimum': '2580.000', + 'Positive Hysteresis': '120.000', + 'Assertion Events': '', + 'Event Message Control': 'Per-threshold', + 'Normal Maximum': '15300.000', + 'Deassertions Enabled': 'lcr-', + 'Sensor Type (Analog)': 'Fan', + 'Lower critical': '1920.000', + 'Negative Hysteresis': '120.000', + 'Threshold Read Mask': 'lcr', + 'Maximum sensor range': 'Unspecified', + 'Readable Thresholds': 'lcr', + 'Sensor ID': 'Fan 2A Tach (0x42)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '4020.000' + }, + 'Fan 4B Tach (0x47)': { + 'Status': 'ok', + 'Sensor Reading': '7488 (+/- 0) RPM', + 'Entity ID': '29.4 (Fan Device)', + 'Assertions Enabled': 'lcr-', + 'Normal Minimum': '2752.000', + 'Positive Hysteresis': '128.000', + 'Assertion Events': '', + 'Event Message Control': 'Per-threshold', + 'Normal Maximum': '16320.000', + 'Deassertions Enabled': 'lcr-', + 'Sensor Type (Analog)': 'Fan', + 'Lower critical': '1920.000', + 'Negative Hysteresis': '128.000', + 'Threshold Read Mask': 'lcr', + 'Maximum sensor range': 'Unspecified', + 'Readable Thresholds': 'lcr', + 'Sensor ID': 'Fan 4B Tach (0x47)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '3968.000' + }, + 'Fan 2B Tach (0x43)': { + 'Status': 'ok', + 'Sensor Reading': '7168 (+/- 0) RPM', + 'Entity ID': '29.2 (Fan Device)', + 'Assertions Enabled': 'lcr-', + 'Normal Minimum': '2752.000', + 'Positive Hysteresis': '128.000', + 'Assertion Events': '', + 'Event Message Control': 'Per-threshold', + 'Normal Maximum': '16320.000', + 'Deassertions Enabled': 'lcr-', + 'Sensor Type (Analog)': 'Fan', + 'Lower critical': '1920.000', + 'Negative Hysteresis': '128.000', + 'Threshold Read Mask': 'lcr', + 'Maximum sensor range': 'Unspecified', + 'Readable Thresholds': 'lcr', + 'Sensor ID': 'Fan 2B Tach (0x43)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '3968.000' + }, + 'Fan 5B Tach (0x49)': { + 'Status': 'ok', + 'Sensor Reading': '7296 (+/- 0) RPM', + 'Entity ID': '29.5 (Fan Device)', + 'Assertions Enabled': 'lcr-', + 'Normal Minimum': '2752.000', + 'Positive Hysteresis': '128.000', + 'Assertion Events': '', + 'Event Message Control': 'Per-threshold', + 'Normal Maximum': '16320.000', + 'Deassertions Enabled': 'lcr-', + 'Sensor Type (Analog)': 'Fan', + 'Lower critical': '1920.000', + 'Negative Hysteresis': '128.000', + 'Threshold Read Mask': 'lcr', + 'Maximum sensor range': 'Unspecified', + 'Readable Thresholds': 'lcr', + 'Sensor ID': 'Fan 5B Tach (0x49)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '3968.000' + }, + 'Fan 1B Tach (0x41)': { + 'Status': 'ok', + 'Sensor Reading': '7296 (+/- 0) RPM', + 'Entity ID': '29.1 (Fan Device)', + 'Assertions Enabled': 'lcr-', + 'Normal Minimum': '2752.000', + 'Positive Hysteresis': '128.000', + 'Assertion Events': '', + 'Event Message Control': 'Per-threshold', + 'Normal Maximum': '16320.000', + 'Deassertions Enabled': 'lcr-', + 'Sensor Type (Analog)': 'Fan', + 'Lower critical': '1920.000', + 'Negative Hysteresis': '128.000', + 'Threshold Read Mask': 'lcr', + 'Maximum sensor range': 'Unspecified', + 'Readable Thresholds': 'lcr', + 'Sensor ID': 'Fan 1B Tach (0x41)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '3968.000' + }, + 'Fan 6B Tach (0x4b)': { + 'Status': 'ok', + 'Sensor Reading': '7616 (+/- 0) RPM', + 'Entity ID': '29.6 (Fan Device)', + 'Assertions Enabled': 'lcr-', + 'Normal Minimum': '2752.000', + 'Positive Hysteresis': '128.000', + 'Assertion Events': '', + 'Event Message Control': 'Per-threshold', + 'Normal Maximum': '16320.000', + 'Deassertions Enabled': 'lcr-', + 'Sensor Type (Analog)': 'Fan', + 'Lower critical': '1920.000', + 'Negative Hysteresis': '128.000', + 'Threshold Read Mask': 'lcr', + 'Maximum sensor range': 'Unspecified', + 'Readable Thresholds': 'lcr', + 'Sensor ID': 'Fan 6B Tach (0x4b)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '3968.000' + }, + 'Fan 6A Tach (0x4a)': { + 'Status': 'ok', + 'Sensor Reading': '7080 (+/- 0) RPM', + 'Entity ID': '29.6 (Fan Device)', + 'Assertions Enabled': 'lcr-', + 'Normal Minimum': '2580.000', + 'Positive Hysteresis': '120.000', + 'Assertion Events': '', + 'Event Message Control': 'Per-threshold', + 'Normal Maximum': '15300.000', + 'Deassertions Enabled': 'lcr-', + 'Sensor Type (Analog)': 'Fan', + 'Lower critical': '1920.000', + 'Negative Hysteresis': '120.000', + 'Threshold Read Mask': 'lcr', + 'Maximum sensor range': 'Unspecified', + 'Readable Thresholds': 'lcr', + 'Sensor ID': 'Fan 6A Tach (0x4a)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '4020.000' + } +} + + +VOLTAGE_DATA = { + 'Planar 12V (0x18)': { + 'Status': 'ok', + 'Sensor Reading': '12.312 (+/- 0) Volts', + 'Entity ID': '7.1 (System Board)', + 'Assertions Enabled': 'lcr- ucr+', + 'Event Message Control': 'Per-threshold', + 'Assertion Events': '', + 'Maximum sensor range': 'Unspecified', + 'Positive Hysteresis': '0.108', + 'Deassertions Enabled': 'lcr- ucr+', + 'Sensor Type (Analog)': 'Voltage', + 'Lower critical': '10.692', + 'Negative Hysteresis': '0.108', + 'Threshold Read Mask': 'lcr ucr', + 'Upper critical': '13.446', + 'Readable Thresholds': 'lcr ucr', + 'Sensor ID': 'Planar 12V (0x18)', + 'Settable Thresholds': 'lcr ucr', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '12.042' + }, + 'Planar 3.3V (0x16)': { + 'Status': 'ok', + 'Sensor Reading': '3.309 (+/- 0) Volts', + 'Entity ID': '7.1 (System Board)', + 'Assertions Enabled': 'lcr- ucr+', + 'Event Message Control': 'Per-threshold', + 'Assertion Events': '', + 'Maximum sensor range': 'Unspecified', + 'Positive Hysteresis': '0.028', + 'Deassertions Enabled': 'lcr- ucr+', + 'Sensor Type (Analog)': 'Voltage', + 'Lower critical': '3.039', + 'Negative Hysteresis': '0.028', + 'Threshold Read Mask': 'lcr ucr', + 'Upper critical': '3.564', + 'Readable Thresholds': 'lcr ucr', + 'Sensor ID': 'Planar 3.3V (0x16)', + 'Settable Thresholds': 'lcr ucr', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '3.309' + }, + 'Planar VBAT (0x1c)': { + 'Status': 'ok', + 'Sensor Reading': '3.137 (+/- 0) Volts', + 'Entity ID': '7.1 (System Board)', + 'Assertions Enabled': 'lnc- lcr-', + 'Event Message Control': 'Per-threshold', + 'Assertion Events': '', + 'Readable Thresholds': 'lcr lnc', + 'Positive Hysteresis': '0.025', + 'Deassertions Enabled': 'lnc- lcr-', + 'Sensor Type (Analog)': 'Voltage', + 'Lower critical': '2.095', + 'Negative Hysteresis': '0.025', + 'Lower non-critical': '2.248', + 'Maximum sensor range': 'Unspecified', + 'Sensor ID': 'Planar VBAT (0x1c)', + 'Settable Thresholds': 'lcr lnc', + 'Threshold Read Mask': 'lcr lnc', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '3.010' + }, + 'Planar 5V (0x17)': { + 'Status': 'ok', + 'Sensor Reading': '5.062 (+/- 0) Volts', + 'Entity ID': '7.1 (System Board)', + 'Assertions Enabled': 'lcr- ucr+', + 'Event Message Control': 'Per-threshold', + 'Assertion Events': '', + 'Maximum sensor range': 'Unspecified', + 'Positive Hysteresis': '0.045', + 'Deassertions Enabled': 'lcr- ucr+', + 'Sensor Type (Analog)': 'Voltage', + 'Lower critical': '4.475', + 'Negative Hysteresis': '0.045', + 'Threshold Read Mask': 'lcr ucr', + 'Upper critical': '5.582', + 'Readable Thresholds': 'lcr ucr', + 'Sensor ID': 'Planar 5V (0x17)', + 'Settable Thresholds': 'lcr ucr', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '4.995' + } +} + + +SENSOR_DATA = { + 'message_id': 'f22188ca-c068-47ce-a3e5-0e27ffe234c6', + 'publisher_id': 'f23188ca-c068-47ce-a3e5-0e27ffe234c6', + 'payload': { + 'instance_uuid': 'f11251ax-c568-25ca-4582-0x27add644c6', + 'timestamp': '20140223134852', + 'node_uuid': 'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad', + 'event_type': 'hardware.ipmi.metrics.update', + 'payload': { + 'Temperature': TEMPERATURE_DATA, + 'Current': CURRENT_DATA, + 'Fan': FAN_DATA, + 'Voltage': VOLTAGE_DATA + } + } +} + + +EMPTY_PAYLOAD = { + 'message_id': 'f22188ca-c068-47ce-a3e5-0e27ffe234c6', + 'publisher_id': 'f23188ca-c068-47ce-a3e5-0e27ffe234c6', + 'payload': { + 'instance_uuid': 'f11251ax-c568-25ca-4582-0x27add644c6', + 'timestamp': '20140223134852', + 'node_uuid': 'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad', + 'event_type': 'hardware.ipmi.metrics.update', + 'payload': { + } + } +} + + +MISSING_SENSOR = { + 'message_id': 'f22188ca-c068-47ce-a3e5-0e27ffe234c6', + 'publisher_id': 'f23188ca-c068-47ce-a3e5-0e27ffe234c6', + 'payload': { + 'instance_uuid': 'f11251ax-c568-25ca-4582-0x27add644c6', + 'timestamp': '20140223134852', + 'node_uuid': 'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad', + 'event_type': 'hardware.ipmi.metrics.update', + 'payload': { + 'Temperature': { + 'PCI Riser 1 Temp (0x33)': { + 'Status': 'ok', + 'Deassertions Enabled': 'unc+ ucr+ unr+', + 'Entity ID': '16.1 (System Internal Expansion Board)', + 'Assertions Enabled': 'unc+ ucr+ unr+', + 'Positive Hysteresis': '4.000', + 'Assertion Events': '', + 'Upper non-critical': '70.000', + 'Event Message Control': 'Per-threshold', + 'Upper non-recoverable': '85.000', + 'Normal Maximum': '112.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '80.000', + 'Sensor ID': 'PCI Riser 1 Temp (0x33)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '16.000' + }, + } + } + } +} + + +BAD_SENSOR = { + 'message_id': 'f22188ca-c068-47ce-a3e5-0e27ffe234c6', + 'publisher_id': 'f23188ca-c068-47ce-a3e5-0e27ffe234c6', + 'payload': { + 'instance_uuid': 'f11251ax-c568-25ca-4582-0x27add644c6', + 'timestamp': '20140223134852', + 'node_uuid': 'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad', + 'event_type': 'hardware.ipmi.metrics.update', + 'payload': { + 'Temperature': { + 'PCI Riser 1 Temp (0x33)': { + 'Status': 'ok', + 'Deassertions Enabled': 'unc+ ucr+ unr+', + 'Sensor Reading': 'some bad stuff', + 'Entity ID': '16.1 (System Internal Expansion Board)', + 'Assertions Enabled': 'unc+ ucr+ unr+', + 'Positive Hysteresis': '4.000', + 'Assertion Events': '', + 'Upper non-critical': '70.000', + 'Event Message Control': 'Per-threshold', + 'Upper non-recoverable': '85.000', + 'Normal Maximum': '112.000', + 'Maximum sensor range': 'Unspecified', + 'Sensor Type (Analog)': 'Temperature', + 'Readable Thresholds': 'unc ucr unr', + 'Negative Hysteresis': 'Unspecified', + 'Threshold Read Mask': 'unc ucr unr', + 'Upper critical': '80.000', + 'Sensor ID': 'PCI Riser 1 Temp (0x33)', + 'Settable Thresholds': '', + 'Minimum sensor range': 'Unspecified', + 'Nominal Reading': '16.000' + }, + } + } + } +} + + +NO_SENSOR_ID = { + 'message_id': 'f22188ca-c068-47ce-a3e5-0e27ffe234c6', + 'publisher_id': 'f23188ca-c068-47ce-a3e5-0e27ffe234c6', + 'payload': { + 'instance_uuid': 'f11251ax-c568-25ca-4582-0x27add644c6', + 'timestamp': '20140223134852', + 'node_uuid': 'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad', + 'event_type': 'hardware.ipmi.metrics.update', + 'payload': { + 'Temperature': { + 'PCI Riser 1 Temp (0x33)': { + 'Sensor Reading': '26 C', + }, + } + } + } +} + + +NO_NODE_ID = { + 'message_id': 'f22188ca-c068-47ce-a3e5-0e27ffe234c6', + 'publisher_id': 'f23188ca-c068-47ce-a3e5-0e27ffe234c6', + 'payload': { + 'instance_uuid': 'f11251ax-c568-25ca-4582-0x27add644c6', + 'timestamp': '20140223134852', + 'event_type': 'hardware.ipmi.metrics.update', + 'payload': { + 'Temperature': { + 'PCI Riser 1 Temp (0x33)': { + 'Sensor Reading': '26 C', + 'Sensor ID': 'PCI Riser 1 Temp (0x33)', + }, + } + } + } +} diff --git a/ceilometer/tests/hardware/notifications/test_ipmi.py b/ceilometer/tests/ipmi/notifications/test_ironic.py index ea85278a..81eecfd6 100644 --- a/ceilometer/tests/hardware/notifications/test_ipmi.py +++ b/ceilometer/tests/ipmi/notifications/test_ironic.py @@ -20,9 +20,9 @@ import mock from oslotest import base -from ceilometer.hardware.notifications import ipmi +from ceilometer.ipmi.notifications import ironic as ipmi from ceilometer import sample -from ceilometer.tests.hardware.notifications import ipmi_test_data +from ceilometer.tests.ipmi.notifications import ipmi_test_data class TestNotifications(base.BaseTestCase): @@ -144,7 +144,7 @@ class TestNotifications(base.BaseTestCase): self.assertEqual(0, len(counters), 'expected 0 readings') - @mock.patch('ceilometer.hardware.notifications.ipmi.LOG') + @mock.patch('ceilometer.ipmi.notifications.ironic.LOG') def test_missing_sensor_data(self, mylog): processor = ipmi.TemperatureSensorNotification(None) @@ -160,7 +160,7 @@ class TestNotifications(base.BaseTestCase): messages[0] ) - @mock.patch('ceilometer.hardware.notifications.ipmi.LOG') + @mock.patch('ceilometer.ipmi.notifications.ironic.LOG') def test_sensor_data_malformed(self, mylog): processor = ipmi.TemperatureSensorNotification(None) @@ -176,7 +176,7 @@ class TestNotifications(base.BaseTestCase): messages[0] ) - @mock.patch('ceilometer.hardware.notifications.ipmi.LOG') + @mock.patch('ceilometer.ipmi.notifications.ironic.LOG') def test_missing_node_uuid(self, mylog): """Test for desired error message when 'node_uuid' missing. @@ -196,7 +196,7 @@ class TestNotifications(base.BaseTestCase): messages[0] ) - @mock.patch('ceilometer.hardware.notifications.ipmi.LOG') + @mock.patch('ceilometer.ipmi.notifications.ironic.LOG') def test_missing_sensor_id(self, mylog): """Test for desired error message when 'Sensor ID' missing.""" processor = ipmi.TemperatureSensorNotification(None) diff --git a/ceilometer/tests/ipmi/pollsters/__init__.py b/ceilometer/tests/ipmi/pollsters/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ceilometer/tests/ipmi/pollsters/__init__.py diff --git a/ceilometer/tests/ipmi/pollsters/base.py b/ceilometer/tests/ipmi/pollsters/base.py new file mode 100644 index 00000000..76d0e260 --- /dev/null +++ b/ceilometer/tests/ipmi/pollsters/base.py @@ -0,0 +1,67 @@ +# Copyright 2014 Intel +# +# Author: Zhai Edwin <edwin.zhai@intel.com> +# +# 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 abc +import mock +import six + +from ceilometer.ipmi import manager +import ceilometer.tests.base as base + +from oslotest import mockpatch + + +@six.add_metaclass(abc.ABCMeta) +class TestPollsterBase(base.BaseTestCase): + + @abc.abstractmethod + def fake_data(self): + """Fake data used for test.""" + + @abc.abstractmethod + def fake_sensor_data(self, sensor_type): + """Fake sensor data used for test.""" + + @abc.abstractmethod + def make_pollster(self): + """Produce right pollster for test.""" + + def _test_get_samples(self): + nm = mock.Mock() + nm.read_temperature_all.side_effect = self.fake_data + nm.read_power_all.side_effect = self.fake_data + nm.read_sensor_any.side_effect = self.fake_sensor_data + + self.mgr = manager.AgentManager() + + self.useFixture(mockpatch.Patch( + 'ceilometer.ipmi.platform.intel_node_manager.NodeManager', + return_value=nm)) + + self.useFixture(mockpatch.Patch( + 'ceilometer.ipmi.platform.ipmi_sensor.IPMISensor', + return_value=nm)) + + self.pollster = self.make_pollster() + + def _verify_metering(self, length, expected_vol): + cache = {} + resources = {} + + samples = list(self.pollster.get_samples(self.mgr, cache, resources)) + self.assertEqual(length, len(samples)) + + self.assertTrue(any(s.volume == expected_vol for s in samples)) diff --git a/ceilometer/tests/ipmi/pollsters/test_node.py b/ceilometer/tests/ipmi/pollsters/test_node.py new file mode 100644 index 00000000..296e1a12 --- /dev/null +++ b/ceilometer/tests/ipmi/pollsters/test_node.py @@ -0,0 +1,62 @@ +# Copyright 2014 Intel Corp. +# +# Author: Zhai Edwin <edwin.zhai@intel.com> +# +# 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 mock + +from ceilometer.ipmi.pollsters import node +from ceilometer.tests.ipmi.pollsters import base + + +class TestPowerPollster(base.TestPollsterBase): + + def fake_data(self): + # data after parsing Intel Node Manager output + return {"Current_value": ['13', '00']} + + def fake_sensor_data(self, sensor_type): + # No use for this test + return None + + def make_pollster(self): + return node.PowerPollster() + + @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) + def test_get_samples(self): + self._test_get_samples() + + # only one sample, and value is 19(0x13 as current_value) + self._verify_metering(1, 19) + + +class TestTemperaturePollster(base.TestPollsterBase): + + def fake_data(self): + # data after parsing Intel Node Manager output + return {"Current_value": ['23', '00']} + + def fake_sensor_data(self, sensor_type): + # No use for this test + return None + + def make_pollster(self): + return node.TemperaturePollster() + + @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) + def test_get_samples(self): + self._test_get_samples() + + # only one sample, and value is 35(0x23 as current_value) + self._verify_metering(1, 35) diff --git a/ceilometer/tests/ipmi/pollsters/test_sensor.py b/ceilometer/tests/ipmi/pollsters/test_sensor.py new file mode 100644 index 00000000..eb7c9a7f --- /dev/null +++ b/ceilometer/tests/ipmi/pollsters/test_sensor.py @@ -0,0 +1,114 @@ +# Copyright 2014 Intel Corp. +# +# Author: Zhai Edwin <edwin.zhai@intel.com> +# +# 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 mock + +from ceilometer.ipmi.pollsters import sensor +from ceilometer.tests.ipmi.notifications import ipmi_test_data +from ceilometer.tests.ipmi.pollsters import base + + +TEMPERATURE_SENSOR_DATA = { + 'Temperature': ipmi_test_data.TEMPERATURE_DATA +} + +CURRENT_SENSOR_DATA = { + 'Current': ipmi_test_data.CURRENT_DATA +} + +FAN_SENSOR_DATA = { + 'Fan': ipmi_test_data.FAN_DATA +} + +VOLTAGE_SENSOR_DATA = { + 'Voltage': ipmi_test_data.VOLTAGE_DATA +} + + +class TestTemperatureSensorPollster(base.TestPollsterBase): + + def fake_sensor_data(self, sensor_type): + return TEMPERATURE_SENSOR_DATA + + def fake_data(self): + # No use for Sensor test + return None + + def make_pollster(self): + return sensor.TemperatureSensorPollster() + + @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) + def test_get_samples(self): + self._test_get_samples() + + self._verify_metering(10, float(32)) + + +class TestFanSensorPollster(base.TestPollsterBase): + + def fake_sensor_data(self, sensor_type): + return FAN_SENSOR_DATA + + def fake_data(self): + # No use for Sensor test + return None + + def make_pollster(self): + return sensor.FanSensorPollster() + + @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) + def test_get_samples(self): + self._test_get_samples() + + self._verify_metering(12, float(7140)) + + +class TestCurrentSensorPollster(base.TestPollsterBase): + + def fake_sensor_data(self, sensor_type): + return CURRENT_SENSOR_DATA + + def fake_data(self): + # No use for Sensor test + return None + + def make_pollster(self): + return sensor.CurrentSensorPollster() + + @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) + def test_get_samples(self): + self._test_get_samples() + + self._verify_metering(1, float(130)) + + +class TestVoltageSensorPollster(base.TestPollsterBase): + + def fake_sensor_data(self, sensor_type): + return VOLTAGE_SENSOR_DATA + + def fake_data(self): + # No use for Sensor test + return None + + def make_pollster(self): + return sensor.VoltageSensorPollster() + + @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) + def test_get_samples(self): + self._test_get_samples() + + self._verify_metering(4, float(3.309)) diff --git a/ceilometer/tests/ipmi/test_manager.py b/ceilometer/tests/ipmi/test_manager.py new file mode 100644 index 00000000..795fb0eb --- /dev/null +++ b/ceilometer/tests/ipmi/test_manager.py @@ -0,0 +1,42 @@ +# Copyright 2014 Intel Corp. +# +# Author: Zhai Edwin <edwin.zhai@intel.com> +# +# 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. +"""Tests for ceilometer/ipmi/manager.py +""" + +from ceilometer.ipmi import manager +from ceilometer.tests import agentbase + +import mock +from oslotest import base + + +class TestManager(base.BaseTestCase): + + @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) + def test_load_plugins(self): + mgr = manager.AgentManager() + self.assertIsNotNone(list(mgr.pollster_manager)) + + +class TestRunTasks(agentbase.BaseAgentManagerTestCase): + + @staticmethod + def create_manager(): + return manager.AgentManager() + + def setUp(self): + self.source_resources = True + super(TestRunTasks, self).setUp() diff --git a/doc/source/measurements.rst b/doc/source/measurements.rst index 96ac52d0..c8ff3dad 100644 --- a/doc/source/measurements.rst +++ b/doc/source/measurements.rst @@ -368,6 +368,21 @@ hardware.ipmi.current Gauge W current sensor notification hardware.ipmi.voltage Gauge V voltage sensor notification Sensor Voltage Reading ============================= ========== ====== ============== ============ ========================== +There is another way to retrieve IPMI data, by deploying the Ceilometer IPMI +agent on each IPMI-capable node in order to poll local sensor data. To avoid +duplication of metering data and unnecessary load on the IPMI interface, the +IPMI agent should not be deployed if the node is managed by Ironic and the +'conductor.send_sensor_data' option is set to true in the Ironic configuration. + +IPMI agent also retrieve following Node Manager meter besides original IPMI +sensor data: + +=============================== ========== ====== ============== ============ ========================== +Meter Type Unit Resource Origin Note +=============================== ========== ====== ============== ============ ========================== +hardware.ipmi.node.power Gauge W host ID pollster System Current Power +hardware.ipmi.node.temperature Gauge C host ID pollster System Current Temperature +=============================== ========== ====== ============== ============ ========================== Dynamically retrieving the Meters via ceilometer client ======================================================= @@ -73,10 +73,10 @@ ceilometer.notification = stack_crud = ceilometer.orchestration.notifications:StackCRUD data_processing = ceilometer.data_processing.notifications:DataProcessing profiler = ceilometer.profiler.notifications:ProfilerNotifications - hardware.ipmi.temperature = ceilometer.hardware.notifications.ipmi:TemperatureSensorNotification - hardware.ipmi.voltage = ceilometer.hardware.notifications.ipmi:VoltageSensorNotification - hardware.ipmi.current = ceilometer.hardware.notifications.ipmi:CurrentSensorNotification - hardware.ipmi.fan = ceilometer.hardware.notifications.ipmi:FanSensorNotification + hardware.ipmi.temperature = ceilometer.ipmi.notifications.ironic:TemperatureSensorNotification + hardware.ipmi.voltage = ceilometer.ipmi.notifications.ironic:VoltageSensorNotification + hardware.ipmi.current = ceilometer.ipmi.notifications.ironic:CurrentSensorNotification + hardware.ipmi.fan = ceilometer.ipmi.notifications.ironic:FanSensorNotification ceilometer.discover = local_instances = ceilometer.compute.discovery:InstanceDiscovery @@ -120,6 +120,14 @@ ceilometer.poll.compute = instance_flavor = ceilometer.compute.pollsters.instance:InstanceFlavorPollster memory.usage = ceilometer.compute.pollsters.memory:MemoryUsagePollster +ceilometer.poll.ipmi = + hardware.ipmi.node.power = ceilometer.ipmi.pollsters.node:PowerPollster + hardware.ipmi.node.temperature = ceilometer.ipmi.pollsters.node:TemperaturePollster + hardware.ipmi.temperature = ceilometer.ipmi.pollsters.sensor:TemperatureSensorPollster + hardware.ipmi.voltage = ceilometer.ipmi.pollsters.sensor:VoltageSensorPollster + hardware.ipmi.current = ceilometer.ipmi.pollsters.sensor:CurrentSensorPollster + hardware.ipmi.fan = ceilometer.ipmi.pollsters.sensor:FanSensorPollster + ceilometer.poll.central = ip.floating = ceilometer.network.floatingip:FloatingIPPollster image = ceilometer.image.glance:ImagePollster @@ -260,6 +268,7 @@ console_scripts = ceilometer-agent-central = ceilometer.cmd.agent_central:main ceilometer-agent-compute = ceilometer.cmd.agent_compute:main ceilometer-agent-notification = ceilometer.cmd.agent_notification:main + ceilometer-agent-ipmi = ceilometer.cmd.agent_ipmi:main ceilometer-send-sample = ceilometer.cli:send_sample ceilometer-dbsync = ceilometer.cmd.storage:dbsync ceilometer-expirer = ceilometer.cmd.storage:expirer |