diff options
Diffstat (limited to 'ironic/drivers/modules/irmc/management.py')
-rw-r--r-- | ironic/drivers/modules/irmc/management.py | 289 |
1 files changed, 254 insertions, 35 deletions
diff --git a/ironic/drivers/modules/irmc/management.py b/ironic/drivers/modules/irmc/management.py index 079ae9e44..cf146f2cd 100644 --- a/ironic/drivers/modules/irmc/management.py +++ b/ironic/drivers/modules/irmc/management.py @@ -27,9 +27,10 @@ from ironic.conductor import task_manager from ironic.conductor import utils as manager_utils from ironic import conf from ironic.drivers import base +from ironic.drivers.modules import boot_mode_utils from ironic.drivers.modules import ipmitool from ironic.drivers.modules.irmc import common as irmc_common -from ironic.drivers import utils as driver_utils +from ironic.drivers.modules.redfish import management as redfish_management irmc = importutils.try_import('scciclient.irmc') @@ -204,7 +205,8 @@ def _restore_bios_config(task): manager_utils.node_power_action(task, states.POWER_ON) -class IRMCManagement(ipmitool.IPMIManagement): +class IRMCManagement(ipmitool.IPMIManagement, + redfish_management.RedfishManagement): def get_properties(self): """Return the properties of the interface. @@ -224,9 +226,30 @@ class IRMCManagement(ipmitool.IPMIManagement): :raises: InvalidParameterValue if required parameters are invalid. :raises: MissingParameterValue if a required parameter is missing. """ - irmc_common.parse_driver_info(task.node) - irmc_common.update_ipmi_properties(task) - super(IRMCManagement, self).validate(task) + if task.node.driver_internal_info.get('irmc_ipmi_succeed'): + irmc_common.parse_driver_info(task.node) + irmc_common.update_ipmi_properties(task) + super(IRMCManagement, self).validate(task) + else: + irmc_common.parse_driver_info(task.node) + super(ipmitool.IPMIManagement, self).validate(task) + + def get_supported_boot_devices(self, task): + """Get list of supported boot devices + + Actual code is delegated to IPMIManagement or RedfishManagement + based on iRMC firmware version. + + :param task: A TaskManager instance + :returns: A list with the supported boot devices defined + in :mod:`ironic.common.boot_devices`. + + """ + if task.node.driver_internal_info.get('irmc_ipmi_succeed'): + return super(IRMCManagement, self).get_supported_boot_devices(task) + else: + return super(ipmitool.IPMIManagement, + self).get_supported_boot_devices(task) @METRICS.timer('IRMCManagement.set_boot_device') @task_manager.require_exclusive_lock @@ -245,39 +268,112 @@ class IRMCManagement(ipmitool.IPMIManagement): specified. :raises: MissingParameterValue if a required parameter is missing. :raises: IPMIFailure on an error from ipmitool. + :raises: RedfishConnectionError on Redfish operation failure. + :raises: RedfishError on Redfish operation failure. + """ + if task.node.driver_internal_info.get('irmc_ipmi_succeed'): + if device not in self.get_supported_boot_devices(task): + raise exception.InvalidParameterValue(_( + "Invalid boot device %s specified.") % device) + + uefi_mode = ( + boot_mode_utils.get_boot_mode(task.node) == 'uefi') + + # disable 60 secs timer + timeout_disable = "0x00 0x08 0x03 0x08" + ipmitool.send_raw(task, timeout_disable) + + # note(naohirot): + # Set System Boot Options : ipmi cmd '0x08', bootparam '0x05' + # + # $ ipmitool raw 0x00 0x08 0x05 data1 data2 0x00 0x00 0x00 + # + # data1 : '0xe0' persistent + uefi + # '0xc0' persistent + bios + # '0xa0' next only + uefi + # '0x80' next only + bios + # data2 : boot device defined in the dict _BOOTPARAM5_DATA2 + + bootparam5 = '0x00 0x08 0x05 %s %s 0x00 0x00 0x00' + if persistent: + data1 = '0xe0' if uefi_mode else '0xc0' + else: + data1 = '0xa0' if uefi_mode else '0x80' + data2 = _BOOTPARAM5_DATA2[device] + + cmd8 = bootparam5 % (data1, data2) + ipmitool.send_raw(task, cmd8) + else: + if device not in self.get_supported_boot_devices(task): + raise exception.InvalidParameterValue(_( + "Invalid boot device %s specified. " + "Current iRMC firmware condition doesn't support IPMI " + "but Redfish.") % device) + super(ipmitool.IPMIManagement, self).set_boot_device( + task, device, persistent) + + def get_boot_device(self, task): + """Get the current boot device for the task's node. + Returns the current boot device of the node. + + :param task: a task from TaskManager. + :raises: InvalidParameterValue if an invalid boot device is + specified. + :raises: MissingParameterValue if a required parameter is missing. + :raises: IPMIFailure on an error from ipmitool. + :raises: RedfishConnectionError on Redfish operation failure. + :raises: RedfishError on Redfish operation failure. + :returns: a dictionary containing: + + :boot_device: the boot device, one of + :mod:`ironic.common.boot_devices` or None if it is unknown. + :persistent: Whether the boot device will persist to all + future boots or not, None if it is unknown. """ - if device not in self.get_supported_boot_devices(task): - raise exception.InvalidParameterValue(_( - "Invalid boot device %s specified.") % device) - - uefi_mode = ( - driver_utils.get_node_capability(task.node, 'boot_mode') == 'uefi') - - # disable 60 secs timer - timeout_disable = "0x00 0x08 0x03 0x08" - ipmitool.send_raw(task, timeout_disable) - - # note(naohirot): - # Set System Boot Options : ipmi cmd '0x08', bootparam '0x05' - # - # $ ipmitool raw 0x00 0x08 0x05 data1 data2 0x00 0x00 0x00 - # - # data1 : '0xe0' persistent + uefi - # '0xc0' persistent + bios - # '0xa0' next only + uefi - # '0x80' next only + bios - # data2 : boot device defined in the dict _BOOTPARAM5_DATA2 - - bootparam5 = '0x00 0x08 0x05 %s %s 0x00 0x00 0x00' - if persistent: - data1 = '0xe0' if uefi_mode else '0xc0' + if task.node.driver_internal_info.get('irmc_ipmi_succeed'): + return super(IRMCManagement, self).get_boot_device(task) else: - data1 = '0xa0' if uefi_mode else '0x80' - data2 = _BOOTPARAM5_DATA2[device] + return super( + ipmitool.IPMIManagement, self).get_boot_device(task) - cmd8 = bootparam5 % (data1, data2) - ipmitool.send_raw(task, cmd8) + def get_supported_boot_modes(self, task): + """Get a list of the supported boot modes. + + IRMCManagement class doesn't support this method + + :param task: a task from TaskManager. + :raises: UnsupportedDriverExtension if requested operation is + not supported by the driver + """ + raise exception.UnsupportedDriverExtension( + driver=task.node.driver, extension='get_supported_boot_modes') + + def set_boot_mode(self, task, mode): + """Set the boot mode for a node. + + IRMCManagement class doesn't support this method + + :param task: a task from TaskManager. + :param mode: The boot mode, one of + :mod:`ironic.common.boot_modes`. + :raises: UnsupportedDriverExtension if requested operation is + not supported by the driver + """ + raise exception.UnsupportedDriverExtension( + driver=task.node.driver, extension='set_boot_mode') + + def get_boot_mode(self, task): + """Get the current boot mode for a node. + + IRMCManagement class doesn't support this method + + :param task: a task from TaskManager. + :raises: UnsupportedDriverExtension if requested operation is + not supported by the driver + """ + raise exception.UnsupportedDriverExtension( + driver=task.node.driver, extension='get_boot_mode') @METRICS.timer('IRMCManagement.get_sensors_data') def get_sensors_data(self, task): @@ -330,7 +426,13 @@ class IRMCManagement(ipmitool.IPMIManagement): if sensor_method == 'scci': return _get_sensors_data(task) elif sensor_method == 'ipmitool': - return super(IRMCManagement, self).get_sensors_data(task) + if task.node.driver_internal_info.get('irmc_ipmi_succeed'): + return super(IRMCManagement, self).get_sensors_data(task) + else: + raise exception.InvalidParameterValue(_( + "Invalid sensor method %s specified. " + "IPMI operation doesn't work on current iRMC " + "condition.") % sensor_method) @METRICS.timer('IRMCManagement.inject_nmi') @task_manager.require_exclusive_lock @@ -401,3 +503,120 @@ class IRMCManagement(ipmitool.IPMIManagement): not supported by the driver or the hardware """ return irmc_common.set_secure_boot_mode(task.node, state) + + def get_supported_indicators(self, task, component=None): + """Get a map of the supported indicators (e.g. LEDs). + + IRMCManagement class doesn't support this method + + :param task: a task from TaskManager. + :param component: If not `None`, return indicator information + for just this component, otherwise return indicators for + all existing components. + :raises: UnsupportedDriverExtension if requested operation is + not supported by the driver + + """ + raise exception.UnsupportedDriverExtension( + driver=task.node.driver, extension='get_supported_indicators') + + def set_indicator_state(self, task, component, indicator, state): + """Set indicator on the hardware component to the desired state. + + IRMCManagement class doesn't support this method + + :param task: A task from TaskManager. + :param component: The hardware component, one of + :mod:`ironic.common.components`. + :param indicator: Indicator ID (as reported by + `get_supported_indicators`). + :state: Desired state of the indicator, one of + :mod:`ironic.common.indicator_states`. + :raises: UnsupportedDriverExtension if requested operation is + not supported by the driver + """ + raise exception.UnsupportedDriverExtension( + driver=task.node.driver, extension='set_indicator_state') + + def get_indicator_state(self, task, component, indicator): + """Get current state of the indicator of the hardware component. + + IRMCManagement class doesn't support this method + + :param task: A task from TaskManager. + :param component: The hardware component, one of + :mod:`ironic.common.components`. + :param indicator: Indicator ID (as reported by + `get_supported_indicators`). + :raises: UnsupportedDriverExtension if requested operation is + not supported by the driver + """ + raise exception.UnsupportedDriverExtension( + driver=task.node.driver, extension='get_indicator_state') + + def detect_vendor(self, task): + """Detects and returns the hardware vendor. + + :param task: A task from TaskManager. + :raises: InvalidParameterValue if a required parameter is missing + :raises: MissingParameterValue if a required parameter is missing + :raises: RedfishError on Redfish operation error. + :raises: PasswordFileFailedToCreate from creating or writing to the + temporary file during IPMI operation. + :raises: processutils.ProcessExecutionError from executing ipmi command + :returns: String representing the BMC reported Vendor or + Manufacturer, otherwise returns None. + """ + if task.node.driver_internal_info.get('irmc_ipmi_succeed'): + return super(IRMCManagement, self).detect_vendor(task) + else: + return super(ipmitool.IPMIManagement, self).detect_vendor(task) + + def get_mac_addresses(self, task): + """Get MAC address information for the node. + + IRMCManagement class doesn't support this method + + :param task: A TaskManager instance containing the node to act on. + :raises: UnsupportedDriverExtension + """ + raise exception.UnsupportedDriverExtension( + driver=task.node.driver, extension='get_mac_addresses') + + @base.verify_step(priority=10) + def verify_http_https_connection_and_fw_version(self, task): + """Check http(s) connection to iRMC and save fw version + + :param task' A task from TaskManager + 'raises: IRMCOperationError + """ + error_msg_https = ('Access to REST API returns unexpected ' + 'status code. Check driver_info parameter ' + 'related to iRMC driver') + error_msg_http = ('Access to REST API returns unexpected ' + 'status code. Check driver_info parameter ' + 'or version of iRMC because iRMC does not ' + 'support HTTP connection to iRMC REST API ' + 'since iRMC S6 2.00.') + try: + # Check connection to iRMC + elcm_license = irmc_common.check_elcm_license(task.node) + + # On iRMC S6 2.00, access to REST API through HTTP returns 404 + if elcm_license.get('status_code') not in (200, 500): + port = task.node.driver_info.get( + 'irmc_port', CONF.irmc.get('port')) + if port == 80: + e_msg = error_msg_http + else: + e_msg = error_msg_https + raise exception.IRMCOperationError( + operation='establishing connection to REST API', + error=e_msg) + + irmc_common.set_irmc_version(task) + except (exception.InvalidParameterValue, + exception.MissingParameterValue) as irmc_exception: + raise exception.IRMCOperationError( + operation='configuration validation', + error=irmc_exception) |