2
# Licensed under the Apache License, Version 2.0 (the "License"); you may
3
# not use this file except in compliance with the License. You may obtain
4
# a copy of the License at
6
# http://www.apache.org/licenses/LICENSE-2.0
8
# Unless required by applicable law or agreed to in writing, software
9
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
# License for the specific language governing permissions and limitations
14
iRMC Management Driver
17
from oslo_utils import importutils
19
from ironic.common import boot_devices
20
from ironic.common import exception
21
from ironic.common.i18n import _
22
from ironic.common.i18n import _LE
23
from ironic.conductor import task_manager
24
from ironic.drivers.modules import ipmitool
25
from ironic.drivers.modules.irmc import common as irmc_common
26
from ironic.drivers import utils as driver_utils
27
from ironic.openstack.common import log as logging
29
scci = importutils.try_import('scciclient.irmc.scci')
31
LOG = logging.getLogger(__name__)
33
# Boot Option Parameters #5 Data2 defined in
34
# Set/Get System Boot Options Command, IPMI spec v2.0.
35
_BOOTPARAM5_DATA2 = {boot_devices.PXE: '0x04',
36
boot_devices.DISK: '0x08',
37
boot_devices.CDROM: '0x14',
38
boot_devices.BIOS: '0x18',
39
boot_devices.SAFE: '0x0c',
43
def _get_sensors_data(task):
44
"""Get sensors data method.
46
It gets sensor data from the task's node via SCCI, and convert the data
47
from XML to the dict format.
49
:param task: A TaskManager instance.
50
:raises: FailedToGetSensorData when getting the sensor data fails.
51
:returns: Returns a consistent formatted dict of sensor data grouped
52
by sensor type, which can be processed by Ceilometer.
56
report = irmc_common.get_irmc_report(task.node)
57
sensor = scci.get_sensor_data(report)
59
except Exception as e:
60
LOG.error(_LE("SCCI get sensor data failed for node %(node_id)s "
61
"with the following error: %(error)s"),
62
{'node_id': task.node.uuid, 'error': e})
63
raise exception.FailedToGetSensorData(
64
node=task.node.uuid, error=e)
68
sensor_type_name = sdr.find('./Data/Decoded/Sensor/TypeName')
69
sensor_type_number = sdr.find('./Data/Decoded/Sensor/Type')
70
entity_name = sdr.find('./Data/Decoded/Entity/Name')
71
entity_id = sdr.find('./Data/Decoded/Entity/ID')
73
if None in (sensor_type_name, sensor_type_number,
74
entity_name, entity_id):
77
sensor_type = ('%s (%s)' %
78
(sensor_type_name.text, sensor_type_number.text))
79
sensor_id = ('%s (%s)' %
80
(entity_name.text, entity_id.text))
81
reading_value = sdr.find(
82
'./Data/Decoded/Sensor/Thresholds/*/Normalized')
83
reading_value_text = "None" if (
84
reading_value is None) else str(reading_value.text)
85
reading_units = sdr.find('./Data/Decoded/Sensor/BaseUnitName')
86
reading_units_text = "None" if (
87
reading_units is None) else str(reading_units.text)
88
sensor_reading = '%s %s' % (reading_value_text, reading_units_text)
90
sensors_data.setdefault(sensor_type, {})[sensor_id] = {
91
'Sensor Reading': sensor_reading,
92
'Sensor ID': sensor_id,
93
'Units': reading_units_text,
99
class IRMCManagement(ipmitool.IPMIManagement):
101
def get_properties(self):
102
"""Return the properties of the interface.
104
:returns: Dictionary of <property name>:<property description> entries.
106
return irmc_common.COMMON_PROPERTIES
108
def validate(self, task):
109
"""Validate the driver-specific management information.
111
This method validates whether the 'driver_info' property of the
112
supplied node contains the required information for this driver.
114
:param task: A TaskManager instance containing the node to act on.
115
:raises: InvalidParameterValue if required parameters are invalid.
116
:raises: MissingParameterValue if a required parameter is missing.
118
irmc_common.parse_driver_info(task.node)
119
irmc_common.update_ipmi_properties(task)
120
super(IRMCManagement, self).validate(task)
122
@task_manager.require_exclusive_lock
123
def set_boot_device(self, task, device, persistent=False):
124
"""Set the boot device for a node.
126
Set the boot device to use on next reboot of the node.
128
:param task: A task from TaskManager.
129
:param device: The boot device, one of the supported devices
130
listed in :mod:`ironic.common.boot_devices`.
131
:param persistent: Boolean value. True if the boot device will
132
persist to all future boots, False if not.
134
:raises: InvalidParameterValue if an invalid boot device is
136
:raises: MissingParameterValue if a required parameter is missing.
137
:raises: IPMIFailure on an error from ipmitool.
140
if driver_utils.get_node_capability(task.node, 'boot_mode') == 'uefi':
141
if device not in self.get_supported_boot_devices():
142
raise exception.InvalidParameterValue(_(
143
"Invalid boot device %s specified.") % device)
144
timeout_disable = "0x00 0x08 0x03 0x08"
145
ipmitool.send_raw(task, timeout_disable)
147
# note(naohirot): As of ipmitool version 1.8.13,
148
# in case of chassis command, the efiboot option doesn't
149
# get set with persistent at the same time.
150
# $ ipmitool chassis bootdev pxe options=efiboot,persistent
151
# In case of raw command, however, both can be set at the
153
# $ ipmitool raw 0x00 0x08 0x05 0xe0 0x04 0x00 0x00 0x00
155
# ipmi cmd '0x08' : Set System Boot Options
156
# data1 '0xe0' : persistent and uefi
157
# data1 '0xa0' : next boot only and uefi
159
data1 = '0xe0' if persistent else '0xa0'
160
bootparam5 = '0x00 0x08 0x05 %s %s 0x00 0x00 0x00'
161
cmd08 = bootparam5 % (data1, _BOOTPARAM5_DATA2[device])
162
ipmitool.send_raw(task, cmd08)
165
super(IRMCManagement, self).set_boot_device(
166
task, device, persistent)
168
def get_sensors_data(self, task):
169
"""Get sensors data method.
171
It gets sensor data from the task's node via SCCI, and convert the data
172
from XML to the dict format.
174
:param task: A TaskManager instance.
175
:raises: FailedToGetSensorData when getting the sensor data fails.
176
:raises: FailedToParseSensorData when parsing sensor data fails.
177
:raises: InvalidParameterValue if required parameters are invalid.
178
:raises: MissingParameterValue if a required parameter is missing.
179
:returns: Returns a consistent formatted dict of sensor data grouped
180
by sensor type, which can be processed by Ceilometer.
185
'Sensor Reading': 'Value1 Units1',
186
'Sensor ID': 'Sensor ID 1',
190
'Sensor Reading': 'Value2 Units2',
191
'Sensor ID': 'Sensor ID 2',
197
'Sensor Reading': 'Value3 Units3',
198
'Sensor ID': 'Sensor ID 3',
202
'Sensor Reading': 'Value4 Units4',
203
'Sensor ID': 'Sensor ID 4',
210
# irmc_common.parse_driver_info() makes sure that
211
# d_info['irmc_sensor_method'] is either 'scci' or 'ipmitool'.
212
d_info = irmc_common.parse_driver_info(task.node)
213
sensor_method = d_info['irmc_sensor_method']
214
if sensor_method == 'scci':
215
return _get_sensors_data(task)
216
elif sensor_method == 'ipmitool':
217
return super(IRMCManagement, self).get_sensors_data(task)