From 62c5674a600baeeef0af3b12baeab486870eb103 Mon Sep 17 00:00:00 2001 From: Arne Wiebalck Date: Mon, 24 Jan 2022 15:00:05 +0100 Subject: SoftwareRAID: Use efibootmgr (and drop grub2-install) Move the software RAID code path from grub2-install to efibootmgr: - remove the UEFI efibootmgr exception for software RAID - create and populate the ESPs on the holder disks - update the NVRAM with all ESPs (the component devices of the ESP mirror, use unique labels to avoid unintentional deduplication of entries in the NVRAM) Story: #2009794 Change-Id: I7ed34e595215194a589c2f1cd0b39ff0336da8f1 --- ironic_python_agent/efi_utils.py | 73 ++++++++++++++++--- ironic_python_agent/extensions/image.py | 10 ++- ironic_python_agent/hardware.py | 6 +- .../tests/unit/extensions/test_image.py | 24 +++---- ironic_python_agent/tests/unit/test_efi_utils.py | 83 +++++++++++++++++++--- ironic_python_agent/tests/unit/test_hardware.py | 14 ++-- ...move_swraid_to_efibootmgr-d87c1bfde1661fb5.yaml | 7 ++ 7 files changed, 172 insertions(+), 45 deletions(-) create mode 100644 releasenotes/notes/move_swraid_to_efibootmgr-d87c1bfde1661fb5.yaml diff --git a/ironic_python_agent/efi_utils.py b/ironic_python_agent/efi_utils.py index 156f818a..54d1e62f 100644 --- a/ironic_python_agent/efi_utils.py +++ b/ironic_python_agent/efi_utils.py @@ -20,6 +20,8 @@ from oslo_concurrency import processutils from oslo_log import log from ironic_python_agent import errors +from ironic_python_agent.extensions import image +from ironic_python_agent import hardware from ironic_python_agent import partition_utils from ironic_python_agent import utils @@ -92,16 +94,60 @@ def manage_uefi(device, efi_system_part_uuid=None): efi_mounted = True valid_efi_bootloaders = _get_efi_bootloaders(efi_partition_mount_point) - if valid_efi_bootloaders: - _run_efibootmgr(valid_efi_bootloaders, device, efi_partition, - efi_partition_mount_point) - return True - else: + if not valid_efi_bootloaders: # NOTE(dtantsur): if we have an empty EFI partition, try to use # grub-install to populate it. LOG.warning('Empty EFI partition detected.') return False + if not hardware.is_md_device(device): + efi_devices = [device] + efi_partition_numbers = [efi_partition] + efi_label_suffix = '' + else: + # umount to allow for signature removal (to avoid confusion about + # which ESP to mount once the instance is deployed) + utils.execute('umount', efi_partition_mount_point, attempts=3, + delay_on_retry=True) + efi_mounted = False + + holders = hardware.get_holder_disks(device) + efi_md_device = image.prepare_boot_partitions_for_softraid( + device, holders, efi_device_part, target_boot_mode='uefi' + ) + efi_devices = hardware.get_component_devices(efi_md_device) + efi_partition_numbers = [] + _PARTITION_NUMBER = re.compile(r'(\d+)$') + for dev in efi_devices: + match = _PARTITION_NUMBER.search(dev) + if match: + partition_number = match.group(1) + efi_partition_numbers.append(partition_number) + else: + raise errors.DeviceNotFound( + "Could not extract the partition number " + "from %s!" % dev) + efi_label_suffix = "(RAID, part%s)" + + # remount for _run_efibootmgr + utils.execute('mount', efi_device_part, efi_partition_mount_point) + efi_mounted = True + + efi_dev_part = zip(efi_devices, efi_partition_numbers) + for i, (efi_dev, efi_part) in enumerate(efi_dev_part): + LOG.debug("Calling efibootmgr with dev %s part %s", + efi_dev, efi_part) + if efi_label_suffix: + # NOTE (arne_wiebalck): uniqify the labels to prevent + # unintentional boot entry cleanup + _run_efibootmgr(valid_efi_bootloaders, efi_dev, efi_part, + efi_partition_mount_point, + efi_label_suffix % i) + else: + _run_efibootmgr(valid_efi_bootloaders, efi_dev, efi_part, + efi_partition_mount_point) + return True + except processutils.ProcessExecutionError as e: error_msg = ('Could not verify uefi on device %(dev)s, ' 'failed with %(err)s.' % {'dev': device, 'err': e}) @@ -227,7 +273,7 @@ def remove_boot_record(boot_num): def _run_efibootmgr(valid_efi_bootloaders, device, efi_partition, - mount_point): + mount_point, label_suffix=None): """Executes efibootmgr and removes duplicate entries. :param valid_efi_bootloaders: the list of valid efi bootloaders @@ -236,6 +282,9 @@ def _run_efibootmgr(valid_efi_bootloaders, device, efi_partition, :param mount_point: The mountpoint for the EFI partition so we can read contents of files if necessary to perform proper bootloader injection operations. + :param label_suffix: a string to be appended to the EFI label, + mainly used in the case of software to uniqify + the entries for the md components. """ # Before updating let's get information about the bootorder @@ -255,9 +304,13 @@ def _run_efibootmgr(valid_efi_bootloaders, device, efi_partition, v_efi_bl_path = v_bl.replace(csv_filename, str(csv_contents[0])) v_efi_bl_path = '\\' + v_efi_bl_path.replace('/', '\\') label = csv_contents[1] + if label_suffix: + label = label + " " + str(label_suffix) else: v_efi_bl_path = '\\' + v_bl.replace('/', '\\') label = 'ironic' + str(label_id) + if label_suffix: + label = label + " " + str(label_suffix) # Iterate through standard out, and look for duplicates for boot_num, boot_rec in boot_records: @@ -268,9 +321,11 @@ def _run_efibootmgr(valid_efi_bootloaders, device, efi_partition, LOG.debug("Found bootnum %s matching label", boot_num) remove_boot_record(boot_num) - LOG.debug("Adding loader %(path)s on partition %(part)s of device " - " %(dev)s", {'path': v_efi_bl_path, 'part': efi_partition, - 'dev': device}) + LOG.info("Adding loader %(path)s on partition %(part)s of device " + " %(dev)s with label %(label)s", + {'path': v_efi_bl_path, 'part': efi_partition, + 'dev': device, 'label': label}) + # Update the nvram using efibootmgr add_boot_record(device, efi_partition, v_efi_bl_path, label) # Increment the ID in case the loop runs again. diff --git a/ironic_python_agent/extensions/image.py b/ironic_python_agent/extensions/image.py index 11caf585..c917c111 100644 --- a/ironic_python_agent/extensions/image.py +++ b/ironic_python_agent/extensions/image.py @@ -105,8 +105,8 @@ def _is_bootloader_loaded(dev): # TODO(rg): handle PreP boot parts relocation as well -def _prepare_boot_partitions_for_softraid(device, holders, efi_part, - target_boot_mode): +def prepare_boot_partitions_for_softraid(device, holders, efi_part, + target_boot_mode): """Prepare boot partitions when relevant. Create either a RAIDed EFI partition or bios boot partitions for software @@ -311,7 +311,7 @@ def _install_grub2(device, root_uuid, efi_system_part_uuid=None, efi_partition = efi_part if hardware.is_md_device(device): holders = hardware.get_holder_disks(device) - efi_partition = _prepare_boot_partitions_for_softraid( + efi_partition = prepare_boot_partitions_for_softraid( device, holders, efi_part, target_boot_mode ) @@ -648,9 +648,7 @@ def _efi_boot_setup(device, efi_system_part_uuid=None, target_boot_mode=None): {'target': target_boot_mode, 'current': boot.current_boot_mode}) - # FIXME(arne_wiebalck): make software RAID work with efibootmgr - if (boot.current_boot_mode == 'uefi' - and not hardware.is_md_device(device)): + if boot.current_boot_mode == 'uefi': try: utils.execute('efibootmgr', '--version') except FileNotFoundError: diff --git a/ironic_python_agent/hardware.py b/ironic_python_agent/hardware.py index ba42800a..ceafe31e 100644 --- a/ironic_python_agent/hardware.py +++ b/ironic_python_agent/hardware.py @@ -181,7 +181,7 @@ def _get_md_uuid(raid_device): return match.group(1) -def _get_component_devices(raid_device): +def get_component_devices(raid_device): """Get the component devices of a Software RAID device. Get the UUID of the md device and scan all other devices @@ -325,7 +325,7 @@ def md_restart(raid_device): """ try: LOG.debug('Restarting software RAID device %s', raid_device) - component_devices = _get_component_devices(raid_device) + component_devices = get_component_devices(raid_device) il_utils.execute('mdadm', '--stop', raid_device) il_utils.execute('mdadm', '--assemble', raid_device, *component_devices) @@ -2221,7 +2221,7 @@ class GenericHardwareManager(HardwareManager): def _delete_config_pass(self, raid_devices): all_holder_disks = [] for raid_device in raid_devices: - component_devices = _get_component_devices(raid_device.name) + component_devices = get_component_devices(raid_device.name) if not component_devices: # A "Software RAID device" without components is usually # a partition on an md device (as, for instance, created diff --git a/ironic_python_agent/tests/unit/extensions/test_image.py b/ironic_python_agent/tests/unit/extensions/test_image.py index 4d389005..c687e59e 100644 --- a/ironic_python_agent/tests/unit/extensions/test_image.py +++ b/ironic_python_agent/tests/unit/extensions/test_image.py @@ -1654,7 +1654,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640 self.assertFalse(mock_dispatch.called) @mock.patch.object(disk_utils, 'find_efi_partition', autospec=True) - def test__prepare_boot_partitions_for_softraid_uefi_gpt( + def test_prepare_boot_partitions_for_softraid_uefi_gpt( self, mock_efi_part, mock_execute, mock_dispatch): mock_efi_part.return_value = {'number': '12'} mock_execute.side_effect = [ @@ -1673,7 +1673,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640 (None, None), # wipefs ] - efi_part = image._prepare_boot_partitions_for_softraid( + efi_part = image.prepare_boot_partitions_for_softraid( '/dev/md0', ['/dev/sda', '/dev/sdb'], None, target_boot_mode='uefi') @@ -1704,7 +1704,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640 @mock.patch.object(disk_utils, 'find_efi_partition', autospec=True) @mock.patch.object(ilib_utils, 'mkfs', autospec=True) - def test__prepare_boot_partitions_for_softraid_uefi_gpt_esp_not_found( + def test_prepare_boot_partitions_for_softraid_uefi_gpt_esp_not_found( self, mock_mkfs, mock_efi_part, mock_execute, mock_dispatch): mock_efi_part.return_value = None mock_execute.side_effect = [ @@ -1721,7 +1721,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640 (None, None), # mdadm ] - efi_part = image._prepare_boot_partitions_for_softraid( + efi_part = image.prepare_boot_partitions_for_softraid( '/dev/md0', ['/dev/sda', '/dev/sdb'], None, target_boot_mode='uefi') @@ -1748,7 +1748,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640 ], any_order=False) self.assertEqual(efi_part, '/dev/md/esp') - def test__prepare_boot_partitions_for_softraid_uefi_gpt_efi_provided( + def test_prepare_boot_partitions_for_softraid_uefi_gpt_efi_provided( self, mock_execute, mock_dispatch): mock_execute.side_effect = [ ('451', None), # sgdisk -F @@ -1766,7 +1766,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640 (None, None), # wipefs ] - efi_part = image._prepare_boot_partitions_for_softraid( + efi_part = image.prepare_boot_partitions_for_softraid( '/dev/md0', ['/dev/sda', '/dev/sdb'], '/dev/md0p15', target_boot_mode='uefi') @@ -1796,10 +1796,10 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640 @mock.patch.object(disk_utils, 'get_partition_table_type', autospec=True, return_value='msdos') - def test__prepare_boot_partitions_for_softraid_bios_msdos( + def test_prepare_boot_partitions_for_softraid_bios_msdos( self, mock_label_scan, mock_execute, mock_dispatch): - efi_part = image._prepare_boot_partitions_for_softraid( + efi_part = image.prepare_boot_partitions_for_softraid( '/dev/md0', ['/dev/sda', '/dev/sdb'], 'notusedanyway', target_boot_mode='bios') @@ -1812,7 +1812,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640 @mock.patch.object(disk_utils, 'get_partition_table_type', autospec=True, return_value='gpt') - def test__prepare_boot_partitions_for_softraid_bios_gpt( + def test_prepare_boot_partitions_for_softraid_bios_gpt( self, mock_label_scan, mock_execute, mock_dispatch): mock_execute.side_effect = [ @@ -1822,7 +1822,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640 (None, None), # bios boot grub ] - efi_part = image._prepare_boot_partitions_for_softraid( + efi_part = image.prepare_boot_partitions_for_softraid( '/dev/md0', ['/dev/sda', '/dev/sdb'], 'notusedanyway', target_boot_mode='bios') @@ -1854,7 +1854,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640 @mock.patch.object(os, 'environ', autospec=True) @mock.patch.object(os, 'makedirs', autospec=True) @mock.patch.object(partition_utils, 'get_partition', autospec=True) - @mock.patch.object(image, '_prepare_boot_partitions_for_softraid', + @mock.patch.object(image, 'prepare_boot_partitions_for_softraid', autospec=True, return_value='/dev/md/esp') @mock.patch.object(image, '_has_dracut', @@ -1972,7 +1972,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640 @mock.patch.object(os, 'environ', autospec=True) @mock.patch.object(os, 'makedirs', autospec=True) @mock.patch.object(partition_utils, 'get_partition', autospec=True) - @mock.patch.object(image, '_prepare_boot_partitions_for_softraid', + @mock.patch.object(image, 'prepare_boot_partitions_for_softraid', autospec=True, return_value=[]) @mock.patch.object(image, '_has_dracut', diff --git a/ironic_python_agent/tests/unit/test_efi_utils.py b/ironic_python_agent/tests/unit/test_efi_utils.py index 0933cc32..775d0fce 100644 --- a/ironic_python_agent/tests/unit/test_efi_utils.py +++ b/ironic_python_agent/tests/unit/test_efi_utils.py @@ -19,6 +19,8 @@ from ironic_lib import disk_utils from ironic_python_agent import efi_utils from ironic_python_agent import errors +from ironic_python_agent.extensions import image +from ironic_python_agent import hardware from ironic_python_agent import partition_utils from ironic_python_agent.tests.unit import base from ironic_python_agent import utils @@ -158,12 +160,15 @@ class TestManageUefi(base.IronicAgentTest): mock_rescan.assert_called_once_with(self.fake_dev) @mock.patch.object(os.path, 'exists', lambda *_: False) + @mock.patch.object(hardware, 'is_md_device', autospec=True) @mock.patch.object(efi_utils, '_get_efi_bootloaders', autospec=True) @mock.patch.object(os, 'makedirs', autospec=True) - def test_ok(self, mkdir_mock, mock_efi_bl, mock_utils_efi_part, - mock_get_part_uuid, mock_execute, mock_rescan): + def test_ok(self, mkdir_mock, mock_efi_bl, mock_is_md_device, + mock_utils_efi_part, mock_get_part_uuid, mock_execute, + mock_rescan): mock_utils_efi_part.return_value = {'number': '1'} mock_get_part_uuid.return_value = self.fake_dev + mock_is_md_device.return_value = False mock_efi_bl.return_value = ['EFI/BOOT/BOOTX64.EFI'] @@ -192,13 +197,16 @@ class TestManageUefi(base.IronicAgentTest): mock_rescan.assert_called_once_with(self.fake_dev) @mock.patch.object(os.path, 'exists', lambda *_: False) + @mock.patch.object(hardware, 'is_md_device', autospec=True) @mock.patch.object(efi_utils, '_get_efi_bootloaders', autospec=True) @mock.patch.object(os, 'makedirs', autospec=True) - def test_found_csv(self, mkdir_mock, mock_efi_bl, mock_utils_efi_part, - mock_get_part_uuid, mock_execute, mock_rescan): + def test_found_csv(self, mkdir_mock, mock_efi_bl, mock_is_md_device, + mock_utils_efi_part, mock_get_part_uuid, mock_execute, + mock_rescan): mock_utils_efi_part.return_value = {'number': '1'} mock_get_part_uuid.return_value = self.fake_dev mock_efi_bl.return_value = ['EFI/vendor/BOOTX64.CSV'] + mock_is_md_device.return_value = False # Format is ,,,humanfriendlytextnotused # https://www.rodsbooks.com/efi-bootloaders/fallback.html @@ -242,12 +250,15 @@ Boot0002: VENDMAGIC FvFile(9f3c6294-bf9b-4208-9808-be45dfc34b51) mock_execute.assert_has_calls(expected) @mock.patch.object(os.path, 'exists', lambda *_: False) + @mock.patch.object(hardware, 'is_md_device', autospec=True) @mock.patch.object(efi_utils, '_get_efi_bootloaders', autospec=True) @mock.patch.object(os, 'makedirs', autospec=True) - def test_nvme_device(self, mkdir_mock, mock_efi_bl, mock_utils_efi_part, - mock_get_part_uuid, mock_execute, mock_rescan): + def test_nvme_device(self, mkdir_mock, mock_efi_bl, mock_is_md_device, + mock_utils_efi_part, mock_get_part_uuid, + mock_execute, mock_rescan): mock_utils_efi_part.return_value = {'number': '1'} mock_get_part_uuid.return_value = '/dev/fakenvme0p1' + mock_is_md_device.return_value = False mock_efi_bl.return_value = ['EFI/BOOT/BOOTX64.EFI'] @@ -274,12 +285,15 @@ Boot0002: VENDMAGIC FvFile(9f3c6294-bf9b-4208-9808-be45dfc34b51) mock_execute.assert_has_calls(expected) @mock.patch.object(os.path, 'exists', lambda *_: False) + @mock.patch.object(hardware, 'is_md_device', autospec=True) @mock.patch.object(efi_utils, '_get_efi_bootloaders', autospec=True) @mock.patch.object(os, 'makedirs', autospec=True) - def test_wholedisk(self, mkdir_mock, mock_efi_bl, mock_utils_efi_part, - mock_get_part_uuid, mock_execute, mock_rescan): + def test_wholedisk(self, mkdir_mock, mock_efi_bl, mock_is_md_device, + mock_utils_efi_part, mock_get_part_uuid, mock_execute, + mock_rescan): mock_utils_efi_part.return_value = {'number': '1'} mock_get_part_uuid.side_effect = Exception + mock_is_md_device.return_value = False mock_efi_bl.return_value = ['EFI/BOOT/BOOTX64.EFI'] @@ -304,3 +318,56 @@ Boot0002: VENDMAGIC FvFile(9f3c6294-bf9b-4208-9808-be45dfc34b51) mkdir_mock.assert_called_once_with(self.fake_dir + '/boot/efi') mock_efi_bl.assert_called_once_with(self.fake_dir + '/boot/efi') mock_execute.assert_has_calls(expected) + + @mock.patch.object(os.path, 'exists', lambda *_: False) + @mock.patch.object(hardware, 'get_component_devices', autospec=True) + @mock.patch.object(image, + 'prepare_boot_partitions_for_softraid', + autospec=True) + @mock.patch.object(hardware, 'get_holder_disks', autospec=True) + @mock.patch.object(hardware, 'is_md_device', autospec=True) + @mock.patch.object(efi_utils, '_get_efi_bootloaders', autospec=True) + @mock.patch.object(os, 'makedirs', autospec=True) + def test_software_raid(self, mkdir_mock, mock_efi_bl, mock_is_md_device, + mock_get_holder_disks, mock_prepare, + mock_get_component_devices, + mock_utils_efi_part, mock_get_part_uuid, + mock_execute, mock_rescan): + mock_utils_efi_part.return_value = {'number': '1'} + mock_get_part_uuid.side_effect = Exception + mock_is_md_device.return_value = True + mock_get_holder_disks.return_value = ['/dev/sda', '/dev/sdb'] + mock_prepare.return_value = '/dev/md125' + mock_get_component_devices.return_value = ['/dev/sda3', '/dev/sdb3'] + + mock_efi_bl.return_value = ['EFI/BOOT/BOOTX64.EFI'] + + mock_execute.side_effect = iter([('', ''), ('', ''), + ('', ''), ('', ''), + ('', ''), ('', ''), + ('', ''), ('', ''), + ('', '')]) + + expected = [mock.call('mount', self.fake_efi_system_part, + self.fake_dir + '/boot/efi'), + mock.call('umount', self.fake_dir + '/boot/efi', + attempts=3, delay_on_retry=True), + mock.call('mount', self.fake_efi_system_part, + self.fake_dir + '/boot/efi'), + mock.call('efibootmgr', '-v'), + mock.call('efibootmgr', '-v', '-c', '-d', '/dev/sda3', + '-p', '3', '-w', '-L', 'ironic1 (RAID, part0)', + '-l', '\\EFI\\BOOT\\BOOTX64.EFI'), + mock.call('efibootmgr', '-v'), + mock.call('efibootmgr', '-v', '-c', '-d', '/dev/sdb3', + '-p', '3', '-w', '-L', 'ironic1 (RAID, part1)', + '-l', '\\EFI\\BOOT\\BOOTX64.EFI'), + mock.call('umount', self.fake_dir + '/boot/efi', + attempts=3, delay_on_retry=True), + mock.call('sync')] + + result = efi_utils.manage_uefi(self.fake_dev, None) + self.assertTrue(result) + mkdir_mock.assert_called_once_with(self.fake_dir + '/boot/efi') + mock_efi_bl.assert_called_once_with(self.fake_dir + '/boot/efi') + mock_execute.assert_has_calls(expected) diff --git a/ironic_python_agent/tests/unit/test_hardware.py b/ironic_python_agent/tests/unit/test_hardware.py index 482bf344..7b19931b 100644 --- a/ironic_python_agent/tests/unit/test_hardware.py +++ b/ironic_python_agent/tests/unit/test_hardware.py @@ -3660,9 +3660,9 @@ class TestGenericHardwareManager(base.IronicAgentTest): @mock.patch.object(hardware, '_get_md_uuid', autospec=True) @mock.patch.object(hardware, 'list_all_block_devices', autospec=True) @mock.patch.object(il_utils, 'execute', autospec=True) - def test__get_component_devices(self, mocked_execute, - mocked_list_all_block_devices, - mocked_md_uuid): + def test_get_component_devices(self, mocked_execute, + mocked_list_all_block_devices, + mocked_md_uuid): raid_device1 = hardware.BlockDevice('/dev/md0', 'RAID-1', 107374182400, True) sda = hardware.BlockDevice('/dev/sda', 'model12', 21, True) @@ -3682,7 +3682,7 @@ class TestGenericHardwareManager(base.IronicAgentTest): [hws.MDADM_EXAMINE_OUTPUT_NON_MEMBER, '_'], ] - component_devices = hardware._get_component_devices(raid_device1) + component_devices = hardware.get_component_devices(raid_device1) self.assertEqual(['/dev/sda1'], component_devices) mocked_execute.assert_has_calls([ mock.call('mdadm', '--examine', '/dev/sda', @@ -3739,7 +3739,7 @@ class TestGenericHardwareManager(base.IronicAgentTest): self.assertEqual(['/dev/sda'], holder_disks) @mock.patch.object(hardware, 'get_holder_disks', autospec=True) - @mock.patch.object(hardware, '_get_component_devices', autospec=True) + @mock.patch.object(hardware, 'get_component_devices', autospec=True) @mock.patch.object(hardware, 'list_all_block_devices', autospec=True) @mock.patch.object(il_utils, 'execute', autospec=True) def test_delete_configuration(self, mocked_execute, mocked_list, @@ -3827,7 +3827,7 @@ class TestGenericHardwareManager(base.IronicAgentTest): mock.call('mdadm', '--assemble', '--scan', check_exit_code=False), ]) - @mock.patch.object(hardware, '_get_component_devices', autospec=True) + @mock.patch.object(hardware, 'get_component_devices', autospec=True) @mock.patch.object(hardware, 'list_all_block_devices', autospec=True) @mock.patch.object(il_utils, 'execute', autospec=True) def test_delete_configuration_partition(self, mocked_execute, mocked_list, @@ -3852,7 +3852,7 @@ class TestGenericHardwareManager(base.IronicAgentTest): mock.call('mdadm', '--assemble', '--scan', check_exit_code=False), ]) - @mock.patch.object(hardware, '_get_component_devices', autospec=True) + @mock.patch.object(hardware, 'get_component_devices', autospec=True) @mock.patch.object(hardware, 'list_all_block_devices', autospec=True) @mock.patch.object(il_utils, 'execute', autospec=True) def test_delete_configuration_failure_blocks_remaining( diff --git a/releasenotes/notes/move_swraid_to_efibootmgr-d87c1bfde1661fb5.yaml b/releasenotes/notes/move_swraid_to_efibootmgr-d87c1bfde1661fb5.yaml new file mode 100644 index 00000000..3fa29284 --- /dev/null +++ b/releasenotes/notes/move_swraid_to_efibootmgr-d87c1bfde1661fb5.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Use efibootmgr instead of grub2-install for software RAID. + This fixes an issue with images which include newer versions + of grub2-install as they refuse bootloader installations in + UEFI boot mode due to the lack of secure boot support. -- cgit v1.2.1