summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Wiebalck <Arne.Wiebalck@cern.ch>2022-01-28 08:38:28 +0100
committerArne Wiebalck <Arne.Wiebalck@cern.ch>2022-02-14 11:21:36 +0100
commita83f38479ec2925cd11839eeb0742d1ab278b868 (patch)
treeb1188897630671e20ae18341ab5af0da57d3e426
parentb8b1991bea20bb34075cb9295b16256cf0dabc95 (diff)
downloadironic-python-agent-a83f38479ec2925cd11839eeb0742d1ab278b868.tar.gz
Move prepare_boot_partitions_for_softraid to raid_utils
prepare_boot_partitions_for_softraid() is used in BIOS and UEFI modes to prepare the partitions for the bootloader. Move it from the image extensions to raid_utils to reflect this and avoid the import of an extension to efi_utils. Follow-up to 62c5674a600baeeef0af3b12baeab486870eb103. Change-Id: I9f5974fbbfea5e8cdfbb7e49bea375e5cbfdd145
-rw-r--r--ironic_python_agent/efi_utils.py4
-rw-r--r--ironic_python_agent/extensions/image.py121
-rw-r--r--ironic_python_agent/raid_utils.py118
-rw-r--r--ironic_python_agent/tests/unit/extensions/test_image.py210
-rw-r--r--ironic_python_agent/tests/unit/test_efi_utils.py4
-rw-r--r--ironic_python_agent/tests/unit/test_raid_utils.py218
6 files changed, 343 insertions, 332 deletions
diff --git a/ironic_python_agent/efi_utils.py b/ironic_python_agent/efi_utils.py
index 54d1e62f..ea7a9474 100644
--- a/ironic_python_agent/efi_utils.py
+++ b/ironic_python_agent/efi_utils.py
@@ -20,9 +20,9 @@ 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 raid_utils
from ironic_python_agent import utils
@@ -112,7 +112,7 @@ def manage_uefi(device, efi_system_part_uuid=None):
efi_mounted = False
holders = hardware.get_holder_disks(device)
- efi_md_device = image.prepare_boot_partitions_for_softraid(
+ efi_md_device = raid_utils.prepare_boot_partitions_for_softraid(
device, holders, efi_device_part, target_boot_mode='uefi'
)
efi_devices = hardware.get_component_devices(efi_md_device)
diff --git a/ironic_python_agent/extensions/image.py b/ironic_python_agent/extensions/image.py
index 6f20c8a8..892aa288 100644
--- a/ironic_python_agent/extensions/image.py
+++ b/ironic_python_agent/extensions/image.py
@@ -18,8 +18,6 @@ import re
import shutil
import tempfile
-from ironic_lib import disk_utils
-from ironic_lib import utils as ilib_utils
from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_log import log
@@ -104,123 +102,6 @@ def _is_bootloader_loaded(dev):
return _find_bootable_device(stdout, dev)
-# TODO(rg): handle PreP boot parts relocation as well
-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
- RAID, 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 path to the ESP md device when target boot mode is uefi,
- nothing otherwise.
- """
- # 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 = disk_utils.find_efi_partition(device)
- if efi_part:
- efi_part = '{}p{}'.format(device, efi_part['number'])
-
- 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-'
- efi_partitions = []
- 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]
- efi_partitions.append(target_part)
-
- LOG.debug("EFI partition %s created on holder disk %s",
- target_part, holder)
-
- # RAID the ESPs, metadata=1.0 is mandatory to be able to boot
- md_device = raid_utils.get_next_free_raid_device()
- LOG.debug("Creating md device %(md_device)s for the ESPs "
- "on %(efi_partitions)s",
- {'md_device': md_device, 'efi_partitions': efi_partitions})
- utils.execute('mdadm', '--create', md_device, '--force',
- '--run', '--metadata=1.0', '--level', '1',
- '--name', 'esp', '--raid-devices', len(efi_partitions),
- *efi_partitions)
-
- disk_utils.trigger_device_rescan(md_device)
-
- if efi_part:
- # Blockdev copy the source ESP and erase it
- LOG.debug("Relocating EFI %s to %s", efi_part, md_device)
- utils.execute('cp', efi_part, md_device)
- LOG.debug("Erasing EFI partition %s", efi_part)
- utils.execute('wipefs', '-a', efi_part)
- else:
- fslabel = 'efi-part'
- ilib_utils.mkfs(fs='vfat', path=md_device, label=fslabel)
-
- return md_device
-
- elif target_boot_mode == 'bios':
- partlabel_prefix = 'bios-boot-part-'
- for number, holder in enumerate(holders):
- label = disk_utils.get_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.
-
-
def _umount_all_partitions(path, path_variable, umount_warn_msg):
"""Umount all partitions we may have mounted"""
umount_binds_success = True
@@ -313,7 +194,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 = raid_utils.prepare_boot_partitions_for_softraid(
device, holders, efi_part, target_boot_mode
)
diff --git a/ironic_python_agent/raid_utils.py b/ironic_python_agent/raid_utils.py
index d4c338a8..0a53eec5 100644
--- a/ironic_python_agent/raid_utils.py
+++ b/ironic_python_agent/raid_utils.py
@@ -13,6 +13,7 @@
import copy
import re
+from ironic_lib import disk_utils
from ironic_lib import utils as il_utils
from oslo_concurrency import processutils
from oslo_log import log as logging
@@ -262,3 +263,120 @@ def get_next_free_raid_device():
return name
raise errors.SoftwareRAIDError("No free md (RAID) devices are left")
+
+
+# TODO(rg): handle PreP boot parts relocation as well
+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
+ RAID, 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 path to the ESP md device when target boot mode is uefi,
+ nothing otherwise.
+ """
+ # 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 = disk_utils.find_efi_partition(device)
+ if efi_part:
+ efi_part = '{}p{}'.format(device, efi_part['number'])
+
+ 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 = ESP_SIZE_MIB
+ partlabel_prefix = 'uefi-holder-'
+ efi_partitions = []
+ 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]
+ efi_partitions.append(target_part)
+
+ LOG.debug("EFI partition %s created on holder disk %s",
+ target_part, holder)
+
+ # RAID the ESPs, metadata=1.0 is mandatory to be able to boot
+ md_device = get_next_free_raid_device()
+ LOG.debug("Creating md device %(md_device)s for the ESPs "
+ "on %(efi_partitions)s",
+ {'md_device': md_device, 'efi_partitions': efi_partitions})
+ utils.execute('mdadm', '--create', md_device, '--force',
+ '--run', '--metadata=1.0', '--level', '1',
+ '--name', 'esp', '--raid-devices', len(efi_partitions),
+ *efi_partitions)
+
+ disk_utils.trigger_device_rescan(md_device)
+
+ if efi_part:
+ # Blockdev copy the source ESP and erase it
+ LOG.debug("Relocating EFI %s to %s", efi_part, md_device)
+ utils.execute('cp', efi_part, md_device)
+ LOG.debug("Erasing EFI partition %s", efi_part)
+ utils.execute('wipefs', '-a', efi_part)
+ else:
+ fslabel = 'efi-part'
+ il_utils.mkfs(fs='vfat', path=md_device, label=fslabel)
+
+ return md_device
+
+ elif target_boot_mode == 'bios':
+ partlabel_prefix = 'bios-boot-part-'
+ for number, holder in enumerate(holders):
+ label = disk_utils.get_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.
diff --git a/ironic_python_agent/tests/unit/extensions/test_image.py b/ironic_python_agent/tests/unit/extensions/test_image.py
index b2506b9c..6c45c455 100644
--- a/ironic_python_agent/tests/unit/extensions/test_image.py
+++ b/ironic_python_agent/tests/unit/extensions/test_image.py
@@ -1654,212 +1654,6 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
uuid=self.fake_root_uuid)
self.assertFalse(mock_dispatch.called)
- @mock.patch.object(disk_utils, 'trigger_device_rescan', autospec=True)
- @mock.patch.object(raid_utils, 'get_next_free_raid_device', autospec=True,
- return_value='/dev/md42')
- @mock.patch.object(disk_utils, 'find_efi_partition', autospec=True)
- def test_prepare_boot_partitions_for_softraid_uefi_gpt(
- self, mock_efi_part, mock_free_raid_device, mock_rescan,
- mock_execute, mock_dispatch):
- mock_efi_part.return_value = {'number': '12'}
- mock_execute.side_effect = [
- ('451', None), # sgdisk -F
- (None, None), # sgdisk create part
- (None, None), # partprobe
- (None, None), # blkid
- ('/dev/sda12: dsfkgsdjfg', None), # blkid
- ('452', None), # sgdisk -F
- (None, None), # sgdisk create part
- (None, None), # partprobe
- (None, None), # blkid
- ('/dev/sdb14: whatever', None), # blkid
- (None, None), # mdadm
- (None, None), # cp
- (None, None), # wipefs
- ]
-
- efi_part = image.prepare_boot_partitions_for_softraid(
- '/dev/md0', ['/dev/sda', '/dev/sdb'], None,
- target_boot_mode='uefi')
-
- mock_efi_part.assert_called_once_with('/dev/md0')
- expected = [
- mock.call('sgdisk', '-F', '/dev/sda'),
- mock.call('sgdisk', '-n', '0:451s:+550MiB', '-t', '0:ef00', '-c',
- '0:uefi-holder-0', '/dev/sda'),
- mock.call('partprobe'),
- mock.call('blkid'),
- mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-0',
- '/dev/sda'),
- mock.call('sgdisk', '-F', '/dev/sdb'),
- mock.call('sgdisk', '-n', '0:452s:+550MiB', '-t', '0:ef00', '-c',
- '0:uefi-holder-1', '/dev/sdb'),
- mock.call('partprobe'),
- mock.call('blkid'),
- mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-1',
- '/dev/sdb'),
- mock.call('mdadm', '--create', '/dev/md42', '--force', '--run',
- '--metadata=1.0', '--level', '1', '--name', 'esp',
- '--raid-devices', 2, '/dev/sda12', '/dev/sdb14'),
- mock.call('cp', '/dev/md0p12', '/dev/md42'),
- mock.call('wipefs', '-a', '/dev/md0p12')
- ]
- mock_execute.assert_has_calls(expected, any_order=False)
- self.assertEqual(efi_part, '/dev/md42')
- mock_rescan.assert_called_once_with('/dev/md42')
-
- @mock.patch.object(disk_utils, 'trigger_device_rescan', autospec=True)
- @mock.patch.object(raid_utils, 'get_next_free_raid_device', autospec=True,
- return_value='/dev/md42')
- @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(
- self, mock_mkfs, mock_efi_part, mock_free_raid_device,
- mock_rescan, mock_execute, mock_dispatch):
- mock_efi_part.return_value = None
- mock_execute.side_effect = [
- ('451', None), # sgdisk -F
- (None, None), # sgdisk create part
- (None, None), # partprobe
- (None, None), # blkid
- ('/dev/sda12: dsfkgsdjfg', None), # blkid
- ('452', None), # sgdisk -F
- (None, None), # sgdisk create part
- (None, None), # partprobe
- (None, None), # blkid
- ('/dev/sdb14: whatever', None), # blkid
- (None, None), # mdadm
- ]
-
- efi_part = image.prepare_boot_partitions_for_softraid(
- '/dev/md0', ['/dev/sda', '/dev/sdb'], None,
- target_boot_mode='uefi')
-
- mock_efi_part.assert_called_once_with('/dev/md0')
- expected = [
- mock.call('sgdisk', '-F', '/dev/sda'),
- mock.call('sgdisk', '-n', '0:451s:+550MiB', '-t', '0:ef00', '-c',
- '0:uefi-holder-0', '/dev/sda'),
- mock.call('partprobe'),
- mock.call('blkid'),
- mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-0',
- '/dev/sda'),
- mock.call('sgdisk', '-F', '/dev/sdb'),
- mock.call('sgdisk', '-n', '0:452s:+550MiB', '-t', '0:ef00', '-c',
- '0:uefi-holder-1', '/dev/sdb'),
- mock.call('partprobe'),
- mock.call('blkid'),
- mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-1',
- '/dev/sdb'),
- ]
- mock_execute.assert_has_calls(expected, any_order=False)
- mock_mkfs.assert_has_calls([
- mock.call(path='/dev/md42', label='efi-part', fs='vfat'),
- ], any_order=False)
- self.assertEqual(efi_part, '/dev/md42')
- mock_rescan.assert_called_once_with('/dev/md42')
-
- @mock.patch.object(disk_utils, 'trigger_device_rescan', autospec=True)
- @mock.patch.object(raid_utils, 'get_next_free_raid_device', autospec=True,
- return_value='/dev/md42')
- def test_prepare_boot_partitions_for_softraid_uefi_gpt_efi_provided(
- self, mock_free_raid_device, mock_rescan,
- mock_execute, mock_dispatch):
- mock_execute.side_effect = [
- ('451', None), # sgdisk -F
- (None, None), # sgdisk create part
- (None, None), # partprobe
- (None, None), # blkid
- ('/dev/sda12: dsfkgsdjfg', None), # blkid
- ('452', None), # sgdisk -F
- (None, None), # sgdisk create part
- (None, None), # partprobe
- (None, None), # blkid
- ('/dev/sdb14: whatever', None), # blkid
- (None, None), # mdadm create
- (None, None), # cp
- (None, None), # wipefs
- ]
-
- efi_part = image.prepare_boot_partitions_for_softraid(
- '/dev/md0', ['/dev/sda', '/dev/sdb'], '/dev/md0p15',
- target_boot_mode='uefi')
-
- expected = [
- mock.call('sgdisk', '-F', '/dev/sda'),
- mock.call('sgdisk', '-n', '0:451s:+550MiB', '-t', '0:ef00', '-c',
- '0:uefi-holder-0', '/dev/sda'),
- mock.call('partprobe'),
- mock.call('blkid'),
- mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-0',
- '/dev/sda'),
- mock.call('sgdisk', '-F', '/dev/sdb'),
- mock.call('sgdisk', '-n', '0:452s:+550MiB', '-t', '0:ef00', '-c',
- '0:uefi-holder-1', '/dev/sdb'),
- mock.call('partprobe'),
- mock.call('blkid'),
- mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-1',
- '/dev/sdb'),
- mock.call('mdadm', '--create', '/dev/md42', '--force', '--run',
- '--metadata=1.0', '--level', '1', '--name', 'esp',
- '--raid-devices', 2, '/dev/sda12', '/dev/sdb14'),
- mock.call('cp', '/dev/md0p15', '/dev/md42'),
- mock.call('wipefs', '-a', '/dev/md0p15')
- ]
- mock_execute.assert_has_calls(expected, any_order=False)
- self.assertEqual(efi_part, '/dev/md42')
-
- @mock.patch.object(disk_utils, 'get_partition_table_type', autospec=True,
- return_value='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(
- '/dev/md0', ['/dev/sda', '/dev/sdb'], 'notusedanyway',
- target_boot_mode='bios')
-
- expected = [
- mock.call('/dev/sda'),
- mock.call('/dev/sdb'),
- ]
- mock_label_scan.assert_has_calls(expected, any_order=False)
- self.assertIsNone(efi_part)
-
- @mock.patch.object(disk_utils, 'get_partition_table_type', autospec=True,
- return_value='gpt')
- def test_prepare_boot_partitions_for_softraid_bios_gpt(
- self, mock_label_scan, mock_execute, mock_dispatch):
-
- mock_execute.side_effect = [
- ('whatever\n314', None), # sgdisk -F
- (None, None), # bios boot grub
- ('warning message\n914', None), # sgdisk -F
- (None, None), # bios boot grub
- ]
-
- efi_part = image.prepare_boot_partitions_for_softraid(
- '/dev/md0', ['/dev/sda', '/dev/sdb'], 'notusedanyway',
- target_boot_mode='bios')
-
- expected_scan = [
- mock.call('/dev/sda'),
- mock.call('/dev/sdb'),
- ]
-
- mock_label_scan.assert_has_calls(expected_scan, any_order=False)
-
- expected_exec = [
- mock.call('sgdisk', '-F', '/dev/sda'),
- mock.call('sgdisk', '-n', '0:314s:+2MiB', '-t', '0:ef02', '-c',
- '0:bios-boot-part-0', '/dev/sda'),
- mock.call('sgdisk', '-F', '/dev/sdb'),
- mock.call('sgdisk', '-n', '0:914s:+2MiB', '-t', '0:ef02', '-c',
- '0:bios-boot-part-1', '/dev/sdb'),
- ]
-
- mock_execute.assert_has_calls(expected_exec, any_order=False)
- self.assertIsNone(efi_part)
-
@mock.patch.object(image, '_is_bootloader_loaded', lambda *_: True)
@mock.patch.object(hardware, 'is_md_device', autospec=True)
@mock.patch.object(hardware, 'md_restart', autospec=True)
@@ -1869,7 +1663,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(raid_utils, 'prepare_boot_partitions_for_softraid',
autospec=True,
return_value='/dev/md/esp')
@mock.patch.object(image, '_has_dracut',
@@ -1987,7 +1781,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(raid_utils, '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 775d0fce..137ec8d4 100644
--- a/ironic_python_agent/tests/unit/test_efi_utils.py
+++ b/ironic_python_agent/tests/unit/test_efi_utils.py
@@ -19,9 +19,9 @@ 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 import raid_utils
from ironic_python_agent.tests.unit import base
from ironic_python_agent import utils
@@ -321,7 +321,7 @@ Boot0002: VENDMAGIC FvFile(9f3c6294-bf9b-4208-9808-be45dfc34b51)
@mock.patch.object(os.path, 'exists', lambda *_: False)
@mock.patch.object(hardware, 'get_component_devices', autospec=True)
- @mock.patch.object(image,
+ @mock.patch.object(raid_utils,
'prepare_boot_partitions_for_softraid',
autospec=True)
@mock.patch.object(hardware, 'get_holder_disks', autospec=True)
diff --git a/ironic_python_agent/tests/unit/test_raid_utils.py b/ironic_python_agent/tests/unit/test_raid_utils.py
index a20bd13e..5b8577e2 100644
--- a/ironic_python_agent/tests/unit/test_raid_utils.py
+++ b/ironic_python_agent/tests/unit/test_raid_utils.py
@@ -12,6 +12,8 @@
from unittest import mock
+from ironic_lib import disk_utils
+from ironic_lib import utils as ilib_utils
from oslo_concurrency import processutils
from ironic_python_agent import errors
@@ -115,6 +117,222 @@ class TestRaidUtils(base.IronicAgentTest):
raid_utils.create_raid_device, 0,
logical_disk)
+ @mock.patch.object(disk_utils, 'trigger_device_rescan', autospec=True)
+ @mock.patch.object(raid_utils, 'get_next_free_raid_device', autospec=True,
+ return_value='/dev/md42')
+ @mock.patch.object(hardware, 'dispatch_to_managers', autospec=True)
+ @mock.patch.object(ilib_utils, 'execute', autospec=True)
+ @mock.patch.object(disk_utils, 'find_efi_partition', autospec=True)
+ def test_prepare_boot_partitions_for_softraid_uefi_gpt(
+ self, mock_efi_part, mock_execute, mock_dispatch,
+ mock_free_raid_device, mock_rescan):
+ mock_efi_part.return_value = {'number': '12'}
+ mock_execute.side_effect = [
+ ('451', None), # sgdisk -F
+ (None, None), # sgdisk create part
+ (None, None), # partprobe
+ (None, None), # blkid
+ ('/dev/sda12: dsfkgsdjfg', None), # blkid
+ ('452', None), # sgdisk -F
+ (None, None), # sgdisk create part
+ (None, None), # partprobe
+ (None, None), # blkid
+ ('/dev/sdb14: whatever', None), # blkid
+ (None, None), # mdadm
+ (None, None), # cp
+ (None, None), # wipefs
+ ]
+
+ efi_part = raid_utils.prepare_boot_partitions_for_softraid(
+ '/dev/md0', ['/dev/sda', '/dev/sdb'], None,
+ target_boot_mode='uefi')
+
+ mock_efi_part.assert_called_once_with('/dev/md0')
+ expected = [
+ mock.call('sgdisk', '-F', '/dev/sda'),
+ mock.call('sgdisk', '-n', '0:451s:+550MiB', '-t', '0:ef00', '-c',
+ '0:uefi-holder-0', '/dev/sda'),
+ mock.call('partprobe'),
+ mock.call('blkid'),
+ mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-0',
+ '/dev/sda'),
+ mock.call('sgdisk', '-F', '/dev/sdb'),
+ mock.call('sgdisk', '-n', '0:452s:+550MiB', '-t', '0:ef00', '-c',
+ '0:uefi-holder-1', '/dev/sdb'),
+ mock.call('partprobe'),
+ mock.call('blkid'),
+ mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-1',
+ '/dev/sdb'),
+ mock.call('mdadm', '--create', '/dev/md42', '--force', '--run',
+ '--metadata=1.0', '--level', '1', '--name', 'esp',
+ '--raid-devices', 2, '/dev/sda12', '/dev/sdb14'),
+ mock.call('cp', '/dev/md0p12', '/dev/md42'),
+ mock.call('wipefs', '-a', '/dev/md0p12')
+ ]
+ mock_execute.assert_has_calls(expected, any_order=False)
+ self.assertEqual(efi_part, '/dev/md42')
+ mock_rescan.assert_called_once_with('/dev/md42')
+
+ @mock.patch.object(disk_utils, 'trigger_device_rescan', autospec=True)
+ @mock.patch.object(raid_utils, 'get_next_free_raid_device', autospec=True,
+ return_value='/dev/md42')
+ @mock.patch.object(hardware, 'dispatch_to_managers', autospec=True)
+ @mock.patch.object(ilib_utils, 'execute', autospec=True)
+ @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(
+ self, mock_mkfs, mock_efi_part, mock_execute, mock_dispatch,
+ mock_free_raid_device, mock_rescan):
+ mock_efi_part.return_value = None
+ mock_execute.side_effect = [
+ ('451', None), # sgdisk -F
+ (None, None), # sgdisk create part
+ (None, None), # partprobe
+ (None, None), # blkid
+ ('/dev/sda12: dsfkgsdjfg', None), # blkid
+ ('452', None), # sgdisk -F
+ (None, None), # sgdisk create part
+ (None, None), # partprobe
+ (None, None), # blkid
+ ('/dev/sdb14: whatever', None), # blkid
+ (None, None), # mdadm
+ ]
+
+ efi_part = raid_utils.prepare_boot_partitions_for_softraid(
+ '/dev/md0', ['/dev/sda', '/dev/sdb'], None,
+ target_boot_mode='uefi')
+
+ mock_efi_part.assert_called_once_with('/dev/md0')
+ expected = [
+ mock.call('sgdisk', '-F', '/dev/sda'),
+ mock.call('sgdisk', '-n', '0:451s:+550MiB', '-t', '0:ef00', '-c',
+ '0:uefi-holder-0', '/dev/sda'),
+ mock.call('partprobe'),
+ mock.call('blkid'),
+ mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-0',
+ '/dev/sda'),
+ mock.call('sgdisk', '-F', '/dev/sdb'),
+ mock.call('sgdisk', '-n', '0:452s:+550MiB', '-t', '0:ef00', '-c',
+ '0:uefi-holder-1', '/dev/sdb'),
+ mock.call('partprobe'),
+ mock.call('blkid'),
+ mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-1',
+ '/dev/sdb'),
+ ]
+ mock_execute.assert_has_calls(expected, any_order=False)
+ mock_mkfs.assert_has_calls([
+ mock.call(path='/dev/md42', label='efi-part', fs='vfat'),
+ ], any_order=False)
+ self.assertEqual(efi_part, '/dev/md42')
+ mock_rescan.assert_called_once_with('/dev/md42')
+
+ @mock.patch.object(disk_utils, 'trigger_device_rescan', autospec=True)
+ @mock.patch.object(raid_utils, 'get_next_free_raid_device', autospec=True,
+ return_value='/dev/md42')
+ @mock.patch.object(hardware, 'dispatch_to_managers', autospec=True)
+ @mock.patch.object(ilib_utils, 'execute', autospec=True)
+ def test_prepare_boot_partitions_for_softraid_uefi_gpt_efi_provided(
+ self, mock_execute, mock_dispatch, mock_free_raid_device,
+ mock_rescan):
+ mock_execute.side_effect = [
+ ('451', None), # sgdisk -F
+ (None, None), # sgdisk create part
+ (None, None), # partprobe
+ (None, None), # blkid
+ ('/dev/sda12: dsfkgsdjfg', None), # blkid
+ ('452', None), # sgdisk -F
+ (None, None), # sgdisk create part
+ (None, None), # partprobe
+ (None, None), # blkid
+ ('/dev/sdb14: whatever', None), # blkid
+ (None, None), # mdadm create
+ (None, None), # cp
+ (None, None), # wipefs
+ ]
+
+ efi_part = raid_utils.prepare_boot_partitions_for_softraid(
+ '/dev/md0', ['/dev/sda', '/dev/sdb'], '/dev/md0p15',
+ target_boot_mode='uefi')
+
+ expected = [
+ mock.call('sgdisk', '-F', '/dev/sda'),
+ mock.call('sgdisk', '-n', '0:451s:+550MiB', '-t', '0:ef00', '-c',
+ '0:uefi-holder-0', '/dev/sda'),
+ mock.call('partprobe'),
+ mock.call('blkid'),
+ mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-0',
+ '/dev/sda'),
+ mock.call('sgdisk', '-F', '/dev/sdb'),
+ mock.call('sgdisk', '-n', '0:452s:+550MiB', '-t', '0:ef00', '-c',
+ '0:uefi-holder-1', '/dev/sdb'),
+ mock.call('partprobe'),
+ mock.call('blkid'),
+ mock.call('blkid', '-l', '-t', 'PARTLABEL=uefi-holder-1',
+ '/dev/sdb'),
+ mock.call('mdadm', '--create', '/dev/md42', '--force', '--run',
+ '--metadata=1.0', '--level', '1', '--name', 'esp',
+ '--raid-devices', 2, '/dev/sda12', '/dev/sdb14'),
+ mock.call('cp', '/dev/md0p15', '/dev/md42'),
+ mock.call('wipefs', '-a', '/dev/md0p15')
+ ]
+ mock_execute.assert_has_calls(expected, any_order=False)
+ self.assertEqual(efi_part, '/dev/md42')
+
+ @mock.patch.object(hardware, 'dispatch_to_managers', autospec=True)
+ @mock.patch.object(ilib_utils, 'execute', autospec=True)
+ @mock.patch.object(disk_utils, 'get_partition_table_type', autospec=True,
+ return_value='msdos')
+ def test_prepare_boot_partitions_for_softraid_bios_msdos(
+ self, mock_label_scan, mock_execute, mock_dispatch):
+
+ efi_part = raid_utils.prepare_boot_partitions_for_softraid(
+ '/dev/md0', ['/dev/sda', '/dev/sdb'], 'notusedanyway',
+ target_boot_mode='bios')
+
+ expected = [
+ mock.call('/dev/sda'),
+ mock.call('/dev/sdb'),
+ ]
+ mock_label_scan.assert_has_calls(expected, any_order=False)
+ self.assertIsNone(efi_part)
+
+ @mock.patch.object(hardware, 'dispatch_to_managers', autospec=True)
+ @mock.patch.object(ilib_utils, 'execute', autospec=True)
+ @mock.patch.object(disk_utils, 'get_partition_table_type', autospec=True,
+ return_value='gpt')
+ def test_prepare_boot_partitions_for_softraid_bios_gpt(
+ self, mock_label_scan, mock_execute, mock_dispatch):
+
+ mock_execute.side_effect = [
+ ('whatever\n314', None), # sgdisk -F
+ (None, None), # bios boot grub
+ ('warning message\n914', None), # sgdisk -F
+ (None, None), # bios boot grub
+ ]
+
+ efi_part = raid_utils.prepare_boot_partitions_for_softraid(
+ '/dev/md0', ['/dev/sda', '/dev/sdb'], 'notusedanyway',
+ target_boot_mode='bios')
+
+ expected_scan = [
+ mock.call('/dev/sda'),
+ mock.call('/dev/sdb'),
+ ]
+
+ mock_label_scan.assert_has_calls(expected_scan, any_order=False)
+
+ expected_exec = [
+ mock.call('sgdisk', '-F', '/dev/sda'),
+ mock.call('sgdisk', '-n', '0:314s:+2MiB', '-t', '0:ef02', '-c',
+ '0:bios-boot-part-0', '/dev/sda'),
+ mock.call('sgdisk', '-F', '/dev/sdb'),
+ mock.call('sgdisk', '-n', '0:914s:+2MiB', '-t', '0:ef02', '-c',
+ '0:bios-boot-part-1', '/dev/sdb'),
+ ]
+
+ mock_execute.assert_has_calls(expected_exec, any_order=False)
+ self.assertIsNone(efi_part)
+
@mock.patch.object(hardware, 'dispatch_to_managers', autospec=True)
class TestGetNextFreeRaidDevice(base.IronicAgentTest):