Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion ironic/conf/conductor.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@
'partition 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.')),
'partition images. Can be overridden per-architecture '
'using the bootloader_by_arch option.')),
cfg.MultiOpt('clean_step_priority_override',
item_type=types.Dict(),
default={},
Expand Down Expand Up @@ -546,6 +547,16 @@
'here are validated as absolute paths and will be rejected'
'if they contain path traversal mechanisms, such as "..".'
)),
cfg.DictOpt('bootloader_by_arch',
default={},
help=_(
'Bootloader ESP image parameter per node architecture. '
'For example: x86_64:bootx64.efi,aarch64:grubaa64.efi. '
'A node\'s cpu_arch property is used as the key to get '
'the appropriate bootloader ESP image. If the node\'s '
'cpu_arch is not in the dictionary, '
'the [conductor]bootloader value will be used instead.'
)),
]


Expand Down
5 changes: 5 additions & 0 deletions ironic/drivers/modules/image_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,11 @@ def prepare_deploy_iso(task, params, mode, d_info):
kernel_href = _find_param(kernel_str, d_info)
ramdisk_href = _find_param(ramdisk_str, d_info)
iso_href = _find_param(iso_str, d_info)

if not d_info.get('bootloader'):
d_info['bootloader'] = driver_utils.get_field(
task.node, 'bootloader', use_conf=True)

bootloader_href = _find_param(bootloader_str, d_info)

params = override_api_url(params)
Expand Down
3 changes: 3 additions & 0 deletions ironic/drivers/modules/redfish/boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ def _parse_driver_info(node):
{option: d_info.get(option, getattr(CONF.conductor, option, None))
for option in OPTIONAL_PROPERTIES})

deploy_info['bootloader'] = driver_utils.get_field(
node, 'bootloader', use_conf=True)

if (d_info.get('config_via_removable') is None
and d_info.get('config_via_floppy') is not None):
LOG.warning('The config_via_floppy driver_info option is deprecated, '
Expand Down
25 changes: 17 additions & 8 deletions ironic/drivers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,18 +451,27 @@ def get_field(node, name, deprecated_prefix=None, use_conf=False,
"""Get a driver_info field with deprecated prefix."""
node_coll = getattr(node, collection)
value = node_coll.get(name)
if value or not deprecated_prefix:
return value

deprecated_name = f'{deprecated_prefix}_{name}'
value = node_coll.get(deprecated_name)
if value:
LOG.warning("The %s field %s of node %s is deprecated, "
"please use %s instead",
collection, deprecated_name, node.uuid, name)
return value

if deprecated_prefix:
deprecated_name = f'{deprecated_prefix}_{name}'
value = node_coll.get(deprecated_name)
if value:
LOG.warning("The %s field %s of node %s is deprecated, "
"please use %s instead",
collection, deprecated_name, node.uuid, name)
return value

if use_conf:
if name == 'bootloader':
cpu_arch = node.properties.get('cpu_arch')
if cpu_arch:
bootloader_by_arch = getattr(
CONF.conductor, 'bootloader_by_arch', {})
bootloader_href = bootloader_by_arch.get(cpu_arch)
if bootloader_href:
return bootloader_href
return getattr(CONF.conductor, name)


Expand Down
23 changes: 23 additions & 0 deletions ironic/tests/unit/drivers/modules/test_image_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,29 @@ def test_prepare_deploy_iso(self, mock__prepare_iso_image):
task, 'kernel', 'ramdisk', 'bootloader', params={},
inject_files={}, base_iso=None)

@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
def test_prepare_deploy_iso_bootloader_by_arch(self,
mock__prepare_iso_image):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:

self.config(bootloader_by_arch={'x86_64': 'bootx64.efi'},
group='conductor')

d_info = {
'deploy_kernel': 'kernel',
'deploy_ramdisk': 'ramdisk',
}
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, 'kernel', 'ramdisk', 'bootx64.efi', params={},
inject_files={}, base_iso=None)

@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
def test_prepare_deploy_iso_existing_iso(self, mock__prepare_iso_image):
with task_manager.acquire(self.context, self.node.uuid,
Expand Down
22 changes: 22 additions & 0 deletions ironic/tests/unit/drivers/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,28 @@ def test_normalize_mac_unicode(self):
mac_clean = driver_utils.normalize_mac(mac_raw)
self.assertEqual("0a1b2c3d4f", mac_clean)

def test_get_field_bootloader(self):
driver_info = self.node.driver_info
driver_info['bootloader'] = 'custom.efi'
self.node.driver_info = driver_info
result = driver_utils.get_field(self.node, 'bootloader', use_conf=True)
self.assertEqual('custom.efi', result)

self.config(bootloader='global.efi', group='conductor')
del self.node.driver_info['bootloader']
result = driver_utils.get_field(self.node, 'bootloader', use_conf=True)
self.assertEqual('global.efi', result)

def test_get_field_bootloader_by_arch(self):
self.config(bootloader_by_arch={'aarch64': 'grubaa64.efi'},
group='conductor')
properties = self.node.properties
properties['cpu_arch'] = 'aarch64'
self.node.properties = properties

result = driver_utils.get_field(self.node, 'bootloader', use_conf=True)
self.assertEqual('grubaa64.efi', result)


class UtilsRamdiskLogsTestCase(tests_base.TestCase):

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
features:
- |
Adds a new configuration option ``bootloader_by_arch``, a dictionary value
that maps architecture names to a Glance ID, http:// or file:// URL
of an EFI system partition image containing EFI boot loader, to support
architecture-specific images for virtual media boot in mixed-architecture
clouds.