Merge "Implement consuming ipmi notifications from Ironic"
This commit is contained in:
commit
93bb844c20
0
ceilometer/hardware/notifications/__init__.py
Normal file
0
ceilometer/hardware/notifications/__init__.py
Normal file
176
ceilometer/hardware/notifications/ipmi.py
Normal file
176
ceilometer/hardware/notifications/ipmi.py
Normal file
@ -0,0 +1,176 @@
|
||||
#
|
||||
# Copyright 2014 Red Hat
|
||||
#
|
||||
# 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.
|
||||
"""Converters for producing hardware sensor data sample messages from
|
||||
notification events.
|
||||
"""
|
||||
|
||||
from oslo.config import cfg
|
||||
from oslo import messaging
|
||||
|
||||
from ceilometer.openstack.common import log
|
||||
from ceilometer import plugin
|
||||
from ceilometer import sample
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
OPTS = [
|
||||
cfg.StrOpt('ironic_exchange',
|
||||
default='ironic',
|
||||
help='Exchange name for Ironic notifications.'),
|
||||
]
|
||||
|
||||
|
||||
cfg.CONF.register_opts(OPTS)
|
||||
|
||||
|
||||
# Map unit name to SI
|
||||
UNIT_MAP = {
|
||||
'Watts': 'W',
|
||||
'Volts': 'V',
|
||||
}
|
||||
|
||||
|
||||
class InvalidSensorData(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
class SensorNotification(plugin.NotificationBase):
|
||||
"""A generic class for extracting samples from sensor data notifications.
|
||||
|
||||
A notification message can contain multiple samples from multiple
|
||||
sensors, all with the same basic structure: the volume for the sample
|
||||
is found as part of the value of a 'Sensor Reading' key. The unit
|
||||
is in the same value.
|
||||
|
||||
Subclasses exist solely to allow flexibility with stevedore configuration.
|
||||
"""
|
||||
|
||||
event_types = ['hardware.ipmi.*']
|
||||
metric = None
|
||||
|
||||
@staticmethod
|
||||
def get_targets(conf):
|
||||
"""oslo.messaging.TargetS for this this plugin."""
|
||||
return [messaging.Target(topic=topic,
|
||||
exchange=conf.ironic_exchange)
|
||||
for topic in conf.notification_topics]
|
||||
|
||||
def _get_sample(self, message):
|
||||
try:
|
||||
return (payload for _, payload
|
||||
in message['payload'][self.metric].items())
|
||||
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):
|
||||
info = {}
|
||||
info['publisher_id'] = message['publisher_id']
|
||||
info['timestamp'] = message['payload']['timestamp']
|
||||
info['event_type'] = message['payload']['event_type']
|
||||
info['user_id'] = message['payload'].get('user_id')
|
||||
info['project_id'] = message['payload'].get('project_id')
|
||||
# NOTE(chdent): How much of the payload should we keep?
|
||||
info['payload'] = payload
|
||||
return info
|
||||
|
||||
def process_notification(self, message):
|
||||
"""Read and process a notification.
|
||||
|
||||
The guts of a message are in dict value of a 'payload' key
|
||||
which then itself has a payload key containing a dict of
|
||||
multiple sensor readings.
|
||||
|
||||
If expected keys in the payload are missing or values
|
||||
are not in the expected form for transformations,
|
||||
KeyError and ValueError are caught and the current
|
||||
sensor payload is skipped.
|
||||
"""
|
||||
payloads = self._get_sample(message['payload'])
|
||||
for payload in payloads:
|
||||
try:
|
||||
# Provide a fallback resource_id in case parts are missing.
|
||||
resource_id = 'missing id'
|
||||
try:
|
||||
resource_id = '%(nodeid)s-%(sensorid)s' % {
|
||||
'nodeid': message['payload']['node_uuid'],
|
||||
'sensorid': self._transform_id(payload['Sensor ID'])
|
||||
}
|
||||
except KeyError as exc:
|
||||
raise InvalidSensorData('missing key in payload: %s' % exc)
|
||||
|
||||
info = self._package_payload(message, payload)
|
||||
|
||||
try:
|
||||
sensor_reading = info['payload']['Sensor Reading']
|
||||
except KeyError as exc:
|
||||
raise InvalidSensorData(
|
||||
"missing 'Sensor Reading' in payload"
|
||||
)
|
||||
|
||||
if self._validate_reading(sensor_reading):
|
||||
volume, unit = self._parse_reading(sensor_reading)
|
||||
yield sample.Sample.from_notification(
|
||||
name='hardware.ipmi.%s' % self.metric.lower(),
|
||||
type=sample.TYPE_GAUGE,
|
||||
unit=unit,
|
||||
volume=volume,
|
||||
resource_id=resource_id,
|
||||
message=info,
|
||||
user_id=info['user_id'],
|
||||
project_id=info['project_id'])
|
||||
|
||||
except InvalidSensorData as exc:
|
||||
LOG.warn(
|
||||
'invalid sensor data for %(resource)s: %(error)s' %
|
||||
dict(resource=resource_id, error=exc)
|
||||
)
|
||||
continue
|
||||
|
||||
|
||||
class TemperatureSensorNotification(SensorNotification):
|
||||
metric = 'Temperature'
|
||||
|
||||
|
||||
class CurrentSensorNotification(SensorNotification):
|
||||
metric = 'Current'
|
||||
|
||||
|
||||
class FanSensorNotification(SensorNotification):
|
||||
metric = 'Fan'
|
||||
|
||||
|
||||
class VoltageSensorNotification(SensorNotification):
|
||||
metric = 'Voltage'
|
0
ceilometer/tests/hardware/notifications/__init__.py
Normal file
0
ceilometer/tests/hardware/notifications/__init__.py
Normal file
785
ceilometer/tests/hardware/notifications/ipmi_test_data.py
Normal file
785
ceilometer/tests/hardware/notifications/ipmi_test_data.py
Normal file
@ -0,0 +1,785 @@
|
||||
#
|
||||
# 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)',
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
213
ceilometer/tests/hardware/notifications/test_ipmi.py
Normal file
213
ceilometer/tests/hardware/notifications/test_ipmi.py
Normal file
@ -0,0 +1,213 @@
|
||||
#
|
||||
# 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.
|
||||
"""Tests for producing IPMI sample messages from notification events.
|
||||
"""
|
||||
|
||||
import mock
|
||||
|
||||
from ceilometer.hardware.notifications import ipmi
|
||||
from ceilometer.openstack.common import test
|
||||
from ceilometer import sample
|
||||
from ceilometer.tests.hardware.notifications import ipmi_test_data
|
||||
|
||||
|
||||
class TestNotifications(test.BaseTestCase):
|
||||
|
||||
def test_ipmi_temperature_notification(self):
|
||||
"""Test IPMI Temperature sensor data.
|
||||
|
||||
Based on the above test data the expected sample for a single
|
||||
temperature reading has::
|
||||
|
||||
* a resource_id composed from the node_uuid Sensor ID
|
||||
* a name composed from 'hardware.ipmi.' and 'temperature'
|
||||
* a volume from the first chunk of the Sensor Reading
|
||||
* a unit from the last chunk of the Sensor Reading
|
||||
* some readings are skipped if the value is 'Disabled'
|
||||
"""
|
||||
processor = ipmi.TemperatureSensorNotification(None)
|
||||
counters = dict([(counter.resource_id, counter) for counter in
|
||||
processor.process_notification(
|
||||
ipmi_test_data.SENSOR_DATA)])
|
||||
|
||||
self.assertEqual(10, len(counters),
|
||||
'expected 10 temperature readings')
|
||||
resource_id = (
|
||||
'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad-dimm_gh_vr_temp_(0x3b)'
|
||||
)
|
||||
test_counter = counters[resource_id]
|
||||
self.assertEqual(26.0, test_counter.volume)
|
||||
self.assertEqual('C', test_counter.unit)
|
||||
self.assertEqual(sample.TYPE_GAUGE, test_counter.type)
|
||||
self.assertEqual('hardware.ipmi.temperature', test_counter.name)
|
||||
self.assertEqual('hardware.ipmi.metrics.update',
|
||||
test_counter.resource_metadata['event_type'])
|
||||
|
||||
def test_ipmi_current_notification(self):
|
||||
"""Test IPMI Current sensor data.
|
||||
|
||||
A single current reading is effectively the same as temperature,
|
||||
modulo "current".
|
||||
"""
|
||||
processor = ipmi.CurrentSensorNotification(None)
|
||||
counters = dict([(counter.resource_id, counter) for counter in
|
||||
processor.process_notification(
|
||||
ipmi_test_data.SENSOR_DATA)])
|
||||
|
||||
self.assertEqual(1, len(counters), 'expected 1 current reading')
|
||||
resource_id = (
|
||||
'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad-avg_power_(0x2e)'
|
||||
)
|
||||
test_counter = counters[resource_id]
|
||||
self.assertEqual(130.0, test_counter.volume)
|
||||
self.assertEqual('W', test_counter.unit)
|
||||
self.assertEqual(sample.TYPE_GAUGE, test_counter.type)
|
||||
self.assertEqual('hardware.ipmi.current', test_counter.name)
|
||||
|
||||
def test_ipmi_fan_notification(self):
|
||||
"""Test IPMI Fan sensor data.
|
||||
|
||||
A single fan reading is effectively the same as temperature,
|
||||
modulo "fan".
|
||||
"""
|
||||
processor = ipmi.FanSensorNotification(None)
|
||||
counters = dict([(counter.resource_id, counter) for counter in
|
||||
processor.process_notification(
|
||||
ipmi_test_data.SENSOR_DATA)])
|
||||
|
||||
self.assertEqual(12, len(counters), 'expected 12 fan readings')
|
||||
resource_id = (
|
||||
'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad-fan_4a_tach_(0x46)'
|
||||
)
|
||||
test_counter = counters[resource_id]
|
||||
self.assertEqual(6900.0, test_counter.volume)
|
||||
self.assertEqual('RPM', test_counter.unit)
|
||||
self.assertEqual(sample.TYPE_GAUGE, test_counter.type)
|
||||
self.assertEqual('hardware.ipmi.fan', test_counter.name)
|
||||
|
||||
def test_ipmi_voltage_notification(self):
|
||||
"""Test IPMI Voltage sensor data.
|
||||
|
||||
A single voltage reading is effectively the same as temperature,
|
||||
modulo "voltage".
|
||||
"""
|
||||
processor = ipmi.VoltageSensorNotification(None)
|
||||
counters = dict([(counter.resource_id, counter) for counter in
|
||||
processor.process_notification(
|
||||
ipmi_test_data.SENSOR_DATA)])
|
||||
|
||||
self.assertEqual(4, len(counters), 'expected 4 volate readings')
|
||||
resource_id = (
|
||||
'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad-planar_vbat_(0x1c)'
|
||||
)
|
||||
test_counter = counters[resource_id]
|
||||
self.assertEqual(3.137, test_counter.volume)
|
||||
self.assertEqual('V', test_counter.unit)
|
||||
self.assertEqual(sample.TYPE_GAUGE, test_counter.type)
|
||||
self.assertEqual('hardware.ipmi.voltage', test_counter.name)
|
||||
|
||||
def test_disabed_skips_metric(self):
|
||||
"""Test that a meter which a disabled volume is skipped."""
|
||||
processor = ipmi.TemperatureSensorNotification(None)
|
||||
counters = dict([(counter.resource_id, counter) for counter in
|
||||
processor.process_notification(
|
||||
ipmi_test_data.SENSOR_DATA)])
|
||||
|
||||
self.assertEqual(10, len(counters),
|
||||
'expected 10 temperature readings')
|
||||
|
||||
resource_id = (
|
||||
'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad-mezz_card_temp_(0x35)'
|
||||
)
|
||||
|
||||
self.assertNotIn(resource_id, counters)
|
||||
|
||||
def test_empty_payload_no_metrics_success(self):
|
||||
processor = ipmi.TemperatureSensorNotification(None)
|
||||
counters = dict([(counter.resource_id, counter) for counter in
|
||||
processor.process_notification(
|
||||
ipmi_test_data.EMPTY_PAYLOAD)])
|
||||
|
||||
self.assertEqual(0, len(counters), 'expected 0 readings')
|
||||
|
||||
@mock.patch('ceilometer.hardware.notifications.ipmi.LOG')
|
||||
def test_missing_sensor_data(self, mylog):
|
||||
processor = ipmi.TemperatureSensorNotification(None)
|
||||
|
||||
messages = []
|
||||
mylog.warn = lambda *args: messages.extend(args)
|
||||
|
||||
list(processor.process_notification(ipmi_test_data.MISSING_SENSOR))
|
||||
|
||||
self.assertEqual(
|
||||
'invalid sensor data for '
|
||||
'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad-pci_riser_1_temp_(0x33): '
|
||||
"missing 'Sensor Reading' in payload",
|
||||
messages[0]
|
||||
)
|
||||
|
||||
@mock.patch('ceilometer.hardware.notifications.ipmi.LOG')
|
||||
def test_sensor_data_malformed(self, mylog):
|
||||
processor = ipmi.TemperatureSensorNotification(None)
|
||||
|
||||
messages = []
|
||||
mylog.warn = lambda *args: messages.extend(args)
|
||||
|
||||
list(processor.process_notification(ipmi_test_data.BAD_SENSOR))
|
||||
|
||||
self.assertEqual(
|
||||
'invalid sensor data for '
|
||||
'f4982fd2-2f2b-4bb5-9aff-48aac801d1ad-pci_riser_1_temp_(0x33): '
|
||||
'unable to parse sensor reading: some bad stuff',
|
||||
messages[0]
|
||||
)
|
||||
|
||||
@mock.patch('ceilometer.hardware.notifications.ipmi.LOG')
|
||||
def test_missing_node_uuid(self, mylog):
|
||||
"""Test for desired error message when 'node_uuid' missing.
|
||||
|
||||
Presumably this will never happen given the way the data
|
||||
is created, but better defensive than dead.
|
||||
"""
|
||||
processor = ipmi.TemperatureSensorNotification(None)
|
||||
|
||||
messages = []
|
||||
mylog.warn = lambda *args: messages.extend(args)
|
||||
|
||||
list(processor.process_notification(ipmi_test_data.NO_NODE_ID))
|
||||
|
||||
self.assertEqual(
|
||||
'invalid sensor data for missing id: missing key in payload: '
|
||||
"'node_uuid'",
|
||||
messages[0]
|
||||
)
|
||||
|
||||
@mock.patch('ceilometer.hardware.notifications.ipmi.LOG')
|
||||
def test_missing_sensor_id(self, mylog):
|
||||
"""Test for desired error message when 'Sensor ID' missing."""
|
||||
processor = ipmi.TemperatureSensorNotification(None)
|
||||
|
||||
messages = []
|
||||
mylog.warn = lambda *args: messages.extend(args)
|
||||
|
||||
list(processor.process_notification(ipmi_test_data.NO_SENSOR_ID))
|
||||
|
||||
self.assertEqual(
|
||||
'invalid sensor data for missing id: missing key in payload: '
|
||||
"'Sensor ID'",
|
||||
messages[0]
|
||||
)
|
@ -281,6 +281,23 @@ network.services.lb.incoming.bytes Cumulative B pool ID p
|
||||
network.services.lb.outgoing.bytes Cumulative B pool ID pollster Number of outgoing Bytes
|
||||
======================================= ========== ========== ========== ========= ==============================
|
||||
|
||||
Ironic Hardware IPMI Sensor Data
|
||||
================================
|
||||
|
||||
IPMI sensor data is not available by default in Ironic. To enable these meters
|
||||
see the `Ironic Installation Guide`_.
|
||||
|
||||
.. _Ironic Installation Guide: http://docs.openstack.org/developer/ironic/deploy/install-guide.html
|
||||
|
||||
============================= ========== ====== ============== ============ ==========================
|
||||
Meter Type Unit Resource Origin Note
|
||||
============================= ========== ====== ============== ============ ==========================
|
||||
hardware.ipmi.fan Gauge RPM fan sensor notification Fan RPM
|
||||
hardware.ipmi.temperature Gauge C temp sensor notification Sensor Temperature Reading
|
||||
hardware.ipmi.current Gauge W current sensor notification Sensor Current Reading
|
||||
hardware.ipmi.voltage Gauge V voltage sensor notification Sensor Voltage Reading
|
||||
============================= ========== ====== ============== ============ ==========================
|
||||
|
||||
|
||||
Dynamically retrieving the Meters via ceilometer client
|
||||
=======================================================
|
||||
|
@ -66,6 +66,10 @@ ceilometer.notification =
|
||||
http.response = ceilometer.middleware:HTTPResponse
|
||||
stack_crud = ceilometer.orchestration.notifications:StackCRUD
|
||||
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
|
||||
|
||||
ceilometer.discover =
|
||||
local_instances = ceilometer.compute.discovery:InstanceDiscovery
|
||||
|
Loading…
x
Reference in New Issue
Block a user