Merge "Software RAID: RAID the ESPs" into stable/wallaby

This commit is contained in:
Zuul 2021-06-01 19:11:46 +00:00 committed by Gerrit Code Review
commit dc78c5074a
3 changed files with 124 additions and 126 deletions

View File

@ -378,8 +378,9 @@ def _prepare_boot_partitions_for_softraid(device, holders, efi_part,
target_boot_mode): target_boot_mode):
"""Prepare boot partitions when relevant. """Prepare boot partitions when relevant.
Create either efi partitions or bios boot partitions for softraid, Create either a RAIDed EFI partition or bios boot partitions for software
according to both target boot mode and disk holders partition table types. RAID, according to both target boot mode and disk holders partition table
types.
:param device: the softraid device path :param device: the softraid device path
:param holders: the softraid drive members :param holders: the softraid drive members
@ -388,11 +389,9 @@ def _prepare_boot_partitions_for_softraid(device, holders, efi_part,
:param target_boot_mode: target boot mode can be bios/uefi/None :param target_boot_mode: target boot mode can be bios/uefi/None
or anything else for unspecified or anything else for unspecified
:returns: the efi partition paths on softraid disk holders when target :returns: the path to the ESP md device when target boot mode is uefi,
boot mode is uefi, empty list otherwise. nothing otherwise.
""" """
efi_partitions = []
# Actually any fat partition could be a candidate. Let's assume the # Actually any fat partition could be a candidate. Let's assume the
# partition also has the esp flag # partition also has the esp flag
if target_boot_mode == 'uefi': if target_boot_mode == 'uefi':
@ -417,6 +416,7 @@ def _prepare_boot_partitions_for_softraid(device, holders, efi_part,
# We could also directly get the EFI partition size. # We could also directly get the EFI partition size.
partsize_mib = raid_utils.ESP_SIZE_MIB partsize_mib = raid_utils.ESP_SIZE_MIB
partlabel_prefix = 'uefi-holder-' partlabel_prefix = 'uefi-holder-'
efi_partitions = []
for number, holder in enumerate(holders): for number, holder in enumerate(holders):
# NOTE: see utils.get_partition_table_type_from_specs # NOTE: see utils.get_partition_table_type_from_specs
# for uefi we know that we have setup a gpt partition table, # for uefi we know that we have setup a gpt partition table,
@ -438,26 +438,31 @@ def _prepare_boot_partitions_for_softraid(device, holders, efi_part,
"blkid", "-l", "-t", "PARTLABEL={}".format(partlabel), holder) "blkid", "-l", "-t", "PARTLABEL={}".format(partlabel), holder)
target_part = target_part.splitlines()[-1].split(':', 1)[0] target_part = target_part.splitlines()[-1].split(':', 1)[0]
efi_partitions.append(target_part)
LOG.debug("EFI partition %s created on holder disk %s", LOG.debug("EFI partition %s created on holder disk %s",
target_part, holder) target_part, holder)
if efi_part: # RAID the ESPs, metadata=1.0 is mandatory to be able to boot
LOG.debug("Relocating EFI %s to holder part %s", efi_part, md_device = '/dev/md/esp'
target_part) LOG.debug("Creating md device {} for the ESPs on {}".format(
# Blockdev copy md_device, efi_partitions))
utils.execute("cp", efi_part, target_part) utils.execute('mdadm', '--create', md_device, '--force',
else: '--run', '--metadata=1.0', '--level', '1',
# Creating a label is just to make life easier '--raid-devices', len(efi_partitions),
if number == 0: *efi_partitions)
fslabel = 'efi-part'
else: if efi_part:
# bak, label is limited to 11 chars # Blockdev copy the source ESP and erase it
fslabel = 'efi-part-b' LOG.debug("Relocating EFI %s to %s", efi_part, md_device)
ilib_utils.mkfs(fs='vfat', path=target_part, label=fslabel) utils.execute('cp', efi_part, md_device)
efi_partitions.append(target_part) LOG.debug("Erasing EFI partition %s", efi_part)
# TBD: Would not hurt to destroy source efi part when defined, utils.execute('wipefs', '-a', efi_part)
# for clarity. else:
fslabel = 'efi-part'
ilib_utils.mkfs(fs='vfat', path=md_device, label=fslabel)
return md_device
elif target_boot_mode == 'bios': elif target_boot_mode == 'bios':
partlabel_prefix = 'bios-boot-part-' partlabel_prefix = 'bios-boot-part-'
@ -481,9 +486,6 @@ def _prepare_boot_partitions_for_softraid(device, holders, efi_part,
# Since there is a structural difference, this means it will # Since there is a structural difference, this means it will
# fail. # fail.
# Just an empty list if not uefi boot mode, nvm, not used anyway
return efi_partitions
def _umount_all_partitions(path, path_variable, umount_warn_msg): def _umount_all_partitions(path, path_variable, umount_warn_msg):
"""Umount all partitions we may have mounted""" """Umount all partitions we may have mounted"""
@ -513,7 +515,7 @@ def _install_grub2(device, root_uuid, efi_system_part_uuid=None,
"""Install GRUB2 bootloader on a given device.""" """Install GRUB2 bootloader on a given device."""
LOG.debug("Installing GRUB2 bootloader on device %s", device) LOG.debug("Installing GRUB2 bootloader on device %s", device)
efi_partitions = None efi_partition = None
efi_part = None efi_part = None
efi_partition_mount_point = None efi_partition_mount_point = None
efi_mounted = False efi_mounted = False
@ -550,15 +552,14 @@ def _install_grub2(device, root_uuid, efi_system_part_uuid=None,
path = tempfile.mkdtemp() path = tempfile.mkdtemp()
if efi_system_part_uuid: if efi_system_part_uuid:
efi_part = _get_partition(device, uuid=efi_system_part_uuid) efi_part = _get_partition(device, uuid=efi_system_part_uuid)
efi_partitions = [efi_part] efi_partition = efi_part
if hardware.is_md_device(device): if hardware.is_md_device(device):
holders = hardware.get_holder_disks(device) holders = hardware.get_holder_disks(device)
efi_partitions = _prepare_boot_partitions_for_softraid( efi_partition = _prepare_boot_partitions_for_softraid(
device, holders, efi_part, target_boot_mode device, holders, efi_part, target_boot_mode
) )
if efi_partitions: if efi_partition:
efi_partition_mount_point = os.path.join(path, "boot/efi") efi_partition_mount_point = os.path.join(path, "boot/efi")
# For power we want to install grub directly onto the PreP partition # For power we want to install grub directly onto the PreP partition
@ -585,7 +586,7 @@ def _install_grub2(device, root_uuid, efi_system_part_uuid=None,
# point if we have no efi partitions at all. # point if we have no efi partitions at all.
efi_preserved = _try_preserve_efi_assets( efi_preserved = _try_preserve_efi_assets(
device, path, efi_system_part_uuid, device, path, efi_system_part_uuid,
efi_partitions, efi_partition_mount_point) efi_partition, efi_partition_mount_point)
if efi_preserved: if efi_preserved:
_append_uefi_to_fstab(path, efi_system_part_uuid) _append_uefi_to_fstab(path, efi_system_part_uuid)
# Success preserving efi assets # Success preserving efi assets
@ -614,50 +615,48 @@ def _install_grub2(device, root_uuid, efi_system_part_uuid=None,
{'path': path}, shell=True, {'path': path}, shell=True,
env_variables={'PATH': path_variable}) env_variables={'PATH': path_variable})
if efi_partitions: if efi_partition:
if not os.path.exists(efi_partition_mount_point): if not os.path.exists(efi_partition_mount_point):
os.makedirs(efi_partition_mount_point) os.makedirs(efi_partition_mount_point)
LOG.warning("GRUB2 will be installed for UEFI on efi partitions " LOG.warning("GRUB2 will be installed for UEFI on efi partition "
"%s using the install command which does not place " "%s using the install command which does not place "
"Secure Boot signed binaries.", efi_partitions) "Secure Boot signed binaries.", efi_partition)
for efi_partition in efi_partitions: utils.execute('mount', efi_partition, efi_partition_mount_point)
utils.execute( efi_mounted = True
'mount', efi_partition, efi_partition_mount_point) # FIXME(rg): does not work in cross boot mode case (target
efi_mounted = True # boot mode differs from ramdisk one)
# FIXME(rg): does not work in cross boot mode case (target # Probe for the correct target (depends on the arch, example
# boot mode differs from ramdisk one) # --target=x86_64-efi)
# Probe for the correct target (depends on the arch, example utils.execute('chroot %(path)s /bin/sh -c '
# --target=x86_64-efi) '"%(bin)s-install"' %
utils.execute('chroot %(path)s /bin/sh -c ' {'path': path, 'bin': binary_name},
'"%(bin)s-install"' % shell=True,
{'path': path, 'bin': binary_name}, env_variables={
shell=True, 'PATH': path_variable
env_variables={ })
'PATH': path_variable # Also run grub-install with --removable, this installs grub to
}) # the EFI fallback path. Useful if the NVRAM wasn't written
# Also run grub-install with --removable, this installs grub to # correctly, was reset or if testing with virt as libvirt
# the EFI fallback path. Useful if the NVRAM wasn't written # resets the NVRAM on instance start.
# correctly, was reset or if testing with virt as libvirt # This operation is essentially a copy operation. Use of the
# resets the NVRAM on instance start. # --removable flag, per the grub-install source code changes
# This operation is essentially a copy operation. Use of the # the default file to be copied, destination file name, and
# --removable flag, per the grub-install source code changes # prevents NVRAM from being updated.
# the default file to be copied, destination file name, and # We only run grub2_install for uefi if we can't verify the
# prevents NVRAM from being updated. # uefi bits
# We only run grub2_install for uefi if we can't verify the utils.execute('chroot %(path)s /bin/sh -c '
# uefi bits '"%(bin)s-install --removable"' %
utils.execute('chroot %(path)s /bin/sh -c ' {'path': path, 'bin': binary_name},
'"%(bin)s-install --removable"' % shell=True,
{'path': path, 'bin': binary_name}, env_variables={
shell=True, 'PATH': path_variable
env_variables={ })
'PATH': path_variable utils.execute('umount', efi_partition_mount_point, attempts=3,
}) delay_on_retry=True)
utils.execute('umount', efi_partition_mount_point, attempts=3, efi_mounted = False
delay_on_retry=True)
efi_mounted = False
# NOTE: probably never needed for grub-mkconfig, does not hurt in # NOTE: probably never needed for grub-mkconfig, does not hurt in
# case of doubt, cleaned in the finally clause anyway # case of doubt, cleaned in the finally clause anyway
utils.execute('mount', efi_partitions[0], utils.execute('mount', efi_partition,
efi_partition_mount_point) efi_partition_mount_point)
efi_mounted = True efi_mounted = True
else: else:
@ -789,7 +788,7 @@ def _mount_for_chroot(path):
def _try_preserve_efi_assets(device, path, def _try_preserve_efi_assets(device, path,
efi_system_part_uuid, efi_system_part_uuid,
efi_partitions, efi_partition,
efi_partition_mount_point): efi_partition_mount_point):
"""Attempt to preserve UEFI boot assets. """Attempt to preserve UEFI boot assets.
@ -799,8 +798,8 @@ def _try_preserve_efi_assets(device, path,
which we should examine to preserve assets from. which we should examine to preserve assets from.
:param efi_system_part_uuid: The partition ID representing the :param efi_system_part_uuid: The partition ID representing the
created EFI system partition. created EFI system partition.
:param efi_partitions: The list of partitions upon wich to :param efi_partition: The partitions upon wich to write the preserved
write the preserved assets to. assets to.
:param efi_partition_mount_point: The folder at which to mount :param efi_partition_mount_point: The folder at which to mount
the assets for the process of the assets for the process of
preservation. preservation.
@ -823,7 +822,7 @@ def _try_preserve_efi_assets(device, path,
# But first, if we have grub, we should try to build a grub config! # But first, if we have grub, we should try to build a grub config!
LOG.debug('EFI asset folder detected, attempting to preserve assets.') LOG.debug('EFI asset folder detected, attempting to preserve assets.')
if _preserve_efi_assets(path, efi_assets_folder, if _preserve_efi_assets(path, efi_assets_folder,
efi_partitions, efi_partition,
efi_partition_mount_point): efi_partition_mount_point):
try: try:
# Since we have preserved the assets, we should be able # Since we have preserved the assets, we should be able
@ -903,21 +902,21 @@ def _efi_boot_setup(device, efi_system_part_uuid=None, target_boot_mode=None):
return False return False
def _preserve_efi_assets(path, efi_assets_folder, efi_partitions, def _preserve_efi_assets(path, efi_assets_folder, efi_partition,
efi_partition_mount_point): efi_partition_mount_point):
"""Preserve the EFI assets in a partition image. """Preserve the EFI assets in a partition image.
:param path: The path used for the mounted image filesystem. :param path: The path used for the mounted image filesystem.
:param efi_assets_folder: The folder where we can find the :param efi_assets_folder: The folder where we can find the
UEFI assets required for booting. UEFI assets required for booting.
:param efi_partitions: The list of partitions upon which to :param efi_partition: The partition upon which to write the
write the perserved assets to. perserved assets to.
:param efi_partition_mount_point: The folder at which to mount :param efi_partition_mount_point: The folder at which to mount
the assets for the process of the assets for the process of
preservation. preservation.
:returns: True if EFI assets were able to be located and preserved :returns: True if EFI assets were able to be located and preserved
to their appropriate locations based upon the supplied to their appropriate locations based upon the supplied
efi_partitions list. efi_partition.
False if any error is encountered in this process. False if any error is encountered in this process.
""" """
try: try:
@ -966,18 +965,16 @@ def _preserve_efi_assets(path, efi_assets_folder, efi_partitions,
except (IOError, OSError, shutil.SameFileError) as e: except (IOError, OSError, shutil.SameFileError) as e:
LOG.warning('Failed to copy grubenv file. ' LOG.warning('Failed to copy grubenv file. '
'Error: %s', e) 'Error: %s', e)
# Loop through partitions because software RAID. utils.execute('mount', '-t', 'vfat', efi_partition,
for efi_part in efi_partitions: efi_partition_mount_point)
utils.execute('mount', '-t', 'vfat', efi_part, shutil.copytree(save_efi, efi_assets_folder)
efi_partition_mount_point) LOG.debug('Files preserved to %(disk)s for %(part)s. '
shutil.copytree(save_efi, efi_assets_folder) 'Files: %(filelist)s From: %(from)s',
LOG.debug('Files preserved to %(disk)s for %(part)s. ' {'disk': efi_partition,
'Files: %(filelist)s From: %(from)s', 'part': efi_partition_mount_point,
{'disk': efi_part, 'filelist': os.listdir(efi_assets_folder),
'part': efi_partition_mount_point, 'from': save_efi})
'filelist': os.listdir(efi_assets_folder), utils.execute('umount', efi_partition_mount_point)
'from': save_efi})
utils.execute('umount', efi_partition_mount_point)
return True return True
except Exception as e: except Exception as e:
LOG.debug('Failed to preserve EFI assets. Error %s', e) LOG.debug('Failed to preserve EFI assets. Error %s', e)

View File

@ -1200,7 +1200,7 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
mock_preserve_efi_assets.assert_called_with( mock_preserve_efi_assets.assert_called_with(
self.fake_dir, self.fake_dir,
self.fake_dir + '/boot/efi/EFI', self.fake_dir + '/boot/efi/EFI',
['/dev/fake1'], '/dev/fake1',
self.fake_dir + '/boot/efi') self.fake_dir + '/boot/efi')
mock_append_to_fstab.assert_called_with(self.fake_dir, mock_append_to_fstab.assert_called_with(self.fake_dir,
self.fake_efi_system_part_uuid) self.fake_efi_system_part_uuid)
@ -1526,16 +1526,17 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
(None, None), # partprobe (None, None), # partprobe
(None, None), # blkid (None, None), # blkid
('/dev/sda12: dsfkgsdjfg', None), # blkid ('/dev/sda12: dsfkgsdjfg', None), # blkid
(None, None), # cp
('452', None), # sgdisk -F ('452', None), # sgdisk -F
(None, None), # sgdisk create part (None, None), # sgdisk create part
(None, None), # partprobe (None, None), # partprobe
(None, None), # blkid (None, None), # blkid
('/dev/sdb14: whatever', None), # blkid ('/dev/sdb14: whatever', None), # blkid
(None, None), # mdadm
(None, None), # cp (None, None), # cp
(None, None), # wipefs
] ]
efi_parts = image._prepare_boot_partitions_for_softraid( efi_part = image._prepare_boot_partitions_for_softraid(
'/dev/md0', ['/dev/sda', '/dev/sdb'], None, '/dev/md0', ['/dev/sda', '/dev/sdb'], None,
target_boot_mode='uefi') target_boot_mode='uefi')
@ -1548,7 +1549,6 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
mock.call('blkid'), mock.call('blkid'),
mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-0', mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-0',
'/dev/sda'), '/dev/sda'),
mock.call('cp', '/dev/md0p12', '/dev/sda12'),
mock.call('sgdisk', '-F', '/dev/sdb'), mock.call('sgdisk', '-F', '/dev/sdb'),
mock.call('sgdisk', '-n', '0:452s:+550MiB', '-t', '0:ef00', '-c', mock.call('sgdisk', '-n', '0:452s:+550MiB', '-t', '0:ef00', '-c',
'0:uefi-holder-1', '/dev/sdb'), '0:uefi-holder-1', '/dev/sdb'),
@ -1556,10 +1556,14 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
mock.call('blkid'), mock.call('blkid'),
mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-1', mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-1',
'/dev/sdb'), '/dev/sdb'),
mock.call('cp', '/dev/md0p12', '/dev/sdb14') mock.call('mdadm', '--create', '/dev/md/esp', '--force', '--run',
'--metadata=1.0', '--level', '1', '--raid-devices', 2,
'/dev/sda12', '/dev/sdb14'),
mock.call('cp', '/dev/md0p12', '/dev/md/esp'),
mock.call('wipefs', '-a', '/dev/md0p12')
] ]
mock_execute.assert_has_calls(expected, any_order=False) mock_execute.assert_has_calls(expected, any_order=False)
self.assertEqual(efi_parts, ['/dev/sda12', '/dev/sdb14']) self.assertEqual(efi_part, '/dev/md/esp')
@mock.patch.object(utils, 'get_efi_part_on_device', autospec=True) @mock.patch.object(utils, 'get_efi_part_on_device', autospec=True)
@mock.patch.object(ilib_utils, 'mkfs', autospec=True) @mock.patch.object(ilib_utils, 'mkfs', autospec=True)
@ -1577,9 +1581,10 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
(None, None), # partprobe (None, None), # partprobe
(None, None), # blkid (None, None), # blkid
('/dev/sdb14: whatever', None), # blkid ('/dev/sdb14: whatever', None), # blkid
(None, None), # mdadm
] ]
efi_parts = image._prepare_boot_partitions_for_softraid( efi_part = image._prepare_boot_partitions_for_softraid(
'/dev/md0', ['/dev/sda', '/dev/sdb'], None, '/dev/md0', ['/dev/sda', '/dev/sdb'], None,
target_boot_mode='uefi') target_boot_mode='uefi')
@ -1602,10 +1607,9 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
] ]
mock_execute.assert_has_calls(expected, any_order=False) mock_execute.assert_has_calls(expected, any_order=False)
mock_mkfs.assert_has_calls([ mock_mkfs.assert_has_calls([
mock.call(path='/dev/sda12', label='efi-part', fs='vfat'), mock.call(path='/dev/md/esp', label='efi-part', fs='vfat'),
mock.call(path='/dev/sdb14', label='efi-part-b', fs='vfat'),
], any_order=False) ], any_order=False)
self.assertEqual(efi_parts, ['/dev/sda12', '/dev/sdb14']) 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): self, mock_execute, mock_dispatch):
@ -1615,16 +1619,17 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
(None, None), # partprobe (None, None), # partprobe
(None, None), # blkid (None, None), # blkid
('/dev/sda12: dsfkgsdjfg', None), # blkid ('/dev/sda12: dsfkgsdjfg', None), # blkid
(None, None), # cp
('452', None), # sgdisk -F ('452', None), # sgdisk -F
(None, None), # sgdisk create part (None, None), # sgdisk create part
(None, None), # partprobe (None, None), # partprobe
(None, None), # blkid (None, None), # blkid
('/dev/sdb14: whatever', None), # blkid ('/dev/sdb14: whatever', None), # blkid
(None, None), # mdadm create
(None, None), # cp (None, None), # cp
(None, None), # wipefs
] ]
efi_parts = image._prepare_boot_partitions_for_softraid( efi_part = image._prepare_boot_partitions_for_softraid(
'/dev/md0', ['/dev/sda', '/dev/sdb'], '/dev/md0p15', '/dev/md0', ['/dev/sda', '/dev/sdb'], '/dev/md0p15',
target_boot_mode='uefi') target_boot_mode='uefi')
@ -1636,7 +1641,6 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
mock.call('blkid'), mock.call('blkid'),
mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-0', mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-0',
'/dev/sda'), '/dev/sda'),
mock.call('cp', '/dev/md0p15', '/dev/sda12'),
mock.call('sgdisk', '-F', '/dev/sdb'), mock.call('sgdisk', '-F', '/dev/sdb'),
mock.call('sgdisk', '-n', '0:452s:+550MiB', '-t', '0:ef00', '-c', mock.call('sgdisk', '-n', '0:452s:+550MiB', '-t', '0:ef00', '-c',
'0:uefi-holder-1', '/dev/sdb'), '0:uefi-holder-1', '/dev/sdb'),
@ -1644,17 +1648,21 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
mock.call('blkid'), mock.call('blkid'),
mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-1', mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-1',
'/dev/sdb'), '/dev/sdb'),
mock.call('cp', '/dev/md0p15', '/dev/sdb14') mock.call('mdadm', '--create', '/dev/md/esp', '--force', '--run',
'--metadata=1.0', '--level', '1', '--raid-devices', 2,
'/dev/sda12', '/dev/sdb14'),
mock.call('cp', '/dev/md0p15', '/dev/md/esp'),
mock.call('wipefs', '-a', '/dev/md0p15')
] ]
mock_execute.assert_has_calls(expected, any_order=False) mock_execute.assert_has_calls(expected, any_order=False)
self.assertEqual(efi_parts, ['/dev/sda12', '/dev/sdb14']) self.assertEqual(efi_part, '/dev/md/esp')
@mock.patch.object(utils, 'scan_partition_table_type', autospec=True, @mock.patch.object(utils, 'scan_partition_table_type', autospec=True,
return_value='msdos') 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): self, mock_label_scan, mock_execute, mock_dispatch):
efi_parts = image._prepare_boot_partitions_for_softraid( efi_part = image._prepare_boot_partitions_for_softraid(
'/dev/md0', ['/dev/sda', '/dev/sdb'], 'notusedanyway', '/dev/md0', ['/dev/sda', '/dev/sdb'], 'notusedanyway',
target_boot_mode='bios') target_boot_mode='bios')
@ -1663,7 +1671,7 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
mock.call('/dev/sdb'), mock.call('/dev/sdb'),
] ]
mock_label_scan.assert_has_calls(expected, any_order=False) mock_label_scan.assert_has_calls(expected, any_order=False)
self.assertEqual(efi_parts, []) self.assertIsNone(efi_part)
@mock.patch.object(utils, 'scan_partition_table_type', autospec=True, @mock.patch.object(utils, 'scan_partition_table_type', autospec=True,
return_value='gpt') return_value='gpt')
@ -1677,7 +1685,7 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
(None, None), # bios boot grub (None, None), # bios boot grub
] ]
efi_parts = image._prepare_boot_partitions_for_softraid( efi_part = image._prepare_boot_partitions_for_softraid(
'/dev/md0', ['/dev/sda', '/dev/sdb'], 'notusedanyway', '/dev/md0', ['/dev/sda', '/dev/sdb'], 'notusedanyway',
target_boot_mode='bios') target_boot_mode='bios')
@ -1698,7 +1706,7 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
] ]
mock_execute.assert_has_calls(expected_exec, any_order=False) mock_execute.assert_has_calls(expected_exec, any_order=False)
self.assertEqual(efi_parts, []) self.assertIsNone(efi_part)
@mock.patch.object(image, '_is_bootloader_loaded', lambda *_: True) @mock.patch.object(image, '_is_bootloader_loaded', lambda *_: True)
@mock.patch.object(hardware, 'is_md_device', autospec=True) @mock.patch.object(hardware, 'is_md_device', autospec=True)
@ -1711,7 +1719,7 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
@mock.patch.object(image, '_get_partition', autospec=True) @mock.patch.object(image, '_get_partition', autospec=True)
@mock.patch.object(image, '_prepare_boot_partitions_for_softraid', @mock.patch.object(image, '_prepare_boot_partitions_for_softraid',
autospec=True, autospec=True,
return_value=['/dev/sda1', '/dev/sdb2']) return_value='/dev/md/esp')
@mock.patch.object(image, '_has_dracut', @mock.patch.object(image, '_has_dracut',
autospec=True, autospec=True,
return_value=False) return_value=False)
@ -1746,7 +1754,7 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
(self.fake_dir)), shell=True, (self.fake_dir)), shell=True,
env_variables={ env_variables={
'PATH': '/sbin:/bin:/usr/sbin:/sbin'}), 'PATH': '/sbin:/bin:/usr/sbin:/sbin'}),
mock.call('mount', '/dev/sda1', mock.call('mount', '/dev/md/esp',
self.fake_dir + '/boot/efi'), self.fake_dir + '/boot/efi'),
mock.call(('chroot %s /bin/sh -c "grub-install"' % mock.call(('chroot %s /bin/sh -c "grub-install"' %
self.fake_dir), shell=True, self.fake_dir), shell=True,
@ -1760,21 +1768,7 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
mock.call( mock.call(
'umount', self.fake_dir + '/boot/efi', 'umount', self.fake_dir + '/boot/efi',
attempts=3, delay_on_retry=True), attempts=3, delay_on_retry=True),
mock.call('mount', '/dev/sdb2', mock.call('mount', '/dev/md/esp',
self.fake_dir + '/boot/efi'),
mock.call(('chroot %s /bin/sh -c "grub-install"' %
self.fake_dir), shell=True,
env_variables={
'PATH': '/sbin:/bin:/usr/sbin:/sbin'}),
mock.call(('chroot %s /bin/sh -c '
'"grub-install --removable"' %
self.fake_dir), shell=True,
env_variables={
'PATH': '/sbin:/bin:/usr/sbin:/sbin'}),
mock.call(
'umount', self.fake_dir + '/boot/efi',
attempts=3, delay_on_retry=True),
mock.call('mount', '/dev/sda1',
'/tmp/fake-dir/boot/efi'), '/tmp/fake-dir/boot/efi'),
mock.call(('chroot %s /bin/sh -c ' mock.call(('chroot %s /bin/sh -c '
'"grub-mkconfig -o ' '"grub-mkconfig -o '

View File

@ -0,0 +1,7 @@
---
fixes:
- |
Mirrors the previously disconnected EFI system partitions (ESPs) in UEFI
software RAID setups. Disconnected ESPs can lead to nodes booting with
outdated kernel parameters or the UEFI firmware not finding bootable
kernels at all.