def _test_scan_partition_table_by_type(self, mocked_execute, table_type_output, expected_table_type): parted_ret = PARTED_OUTPUT_UNFORMATTED.format(table_type_output) mocked_execute.side_effect = [ (parted_ret, None), ] ret = utils.scan_partition_table_type('hello') mocked_execute.assert_has_calls( [mock.call('parted', '-s', 'hello', '--', 'print')]) self.assertEqual(expected_table_type, ret)
def _prepare_boot_partitions_for_softraid(device, holders, efi_part, target_boot_mode): """Prepare boot partitions when relevant. Create either efi partitions or bios boot partitions for softraid, according to both target boot mode and disk holders partition table types. :param device: the softraid device path :param holders: the softraid drive members :param efi_part: when relevant the efi partition coming from the image deployed on softraid device, can be/is often None :param target_boot_mode: target boot mode can be bios/uefi/None or anything else for unspecified :returns: the efi partition paths on softraid disk holders when target boot mode is uefi, empty list otherwise. """ efi_partitions = [] # Actually any fat partition could be a candidate. Let's assume the # partition also has the esp flag if target_boot_mode == 'uefi': if not efi_part: LOG.debug( "No explicit EFI partition provided. Scanning for any " "EFI partition located on software RAID device %s to " "be relocated", device) # NOTE: for whole disk images, no efi part uuid will be provided. # Let's try to scan for esp on the root softraid device. If not # found, it's fine in most cases to just create an empty esp and # let grub handle the magic. efi_part = utils.get_efi_part_on_device(device) if efi_part: efi_part = '{}p{}'.format(device, efi_part) LOG.info("Creating EFI partitions on software RAID holder disks") # We know that we kept this space when configuring raid,see # hardware.GenericHardwareManager.create_configuration. # We could also directly get the EFI partition size. partsize_mib = raid_utils.ESP_SIZE_MIB partlabel_prefix = 'uefi-holder-' for number, holder in enumerate(holders): # NOTE: see utils.get_partition_table_type_from_specs # for uefi we know that we have setup a gpt partition table, # sgdisk can be used to edit table, more user friendly # for alignment and relative offsets partlabel = '{}{}'.format(partlabel_prefix, number) out, _u = utils.execute('sgdisk', '-F', holder) start_sector = '{}s'.format(out.splitlines()[-1].strip()) out, _u = utils.execute( 'sgdisk', '-n', '0:{}:+{}MiB'.format(start_sector, partsize_mib), '-t', '0:ef00', '-c', '0:{}'.format(partlabel), holder) # Refresh part table utils.execute("partprobe") utils.execute("blkid") target_part, _u = utils.execute("blkid", "-l", "-t", "PARTLABEL={}".format(partlabel), holder) target_part = target_part.splitlines()[-1].split(':', 1)[0] LOG.debug("EFI partition %s created on holder disk %s", target_part, holder) if efi_part: LOG.debug("Relocating EFI %s to holder part %s", efi_part, target_part) # Blockdev copy utils.execute("cp", efi_part, target_part) else: # Creating a label is just to make life easier if number == 0: fslabel = 'efi-part' else: # bak, label is limited to 11 chars fslabel = 'efi-part-b' ilib_utils.mkfs(fs='vfat', path=target_part, label=fslabel) efi_partitions.append(target_part) # TBD: Would not hurt to destroy source efi part when defined, # for clarity. elif target_boot_mode == 'bios': partlabel_prefix = 'bios-boot-part-' for number, holder in enumerate(holders): label = utils.scan_partition_table_type(holder) if label == 'gpt': LOG.debug("Creating bios boot partition on disk holder %s", holder) out, _u = utils.execute('sgdisk', '-F', holder) start_sector = '{}s'.format(out.splitlines()[-1].strip()) partlabel = '{}{}'.format(partlabel_prefix, number) out, _u = utils.execute('sgdisk', '-n', '0:{}:+2MiB'.format(start_sector), '-t', '0:ef02', '-c', '0:{}'.format(partlabel), holder) # Q: MBR case, could we dd the boot code from the softraid # (446 first bytes) if we detect a bootloader with # _is_bootloader_loaded? # A: This won't work. Because it includes the address on the # disk, as in virtual disk, where to load the data from. # Since there is a structural difference, this means it will # fail. # Just an empty list if not uefi boot mode, nvm, not used anyway return efi_partitions