diff options
author | Dmitry Tantsur <dtantsur@protonmail.com> | 2020-05-04 13:34:05 +0200 |
---|---|---|
committer | Dmitry Tantsur <dtantsur@protonmail.com> | 2020-05-08 13:31:13 +0200 |
commit | 18a8e2f6e9d80a827acba39a6ace366c13d40e31 (patch) | |
tree | 427f2e89ed6ad87c118b481824aecd2e885d144f /ironic/drivers/modules/redfish/management.py | |
parent | 8562df092f4286afc1e592951c7006eb56a4bf09 (diff) | |
download | ironic-18a8e2f6e9d80a827acba39a6ace366c13d40e31.tar.gz |
redfish: handle hardware that is unable to set persistent boot
Some hardware has dropped support for continuous boot, see this thread:
http://lists.openstack.org/pipermail/openstack-discuss/2020-April/014543.html
Work around by falling back to one-time boot device, restoring it on
every reboot or power on.
Story: #2007527
Task: #39320
Change-Id: I762056dea4f7b8ccdb8f95b2f21e26b45763905d
Diffstat (limited to 'ironic/drivers/modules/redfish/management.py')
-rw-r--r-- | ironic/drivers/modules/redfish/management.py | 74 |
1 files changed, 70 insertions, 4 deletions
diff --git a/ironic/drivers/modules/redfish/management.py b/ironic/drivers/modules/redfish/management.py index 4026da48c..dff790ce5 100644 --- a/ironic/drivers/modules/redfish/management.py +++ b/ironic/drivers/modules/redfish/management.py @@ -24,6 +24,7 @@ from ironic.common import components from ironic.common import exception from ironic.common.i18n import _ from ironic.common import indicator_states +from ironic.common import utils from ironic.conductor import task_manager from ironic.drivers import base from ironic.drivers.modules.redfish import utils as redfish_utils @@ -68,6 +69,42 @@ if sushy: v: k for k, v in INDICATOR_MAP.items()} +def _set_boot_device(task, system, device, enabled=None): + """An internal routine to set the boot device. + + :param task: a task from TaskManager. + :param system: a Redfish System object. + :param device: the Redfish boot device. + :param enabled: Redfish boot device persistence value or None. + :raises: SushyError on an error from the Sushy library + """ + try: + system.set_system_boot_options(device, enabled=enabled) + except sushy.exceptions.SushyError as e: + if enabled == sushy.BOOT_SOURCE_ENABLED_CONTINUOUS: + # NOTE(dtantsur): continuous boot device settings have been + # removed from Redfish, and some vendors stopped supporting + # it before an alternative was provided. As a work around, + # use one-time boot and restore the boot device on every + # reboot via RedfishPower. + LOG.debug('Error %(error)s when trying to set a ' + 'persistent boot device on node %(node)s, ' + 'falling back to one-time boot settings', + {'error': e, 'node': task.node.uuid}) + system.set_system_boot_options( + device, enabled=sushy.BOOT_SOURCE_ENABLED_ONCE) + LOG.warning('Could not set persistent boot device to ' + '%(dev)s for node %(node)s, using one-time ' + 'boot device instead', + {'dev': device, 'node': task.node.uuid}) + utils.set_node_nested_field( + task.node, 'driver_internal_info', + 'redfish_boot_device', device) + task.node.save() + else: + raise + + class RedfishManagement(base.ManagementInterface): def __init__(self): @@ -108,6 +145,33 @@ class RedfishManagement(base.ManagementInterface): return list(BOOT_DEVICE_MAP_REV) @task_manager.require_exclusive_lock + def restore_boot_device(self, task, system): + """Restore boot device if needed. + + Checks the redfish_boot_device internal flag and sets the one-time + boot device accordingly. A warning is issued if it fails. + + This method is supposed to be called from the Redfish power interface + and should be considered private to the Redfish hardware type. + + :param task: a task from TaskManager. + :param system: a Redfish System object. + """ + device = task.node.driver_internal_info.get('redfish_boot_device') + if not device: + return + + LOG.debug('Restoring boot device %(dev)s on node %(node)s', + {'dev': device, 'node': task.node.uuid}) + try: + _set_boot_device(task, system, device) + except sushy.exceptions.SushyError as e: + LOG.warning('Unable to recover boot device %(dev)s for node ' + '%(node)s, relying on the pre-configured boot order. ' + 'Error: %(error)s', + {'dev': device, 'node': task.node.uuid, 'error': e}) + + @task_manager.require_exclusive_lock def set_boot_device(self, task, device, persistent=False): """Set the boot device for a node. @@ -124,6 +188,10 @@ class RedfishManagement(base.ManagementInterface): :raises: RedfishConnectionError when it fails to connect to Redfish :raises: RedfishError on an error from the Sushy library """ + utils.pop_node_nested_field( + task.node, 'driver_internal_info', 'redfish_boot_device') + task.node.save() + system = redfish_utils.get_system(task.node) desired_persistence = BOOT_DEVICE_PERSISTENT_MAP_REV[persistent] @@ -132,11 +200,9 @@ class RedfishManagement(base.ManagementInterface): # NOTE(etingof): this can be racy, esp if BMC is not RESTful enabled = (desired_persistence if desired_persistence != current_persistence else None) - try: - system.set_system_boot_options( - BOOT_DEVICE_MAP_REV[device], enabled=enabled) - + _set_boot_device(task, system, BOOT_DEVICE_MAP_REV[device], + enabled=enabled) except sushy.exceptions.SushyError as e: error_msg = (_('Redfish set boot device failed for node ' '%(node)s. Error: %(error)s') % |