From c2786caa1ba9ba5aa9cae2133299554b0a1368a7 Mon Sep 17 00:00:00 2001 From: Dmitry Tantsur Date: Wed, 10 Feb 2021 18:51:34 +0100 Subject: [PATCH] Add find_efi_partition, deprecate get_uefi_disk_identifier The get_uefi_disk_identifier function is currently unused in both ironic and IPA. Furthermore, its name is confusing: it returns the UEFI partition UUID, not the disk identifier, unlike the similarly named get_disk_identifier. This change imports get_efi_part_on_device from IPA as find_efi_partition. The only difference is that it returns a complete partition record rather than only the number. Change-Id: I424d04adb6ccbb3daa99daa5c860cbb81332c02e --- ironic_lib/disk_utils.py | 29 ++++++++++++--- ironic_lib/tests/test_disk_utils.py | 55 +++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/ironic_lib/disk_utils.py b/ironic_lib/disk_utils.py index e2e607fa..a60ea140 100644 --- a/ironic_lib/disk_utils.py +++ b/ironic_lib/disk_utils.py @@ -24,6 +24,7 @@ import shutil import stat import tempfile import time +import warnings from oslo_concurrency import processutils from oslo_config import cfg @@ -212,19 +213,37 @@ def get_device_information(device, probe=False, fields=None): return {} +def find_efi_partition(device): + """Looks for the EFI partition on a given device. + + A boot partition on a GPT disk is assumed to be an EFI partition as well. + + :param device: the name of the device + :return: the EFI partition record from `list_partitions` or None + """ + is_gpt = get_partition_table_type(device) == 'gpt' + for part in list_partitions(device): + flags = {x.strip() for x in part['flags'].split(',')} + if 'esp' in flags or ('boot' in flags and is_gpt): + LOG.debug("Found EFI partition %s on device %s", part, device) + return part + else: + LOG.debug("No efi partition found on device %s", device) + + def get_uefi_disk_identifier(dev): """Get the uuid from the disk being exposed by the ramdisk. - This uuid is appended to the pxe config which will then be set as the root - and load the bootx64.efi file using chainloader and boot the machine. - This is helpful in deployments to nodes with multiple disks. - - https://wiki.gentoo.org/wiki/GRUB2/Chainloading + DEPRECATED: use find_efi_partition with get_device_information instead. :param dev: Path for the already populated disk device. :raises InstanceDeployFailure: Image is not UEFI bootable. :returns: The UUID of the partition. """ + warnings.warn("get_uefi_disk_identifier is deprecated, use " + "find_efi_partition and get_partition_information instead", + DeprecationWarning) + partition_id = None try: report, _ = utils.execute('fdisk', '-l', dev, run_as_root=True) diff --git a/ironic_lib/tests/test_disk_utils.py b/ironic_lib/tests/test_disk_utils.py index b343e25d..060d4c24 100644 --- a/ironic_lib/tests/test_disk_utils.py +++ b/ironic_lib/tests/test_disk_utils.py @@ -2047,3 +2047,58 @@ class GetPartitionTableTypeTestCase(base.IronicLibTestCase): mock_get_device_info.return_value = {} self.assertIsNone(disk_utils.get_partition_table_type('/dev/fake')) mock_get_device_info.assert_called_once_with('/dev/fake', probe=True) + + +PARTED_OUTPUT_UNFORMATTED = '''Model: whatever +Disk /dev/sda: 450GB +Sector size (logical/physical): 512B/512B +Partition Table: {} +Disk Flags: + +Number Start End Size File system Name Flags +14 1049kB 5243kB 4194kB bios_grub +15 5243kB 116MB 111MB fat32 boot, esp + 1 116MB 2361MB 2245MB ext4 +''' + + +@mock.patch.object(disk_utils, 'list_partitions', autospec=True) +@mock.patch.object(disk_utils, 'get_partition_table_type', autospec=True) +class FindEfiPartitionTestCase(base.IronicLibTestCase): + + def test_find_efi_partition(self, mocked_type, mocked_parts): + mocked_parts.return_value = [ + {'number': '1', 'flags': ''}, + {'number': '14', 'flags': 'bios_grub'}, + {'number': '15', 'flags': 'esp, boot'}, + ] + ret = disk_utils.find_efi_partition('/dev/sda') + self.assertEqual({'number': '15', 'flags': 'esp, boot'}, ret) + + def test_find_efi_partition_only_boot_flag_gpt(self, mocked_type, + mocked_parts): + mocked_type.return_value = 'gpt' + mocked_parts.return_value = [ + {'number': '1', 'flags': ''}, + {'number': '14', 'flags': 'bios_grub'}, + {'number': '15', 'flags': 'boot'}, + ] + ret = disk_utils.find_efi_partition('/dev/sda') + self.assertEqual({'number': '15', 'flags': 'boot'}, ret) + + def test_find_efi_partition_only_boot_flag_mbr(self, mocked_type, + mocked_parts): + mocked_type.return_value = 'msdos' + mocked_parts.return_value = [ + {'number': '1', 'flags': ''}, + {'number': '14', 'flags': 'bios_grub'}, + {'number': '15', 'flags': 'boot'}, + ] + self.assertIsNone(disk_utils.find_efi_partition('/dev/sda')) + + def test_find_efi_partition_not_found(self, mocked_type, mocked_parts): + mocked_parts.return_value = [ + {'number': '1', 'flags': ''}, + {'number': '14', 'flags': 'bios_grub'}, + ] + self.assertIsNone(disk_utils.find_efi_partition('/dev/sda'))