summaryrefslogtreecommitdiff
path: root/ironic/drivers/modules/redfish/management.py
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2019-06-13 19:01:18 +0200
committerIlya Etingof <etingof@gmail.com>2019-06-24 11:53:04 +0200
commit82abc0beacd3f8b4626ee1fab6634204af65a07b (patch)
treee66a3822f45281d8d411e6e7fef553d2b1f0070a /ironic/drivers/modules/redfish/management.py
parent9a0bd8a774143e6f767aaa3031be6b70554bc332 (diff)
downloadironic-82abc0beacd3f8b4626ee1fab6634204af65a07b.tar.gz
Collect sensor data in ``redfish`` hardware type
Adds sensor data collector to ``redfish`` management interface. Temperature, power, cooling and drive health metrics are collected. Change-Id: I8accdcc73c7e0261579d753633f9dfc02a868115 Story: 2005878 Task: 33692
Diffstat (limited to 'ironic/drivers/modules/redfish/management.py')
-rw-r--r--ironic/drivers/modules/redfish/management.py151
1 files changed, 147 insertions, 4 deletions
diff --git a/ironic/drivers/modules/redfish/management.py b/ironic/drivers/modules/redfish/management.py
index 3c86fde57..56f35ba60 100644
--- a/ironic/drivers/modules/redfish/management.py
+++ b/ironic/drivers/modules/redfish/management.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import collections
+
from oslo_log import log
from oslo_utils import importutils
@@ -222,14 +224,155 @@ class RedfishManagement(base.ManagementInterface):
return BOOT_MODE_MAP.get(system.boot.get('mode'))
+ @staticmethod
+ def _sensor2dict(resource, *fields):
+ return {field: getattr(resource, field)
+ for field in fields
+ if hasattr(resource, field)}
+
+ @classmethod
+ def _get_sensors_fan(cls, chassis):
+ """Get fan sensors reading.
+
+ :param chassis: Redfish `chassis` object
+ :returns: returns a dict of sensor data.
+ """
+ sensors = {}
+
+ for fan in chassis.thermal.fans.get_members():
+ sensor = cls._sensor2dict(
+ fan, 'identity', 'max_reading_range',
+ 'min_reading_range', 'reading', 'reading_units',
+ 'serial_number', 'physical_context')
+ sensor.update(cls._sensor2dict(fan.status, 'state', 'health'))
+ unique_name = '%s@%s' % (fan.identity, chassis.identity)
+ sensors[unique_name] = sensor
+
+ return sensors
+
+ @classmethod
+ def _get_sensors_temperatures(cls, chassis):
+ """Get temperature sensors reading.
+
+ :param chassis: Redfish `chassis` object
+ :returns: returns a dict of sensor data.
+ """
+ sensors = {}
+
+ for temps in chassis.thermal.temperatures.get_members():
+ sensor = cls._sensor2dict(
+ temps, 'identity', 'max_reading_range_temp',
+ 'min_reading_range_temp', 'reading_celsius',
+ 'physical_context', 'sensor_number')
+ sensor.update(cls._sensor2dict(temps.status, 'state', 'health'))
+ unique_name = '%s@%s' % (temps.identity, chassis.identity)
+ sensors[unique_name] = sensor
+
+ return sensors
+
+ @classmethod
+ def _get_sensors_power(cls, chassis):
+ """Get power supply sensors reading.
+
+ :param chassis: Redfish `chassis` object
+ :returns: returns a dict of sensor data.
+ """
+ sensors = {}
+
+ for power in chassis.power.power_supplies:
+ sensor = cls._sensor2dict(
+ power, 'power_capacity_watts',
+ 'line_input_voltage', 'last_power_output_watts',
+ 'serial_number')
+ sensor.update(cls._sensor2dict(power.status, 'state', 'health'))
+ sensor.update(cls._sensor2dict(
+ power.input_ranges, 'minimum_voltage',
+ 'maximum_voltage', 'minimum_frequency_hz',
+ 'maximum_frequency_hz', 'output_wattage'))
+ unique_name = '%s:%s@%s' % (
+ power.member_id, chassis.power.identity,
+ chassis.identity)
+ sensors[unique_name] = sensor
+
+ return sensors
+
+ @classmethod
+ def _get_sensors_drive(cls, system):
+ """Get storage drive sensors reading.
+
+ :param chassis: Redfish `system` object
+ :returns: returns a dict of sensor data.
+ """
+ sensors = {}
+
+ for storage in system.simple_storage.get_members():
+ for drive in storage.devices:
+ sensor = cls._sensor2dict(
+ drive, 'identity', 'model', 'capacity_bytes',
+ 'failure_predicted')
+ sensor.update(
+ cls._sensor2dict(drive.status, 'state', 'health'))
+ unique_name = '%s:%s@%s' % (
+ drive.identity, system.simple_storage.identity,
+ system.identity)
+ sensors[unique_name] = sensor
+
+ return sensors
+
def get_sensors_data(self, task):
"""Get sensors data.
- Not implemented for this driver.
-
- :raises: NotImplementedError
+ :param task: a TaskManager instance.
+ :raises: FailedToGetSensorData when getting the sensor data fails.
+ :raises: FailedToParseSensorData when parsing sensor data fails.
+ :raises: InvalidParameterValue if required parameters
+ are missing.
+ :raises: MissingParameterValue if a required parameter is missing.
+ :returns: returns a dict of sensor data grouped by sensor type.
"""
- raise NotImplementedError()
+ node = task.node
+
+ sensors = collections.defaultdict(dict)
+
+ system = redfish_utils.get_system(node)
+
+ for chassis in system.chassis:
+ try:
+ sensors['Fan'].update(self._get_sensors_fan(chassis))
+
+ except sushy.exceptions.SushyError as exc:
+ LOG.debug("Failed reading fan information for node "
+ "%(node)s: %(error)s", {'node': node.uuid,
+ 'error': exc})
+
+ try:
+ sensors['Temperature'].update(
+ self._get_sensors_temperatures(chassis))
+
+ except sushy.exceptions.SushyError as exc:
+ LOG.debug("Failed reading temperature information for node "
+ "%(node)s: %(error)s", {'node': node.uuid,
+ 'error': exc})
+
+ try:
+ sensors['Power'].update(self._get_sensors_power(chassis))
+
+ except sushy.exceptions.SushyError as exc:
+ LOG.debug("Failed reading power information for node "
+ "%(node)s: %(error)s", {'node': node.uuid,
+ 'error': exc})
+
+ try:
+ sensors['Drive'].update(self._get_sensors_drive(system))
+
+ except sushy.exceptions.SushyError as exc:
+ LOG.debug("Failed reading drive information for node "
+ "%(node)s: %(error)s", {'node': node.uuid,
+ 'error': exc})
+
+ LOG.debug("Gathered sensor data: %(sensors)s", {'sensors': sensors})
+
+ return sensors
@task_manager.require_exclusive_lock
def inject_nmi(self, task):