diff options
-rw-r--r-- | doc/source/admin/drivers/redfish.rst | 9 | ||||
-rw-r--r-- | driver-requirements.txt | 2 | ||||
-rw-r--r-- | ironic/drivers/modules/redfish/bios.py | 55 | ||||
-rw-r--r-- | ironic/drivers/modules/redfish/boot.py | 46 | ||||
-rw-r--r-- | ironic/drivers/utils.py | 42 | ||||
-rw-r--r-- | ironic/tests/unit/drivers/modules/redfish/test_bios.py | 204 | ||||
-rw-r--r-- | ironic/tests/unit/drivers/modules/redfish/test_boot.py | 16 | ||||
-rw-r--r-- | ironic/tests/unit/drivers/modules/test_image_utils.py | 19 | ||||
-rw-r--r-- | releasenotes/notes/get-bios-registry-aadc74800e0770f7.yaml | 6 | ||||
-rw-r--r-- | releasenotes/notes/redfish-deploy-iso-9671ae83108f6385.yaml | 6 |
10 files changed, 367 insertions, 38 deletions
diff --git a/doc/source/admin/drivers/redfish.rst b/doc/source/admin/drivers/redfish.rst index cff72a48f..63f2e4bbe 100644 --- a/doc/source/admin/drivers/redfish.rst +++ b/doc/source/admin/drivers/redfish.rst @@ -219,13 +219,18 @@ with the Wallaby release it's possible to provide a pre-built ISO image: .. code-block:: bash baremetal node set node-0 \ - --driver_info redfish_deploy_iso=http://url/of/deploy.iso \ - --driver_info redfish_rescue_iso=http://url/of/rescue.iso + --driver_info deploy_iso=http://url/of/deploy.iso \ + --driver_info rescue_iso=http://url/of/rescue.iso .. note:: OpenStack Image service (glance) image IDs and ``file://`` links are also accepted. +.. note:: + Before the Xena release the parameters were called ``redfish_deploy_iso`` + and ``redfish_rescue_iso`` accordingly. The old names are still supported + for backward compatibility. + No customization is currently done to the image, so e.g. :doc:`/admin/dhcp-less` won't work. `Configuring an ESP image`_ is also unnecessary. diff --git a/driver-requirements.txt b/driver-requirements.txt index 151e745bc..e379bb99a 100644 --- a/driver-requirements.txt +++ b/driver-requirements.txt @@ -11,7 +11,7 @@ python-dracclient>=5.1.0,<7.0.0 python-xclarityclient>=0.1.6 # The Redfish hardware type uses the Sushy library -sushy>=3.7.0 +sushy>=3.8.0 # Ansible-deploy interface ansible>=2.7 diff --git a/ironic/drivers/modules/redfish/bios.py b/ironic/drivers/modules/redfish/bios.py index ae8acc939..c1af56f24 100644 --- a/ironic/drivers/modules/redfish/bios.py +++ b/ironic/drivers/modules/redfish/bios.py @@ -32,6 +32,10 @@ METRICS = metrics_utils.get_metrics_logger(__name__) sushy = importutils.try_import('sushy') +registry_fields = ('attribute_type', 'allowable_values', 'lower_bound', + 'max_length', 'min_length', 'read_only', + 'reset_required', 'unique', 'upper_bound') + class RedfishBIOS(base.BIOSInterface): @@ -51,6 +55,23 @@ class RedfishBIOS(base.BIOSInterface): driver='redfish', reason=_("Unable to import the sushy library")) + def _parse_allowable_values(self, allowable_values): + """Convert the BIOS registry allowable_value list to expected strings + + :param allowable_values: list of dicts of valid values for enumeration + :returns: list containing only allowable value names + """ + + # Get name from ValueName if it exists, otherwise use DisplayValueName + new_list = [] + for dic in allowable_values: + for key in dic: + if key == 'ValueName' or key == 'DisplayValueName': + new_list.append(dic[key]) + break + + return new_list + def cache_bios_settings(self, task): """Store or update the current BIOS settings for the node. @@ -77,7 +98,39 @@ class RedfishBIOS(base.BIOSInterface): settings = [] # Convert Redfish BIOS attributes to Ironic BIOS settings if attributes: - settings = [{'name': k, 'value': v} for k, v in attributes.items()] + settings = [{'name': k, 'value': v} + for k, v in attributes.items()] + + # Get the BIOS Registry + registry_attributes = [] + try: + bios_registry = system.bios.get_attribute_registry() + + if bios_registry: + registry_attributes = bios_registry.registry_entries.attributes + + except Exception as e: + LOG.info('Cannot get BIOS Registry attributes for node %(node)s, ' + 'Error %(exc)s.', {'node': task.node.uuid, 'exc': e}) + + # TODO(bfournier): use a common list for registry field names + # e.g. registry_fields = objects.BIOSSetting.registry_fields + + # The BIOS registry will contain more entries than the BIOS settings + # Find the registry entry matching the setting name and get the fields + if registry_attributes: + for setting in settings: + reg = next((r for r in registry_attributes + if r.name == setting['name']), None) + fields = [attr for attr in dir(reg) + if not attr.startswith("_")] + settable_keys = [f for f in fields if f in registry_fields] + # Set registry fields to current values + for k in settable_keys: + setting[k] = getattr(reg, k, None) + if k == "allowable_values" and isinstance(setting[k], + list): + setting[k] = self._parse_allowable_values(setting[k]) LOG.debug('Cache BIOS settings for node %(node_uuid)s', {'node_uuid': task.node.uuid}) diff --git a/ironic/drivers/modules/redfish/boot.py b/ironic/drivers/modules/redfish/boot.py index b854fc994..0f48b4d1e 100644 --- a/ironic/drivers/modules/redfish/boot.py +++ b/ironic/drivers/modules/redfish/boot.py @@ -35,9 +35,11 @@ LOG = log.getLogger(__name__) REQUIRED_PROPERTIES = { 'deploy_kernel': _("URL or Glance UUID of the deployment kernel. " - "Required."), - 'deploy_ramdisk': _("URL or Glance UUID of the ramdisk that is " - "mounted at boot time. Required.") + "Required if deploy_iso is not set."), + 'deploy_ramdisk': _("URL or Glance UUID of the ramdisk that is mounted at " + "boot time. Required if deploy_iso is not set."), + 'deploy_iso': _("URL or Glance UUID of the deployment ISO to use. " + "Required if deploy_kernel/deploy_ramdisk are not set.") } OPTIONAL_PROPERTIES = { @@ -56,16 +58,19 @@ OPTIONAL_PROPERTIES = { "image containing EFI boot loader. This image will be " "used by ironic when building UEFI-bootable ISO " "out of kernel and ramdisk. Required for UEFI " - "boot from partition images."), + "when deploy_iso is not provided."), } RESCUE_PROPERTIES = { - 'rescue_kernel': _('URL or Glance UUID of the rescue kernel. This value ' - 'is required for rescue mode.'), + 'rescue_kernel': _('URL or Glance UUID of the rescue kernel. Required for ' + 'rescue mode if rescue_iso is not set.'), 'rescue_ramdisk': _('URL or Glance UUID of the rescue ramdisk with agent ' - 'that is used at node rescue time. This value is ' - 'required for rescue mode.'), + 'that is used at node rescue time. Required for ' + 'rescue mode if rescue_iso is not set.'), + 'rescue_iso': _("URL or Glance UUID of the rescue ISO to use. Required " + "for rescue mode if rescue_kernel/rescue_ramdisk are " + "not set.") } COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy() @@ -73,11 +78,6 @@ COMMON_PROPERTIES.update(driver_utils.OPTIONAL_PROPERTIES) COMMON_PROPERTIES.update(OPTIONAL_PROPERTIES) COMMON_PROPERTIES.update(RESCUE_PROPERTIES) -KERNEL_RAMDISK_LABELS = { - 'deploy': REQUIRED_PROPERTIES, - 'rescue': RESCUE_PROPERTIES -} - IMAGE_SUBDIR = 'redfish' sushy = importutils.try_import('sushy') @@ -100,23 +100,15 @@ def _parse_driver_info(node): d_info = node.driver_info mode = deploy_utils.rescue_or_deploy_mode(node) - iso_param = 'redfish_%s_iso' % mode - iso_ref = d_info.get(iso_param) + iso_param = f'{mode}_iso' + iso_ref = driver_utils.get_agent_iso(node, deprecated_prefix='redfish', + mode=mode) if iso_ref is not None: deploy_info = {iso_param: iso_ref} can_config = False else: - params_to_check = KERNEL_RAMDISK_LABELS[mode] - - deploy_info = {option: d_info.get(option) - for option in params_to_check} - - if not any(deploy_info.values()): - # NOTE(dtantsur): avoid situation when e.g. deploy_kernel comes - # from driver_info but deploy_ramdisk comes from configuration, - # since it's a sign of a potential operator's mistake. - deploy_info = {k: getattr(CONF.conductor, k) - for k in params_to_check} + # There was never a deprecated prefix for kernel/ramdisk + deploy_info = driver_utils.get_agent_kernel_ramdisk(node, mode) error_msg = _("Error validating Redfish virtual media. Some " "parameters were missing in node's driver_info") @@ -378,6 +370,8 @@ class RedfishVirtualMediaBoot(base.BootInterface): node = task.node _parse_driver_info(node) + # Issue the deprecation warning if needed + driver_utils.get_agent_iso(node, deprecated_prefix='redfish') def _validate_instance_info(self, task): """Validate instance image information for the task's node. diff --git a/ironic/drivers/utils.py b/ironic/drivers/utils.py index fa826c266..56b4409df 100644 --- a/ironic/drivers/utils.py +++ b/ironic/drivers/utils.py @@ -404,3 +404,45 @@ def get_kernel_append_params(node, default): return result return default + + +def _get_field(node, name, deprecated_prefix=None): + value = node.driver_info.get(name) + if value or not deprecated_prefix: + return value + + deprecated_name = f'{deprecated_prefix}_{name}' + value = node.driver_info.get(deprecated_name) + if value: + LOG.warning("The driver_info field %s of node %s is deprecated, " + "please use %s instead", + deprecated_name, node.uuid, name) + return value + + +def get_agent_kernel_ramdisk(node, mode='deploy', deprecated_prefix=None): + """Get the agent kernel/ramdisk as a dictionary.""" + kernel_name = f'{mode}_kernel' + ramdisk_name = f'{mode}_ramdisk' + kernel, ramdisk = ( + _get_field(node, kernel_name, deprecated_prefix), + _get_field(node, ramdisk_name, deprecated_prefix), + ) + # NOTE(dtantsur): avoid situation when e.g. deploy_kernel comes + # from driver_info but deploy_ramdisk comes from configuration, + # since it's a sign of a potential operator's mistake. + if not kernel or not ramdisk: + return { + kernel_name: getattr(CONF.conductor, kernel_name), + ramdisk_name: getattr(CONF.conductor, ramdisk_name), + } + else: + return { + kernel_name: kernel, + ramdisk_name: ramdisk + } + + +def get_agent_iso(node, mode='deploy', deprecated_prefix=None): + """Get the agent ISO image.""" + return _get_field(node, f'{mode}_iso', deprecated_prefix) diff --git a/ironic/tests/unit/drivers/modules/redfish/test_bios.py b/ironic/tests/unit/drivers/modules/redfish/test_bios.py index 30aab9587..cd6f9be5f 100644 --- a/ironic/tests/unit/drivers/modules/redfish/test_bios.py +++ b/ironic/tests/unit/drivers/modules/redfish/test_bios.py @@ -99,7 +99,9 @@ class RedfishBiosTestCase(db_base.DbTestCase): task.driver.bios.cache_bios_settings(task) mock_get_system.assert_called_once_with(task.node) mock_setting_list.sync_node_setting.assert_called_once_with( - task.context, task.node.id, [{'name': 'foo', 'value': 'bar'}]) + task.context, task.node.id, + [{'name': 'foo', 'value': 'bar'}]) + mock_setting_list.create.assert_not_called() mock_setting_list.save.assert_not_called() mock_setting_list.delete.assert_not_called() @@ -153,7 +155,9 @@ class RedfishBiosTestCase(db_base.DbTestCase): task.driver.bios.cache_bios_settings(task) mock_get_system.assert_called_once_with(task.node) mock_setting_list.sync_node_setting.assert_called_once_with( - task.context, task.node.id, [{'name': 'foo', 'value': 'bar'}]) + task.context, task.node.id, + [{'name': 'foo', 'value': 'bar'}]) + mock_setting_list.create.assert_called_once_with( task.context, task.node.id, create_list) mock_setting_list.save.assert_called_once_with( @@ -252,6 +256,7 @@ class RedfishBiosTestCase(db_base.DbTestCase): # by returning the same as requested mock_bios.attributes = attributes_after_reboot \ or self.node.driver_internal_info['requested_bios_attrs'] + mock_bios.get_attribute_registry = [] mock_system = mock.Mock() mock_system.bios = mock_bios mock_get_system.return_value = mock_system @@ -313,7 +318,8 @@ class RedfishBiosTestCase(db_base.DbTestCase): @mock.patch.object(manager_utils, 'cleaning_error_handler', autospec=True) def test_apply_conf_post_reboot_cleaning_failed( self, mock_cleaning_error_handler): - data = [{'name': 'ProcTurboMode', 'value': 'Enabled'}] + data = [{'name': 'ProcTurboMode', 'value': 'Enabled', + 'registry': {'description': 'Turbo mode'}}] self.node.clean_step = {'priority': 100, 'interface': 'bios', 'step': 'apply_configuration', 'argsinfo': {'settings': data}} @@ -331,8 +337,10 @@ class RedfishBiosTestCase(db_base.DbTestCase): mock_cleaning_error_handler.assert_called_once() def test_apply_conf_post_reboot_deploying(self): - data = [{'name': 'ProcTurboMode', 'value': 'Disabled'}, - {'name': 'NicBoot1', 'value': 'NetworkBoot'}] + data = [{'name': 'ProcTurboMode', 'value': 'Enabled', + 'registry': {'description': 'Turbo mode'}}, + {'name': 'NicBoot1', 'value': 'NetworkBoot', + 'registry': {'description': 'Boot off network'}}] self.node.deploy_step = {'priority': 100, 'interface': 'bios', 'step': 'apply_configuration', 'argsinfo': {'settings': data}} @@ -349,7 +357,8 @@ class RedfishBiosTestCase(db_base.DbTestCase): @mock.patch.object(manager_utils, 'deploying_error_handler', autospec=True) def test_apply_conf_post_reboot_deploying_failed( self, mock_deploying_error_handler): - data = [{'name': 'ProcTurboMode', 'value': 'Enabled'}] + data = [{'name': 'ProcTurboMode', 'value': 'Enabled', + 'registry': {'description': 'Turbo mode'}}] self.node.deploy_step = {'priority': 100, 'interface': 'bios', 'step': 'apply_configuration', 'argsinfo': {'settings': data}} @@ -503,3 +512,186 @@ class RedfishBiosTestCase(db_base.DbTestCase): bios.set_attributes.assert_called_once_with( {s['name']: s['value'] for s in settings}, apply_time=None) + + +@mock.patch('oslo_utils.eventletutils.EventletEvent.wait', + lambda *args, **kwargs: None) +class RedfishBiosRegistryTestCase(db_base.DbTestCase): + + def setUp(self): + super(RedfishBiosRegistryTestCase, self).setUp() + self.config(enabled_bios_interfaces=['redfish'], + enabled_hardware_types=['redfish'], + enabled_power_interfaces=['redfish'], + enabled_boot_interfaces=['redfish-virtual-media'], + enabled_management_interfaces=['redfish']) + self.node = obj_utils.create_test_node( + self.context, driver='redfish', driver_info=INFO_DICT) + + self.settings = {'SystemModelName': 'UltraSumma', + 'DcuStreamPrefetcher': 'Enabled', + 'BootDelay': 10} + + class AttributeField(): + + def __init__(self): + self.name = None + self.allowable_values = None + self.attribute_type = None + self.lower_bound = None + self.max_length = None + self.min_length = None + self.read_only = None + self.reset_required = None + self.type = None + self.unique = None + self.upper_bound = None + + class AttributeRegistryEntryField(): + + def __init__(self, num_entries): + self.attributes = [] + for _ in range(num_entries): + self.attributes.append(AttributeField()) + + class AttributeRegistryTest(): + + def __init__(self, num_entries): + self.registry_entries = AttributeRegistryEntryField( + num_entries) + + self.registry = AttributeRegistryTest(4) + self.registry.registry_entries.attributes[0].name = "SystemModelName" + self.registry.registry_entries.attributes[0].attribute_type = "String" + self.registry.registry_entries.attributes[0].max_length = 32 + self.registry.registry_entries.attributes[0].read_only = True + self.registry.registry_entries.attributes[0].unique = True + self.registry.registry_entries.attributes[1].name =\ + "DcuStreamPrefetcher" + self.registry.registry_entries.attributes[1].attribute_type =\ + "Enumeration" + self.registry.registry_entries.attributes[1].read_only = False + self.registry.registry_entries.attributes[1].allowable_values =\ + [{'ValueName': 'Enabled', 'ValueDisplayName': 'Enabled'}, + {'ValueName': 'Disabled', 'ValueDisplayName': 'Disabled'}] + self.registry.registry_entries.attributes[2].name = "BootDelay" + self.registry.registry_entries.attributes[2].attribute_type = "Integer" + self.registry.registry_entries.attributes[2].lower_bound = 5 + self.registry.registry_entries.attributes[2].upper_bound = 30 + self.registry.registry_entries.attributes[2].reset_required = True + self.registry.registry_entries.attributes[3].name = "SomeAttribute" + self.registry.registry_entries.attributes[3].attribute_type = "String" + self.registry.registry_entries.attributes[3].max_length = 32 + self.registry.registry_entries.attributes[3].read_only = True + + self.expected_no_registry = [ + {'name': 'SystemModelName', 'value': 'UltraSumma'}, + {'name': 'DcuStreamPrefetcher', 'value': 'Enabled'}, + {'name': 'BootDelay', 'value': 10}] + + @mock.patch.object(objects, 'BIOSSettingList', autospec=True) + @mock.patch.object(redfish_utils, 'get_system', autospec=True) + def test_cache_bios_registry_save(self, mock_get_system, + mock_setting_list): + create_list = [] + update_list = [] + delete_list = [] + nochange_list = [] + mock_setting_list.sync_node_setting.return_value = ( + create_list, update_list, delete_list, nochange_list + ) + + expected = [{'name': 'SystemModelName', 'value': 'UltraSumma', + 'allowable_values': None, 'lower_bound': None, + 'max_length': 32, 'min_length': None, 'read_only': True, + 'reset_required': None, 'attribute_type': 'String', + 'unique': True, 'upper_bound': None}, + {'name': 'DcuStreamPrefetcher', 'value': 'Enabled', + 'allowable_values': ['Enabled', 'Disabled'], + 'lower_bound': None, 'max_length': None, + 'min_length': None, 'read_only': False, + 'reset_required': None, 'attribute_type': + 'Enumeration', 'unique': None, 'upper_bound': None}, + {'name': 'BootDelay', 'value': 10, + 'allowable_values': None, 'lower_bound': 5, + 'max_length': None, 'min_length': None, 'read_only': None, + 'reset_required': True, 'attribute_type': 'Integer', + 'unique': None, 'upper_bound': 30}] + + mock_get_system.return_value.bios.attributes = self.settings + mock_get_system.return_value.bios.get_attribute_registry.\ + return_value = self.registry + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + task.driver.bios.cache_bios_settings(task) + mock_get_system.assert_called_once_with(task.node) + mock_setting_list.sync_node_setting.assert_called_once_with( + task.context, task.node.id, expected) + + @mock.patch.object(objects, 'BIOSSettingList', autospec=True) + @mock.patch.object(redfish_utils, 'get_system', autospec=True) + def test_cache_empty_bios_registry(self, mock_get_system, + mock_setting_list): + create_list = [] + update_list = [] + delete_list = [] + nochange_list = [] + mock_setting_list.sync_node_setting.return_value = ( + create_list, update_list, delete_list, nochange_list + ) + + mock_get_system.return_value.bios.attributes = self.settings + mock_get_system.return_value.bios.get_attribute_registry.\ + return_value = {} + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + task.driver.bios.cache_bios_settings(task) + mock_setting_list.sync_node_setting.assert_called_once_with( + task.context, task.node.id, self.expected_no_registry) + + @mock.patch.object(objects, 'BIOSSettingList', autospec=True) + @mock.patch.object(redfish_utils, 'get_system', autospec=True) + def test_cache_no_bios_registry(self, mock_get_system, + mock_setting_list): + create_list = [] + update_list = [] + delete_list = [] + nochange_list = [] + mock_setting_list.sync_node_setting.return_value = ( + create_list, update_list, delete_list, nochange_list + ) + + mock_get_system.return_value.bios.attributes = self.settings + mock_get_system.return_value.bios.get_attribute_registry.\ + return_value = None + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + task.driver.bios.cache_bios_settings(task) + mock_setting_list.sync_node_setting.assert_called_once_with( + task.context, task.node.id, self.expected_no_registry) + + @mock.patch.object(objects, 'BIOSSettingList', autospec=True) + @mock.patch.object(redfish_utils, 'get_system', autospec=True) + def test_cache_exception_bios_registry(self, mock_get_system, + mock_setting_list): + create_list = [] + update_list = [] + delete_list = [] + nochange_list = [] + mock_setting_list.sync_node_setting.return_value = ( + create_list, update_list, delete_list, nochange_list + ) + + mock_get_system.return_value.bios.attributes = self.settings + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + bios = mock_get_system(task.node).bios + bios.reset_bios.side_effect = sushy.exceptions.SushyError + + task.driver.bios.cache_bios_settings(task) + mock_setting_list.sync_node_setting.assert_called_once_with( + task.context, task.node.id, self.expected_no_registry) diff --git a/ironic/tests/unit/drivers/modules/redfish/test_boot.py b/ironic/tests/unit/drivers/modules/redfish/test_boot.py index d4471cda5..e0f0dbf17 100644 --- a/ironic/tests/unit/drivers/modules/redfish/test_boot.py +++ b/ironic/tests/unit/drivers/modules/redfish/test_boot.py @@ -78,19 +78,31 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase): with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: task.node.driver_info.update( + {'deploy_iso': 'http://boot.iso'}) + + actual_driver_info = redfish_boot._parse_driver_info(task.node) + + self.assertEqual('http://boot.iso', + actual_driver_info['deploy_iso']) + self.assertFalse(actual_driver_info['can_provide_config']) + + def test_parse_driver_info_iso_deprecated(self): + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + task.node.driver_info.update( {'redfish_deploy_iso': 'http://boot.iso'}) actual_driver_info = redfish_boot._parse_driver_info(task.node) self.assertEqual('http://boot.iso', - actual_driver_info['redfish_deploy_iso']) + actual_driver_info['deploy_iso']) self.assertFalse(actual_driver_info['can_provide_config']) def test_parse_driver_info_removable(self): with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: task.node.driver_info.update( - {'redfish_deploy_iso': 'http://boot.iso', + {'deploy_iso': 'http://boot.iso', 'config_via_removable': True} ) diff --git a/ironic/tests/unit/drivers/modules/test_image_utils.py b/ironic/tests/unit/drivers/modules/test_image_utils.py index 1e105a08f..91c0e514c 100644 --- a/ironic/tests/unit/drivers/modules/test_image_utils.py +++ b/ironic/tests/unit/drivers/modules/test_image_utils.py @@ -654,6 +654,25 @@ class RedfishImageUtilsTestCase(db_base.DbTestCase): shared=True) as task: d_info = { + 'deploy_iso': 'iso', + } + task.node.driver_info.update(d_info) + + task.node.instance_info.update(deploy_boot_mode='uefi') + + image_utils.prepare_deploy_iso(task, {}, 'deploy', d_info) + + mock__prepare_iso_image.assert_called_once_with( + task, None, None, None, params={}, + inject_files={}, base_iso='iso') + + @mock.patch.object(image_utils, '_prepare_iso_image', autospec=True) + def test_prepare_deploy_iso_existing_iso_vendor_prefix( + self, mock__prepare_iso_image): + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + + d_info = { 'redfish_deploy_iso': 'iso', } task.node.driver_info.update(d_info) diff --git a/releasenotes/notes/get-bios-registry-aadc74800e0770f7.yaml b/releasenotes/notes/get-bios-registry-aadc74800e0770f7.yaml new file mode 100644 index 000000000..c158fb0e2 --- /dev/null +++ b/releasenotes/notes/get-bios-registry-aadc74800e0770f7.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Get the BIOS Registry from Sushy and store the fields in the Ironic DB + with the BIOS setting. See `story + 2008571 <https://storyboard.openstack.org/#!/story/2008571>`_. diff --git a/releasenotes/notes/redfish-deploy-iso-9671ae83108f6385.yaml b/releasenotes/notes/redfish-deploy-iso-9671ae83108f6385.yaml new file mode 100644 index 000000000..10111a795 --- /dev/null +++ b/releasenotes/notes/redfish-deploy-iso-9671ae83108f6385.yaml @@ -0,0 +1,6 @@ +--- +deprecations: + - | + The node's ``driver_info`` parameters ``redfish_deploy_iso`` and + ``redfish_rescue_iso`` have been renamed to ``deploy_iso`` and + ``rescue_iso`` accordingly. The old names are deprecated. |