summaryrefslogtreecommitdiff
path: root/ironic_python_agent/tests/unit
diff options
context:
space:
mode:
authorDmitry Tantsur <dtantsur@protonmail.com>2021-10-27 13:45:10 +0200
committerDmitry Tantsur <dtantsur@protonmail.com>2021-11-16 17:58:16 +0100
commit36d4a18fbc7afd873035930a558e971ad4cec12f (patch)
treec762ca4f0b6c69bf97fdb990e7df1015376dbe79 /ironic_python_agent/tests/unit
parentf5efbc3e7ef846fc5bebd368a886e4ed312213fc (diff)
downloadironic-python-agent-36d4a18fbc7afd873035930a558e971ad4cec12f.tar.gz
Move manage_uefi from the image extension to a public location
This call is very useful for custom deploy implementations, such as one we maintain for OpenShift. Splitting it out also makes image.py slightly more manageable. The get_partition call is moved to partition_utils. Change-Id: I60a6a2823d3eb27a4ae78e913e3655dae7b54ffe
Diffstat (limited to 'ironic_python_agent/tests/unit')
-rw-r--r--ironic_python_agent/tests/unit/extensions/test_image.py489
-rw-r--r--ironic_python_agent/tests/unit/test_efi_utils.py304
-rw-r--r--ironic_python_agent/tests/unit/test_partition_utils.py121
3 files changed, 459 insertions, 455 deletions
diff --git a/ironic_python_agent/tests/unit/extensions/test_image.py b/ironic_python_agent/tests/unit/extensions/test_image.py
index 6e5c2a4e..2564ea12 100644
--- a/ironic_python_agent/tests/unit/extensions/test_image.py
+++ b/ironic_python_agent/tests/unit/extensions/test_image.py
@@ -21,15 +21,17 @@ from unittest import mock
from ironic_lib import utils as ilib_utils
from oslo_concurrency import processutils
+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
@mock.patch.object(hardware, 'dispatch_to_managers', autospec=True)
-@mock.patch.object(utils, 'execute', autospec=True)
+@mock.patch.object(ilib_utils, 'execute', autospec=True)
@mock.patch.object(tempfile, 'mkdtemp', lambda *_: '/tmp/fake-dir')
@mock.patch.object(shutil, 'rmtree', lambda *_: None)
class TestImageExtension(base.IronicAgentTest):
@@ -63,7 +65,7 @@ class TestImageExtension(base.IronicAgentTest):
target_boot_mode='bios'
)
- @mock.patch.object(image, '_manage_uefi', autospec=True)
+ @mock.patch.object(efi_utils, 'manage_uefi', autospec=True)
@mock.patch.object(image, '_install_grub2', autospec=True)
def test__install_bootloader_uefi(self, mock_grub2, mock_uefi,
mock_execute, mock_dispatch):
@@ -87,7 +89,7 @@ class TestImageExtension(base.IronicAgentTest):
target_boot_mode='uefi'
)
- @mock.patch.object(image, '_manage_uefi', autospec=True)
+ @mock.patch.object(efi_utils, 'manage_uefi', autospec=True)
@mock.patch.object(image, '_install_grub2', autospec=True)
def test__install_bootloader_uefi_ignores_manage_failure(
self, mock_grub2, mock_uefi,
@@ -114,7 +116,7 @@ class TestImageExtension(base.IronicAgentTest):
target_boot_mode='uefi'
)
- @mock.patch.object(image, '_manage_uefi', autospec=True)
+ @mock.patch.object(efi_utils, 'manage_uefi', autospec=True)
@mock.patch.object(image, '_install_grub2', autospec=True)
def test__install_bootloader_uefi_ignores_grub_failure(
self, mock_grub2, mock_uefi,
@@ -141,7 +143,7 @@ class TestImageExtension(base.IronicAgentTest):
target_boot_mode='uefi'
)
- @mock.patch.object(image, '_manage_uefi', autospec=True)
+ @mock.patch.object(efi_utils, 'manage_uefi', autospec=True)
@mock.patch.object(image, '_install_grub2', autospec=True)
def test__install_bootloader_uefi_ignores_grub_failure_api_override(
self, mock_grub2, mock_uefi,
@@ -168,7 +170,7 @@ class TestImageExtension(base.IronicAgentTest):
target_boot_mode='uefi'
)
- @mock.patch.object(image, '_manage_uefi', autospec=True)
+ @mock.patch.object(efi_utils, 'manage_uefi', autospec=True)
@mock.patch.object(image, '_install_grub2', autospec=True)
def test__install_bootloader_uefi_grub_failure_api_override(
self, mock_grub2, mock_uefi,
@@ -211,8 +213,8 @@ class TestImageExtension(base.IronicAgentTest):
@mock.patch.object(hardware, 'is_md_device', lambda *_: False)
@mock.patch.object(os.path, 'exists', lambda *_: False)
- @mock.patch.object(image, '_get_efi_bootloaders', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(efi_utils, '_get_efi_bootloaders', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
@mock.patch.object(utils, 'get_efi_part_on_device', autospec=False)
@mock.patch.object(os, 'makedirs', autospec=True)
def test__uefi_bootloader_given_partition(
@@ -259,8 +261,8 @@ class TestImageExtension(base.IronicAgentTest):
@mock.patch.object(hardware, 'is_md_device', lambda *_: False)
@mock.patch.object(os.path, 'exists', lambda *_: False)
- @mock.patch.object(image, '_get_efi_bootloaders', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(efi_utils, '_get_efi_bootloaders', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
@mock.patch.object(utils, 'get_efi_part_on_device', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
def test__uefi_bootloader_find_partition(
@@ -306,8 +308,8 @@ class TestImageExtension(base.IronicAgentTest):
@mock.patch.object(hardware, 'is_md_device', lambda *_: False)
@mock.patch.object(os.path, 'exists', lambda *_: False)
- @mock.patch.object(image, '_get_efi_bootloaders', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(efi_utils, '_get_efi_bootloaders', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
@mock.patch.object(utils, 'get_efi_part_on_device', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
def test__uefi_bootloader_with_entry_removal(
@@ -363,8 +365,8 @@ Boot0002 VENDMAGIC FvFile(9f3c6294-bf9b-4208-9808-be45dfc34b51)
@mock.patch.object(hardware, 'is_md_device', lambda *_: False)
@mock.patch.object(os.path, 'exists', lambda *_: False)
- @mock.patch.object(image, '_get_efi_bootloaders', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(efi_utils, '_get_efi_bootloaders', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
@mock.patch.object(utils, 'get_efi_part_on_device', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
def test__uefi_bootloader_with_entry_removal_lenovo(
@@ -425,8 +427,8 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'is_md_device', lambda *_: False)
@mock.patch.object(os.path, 'exists', lambda *_: False)
- @mock.patch.object(image, '_get_efi_bootloaders', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(efi_utils, '_get_efi_bootloaders', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
@mock.patch.object(utils, 'get_efi_part_on_device', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
def test__add_multi_bootloaders(
@@ -518,7 +520,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'is_md_device', autospec=True)
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2(self, mock_get_part_uuid, environ_mock,
mock_md_get_raid_devices, mock_is_md_device,
mock_append_to_fstab, mock_execute,
@@ -580,7 +582,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'is_md_device', autospec=True)
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_prep(self, mock_get_part_uuid, environ_mock,
mock_md_get_raid_devices, mock_is_md_device,
mock_execute, mock_dispatch):
@@ -649,7 +651,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_uefi(self, mock_get_part_uuid, mkdir_mock,
environ_mock, mock_md_get_raid_devices,
mock_is_md_device, mock_append_to_fstab,
@@ -737,7 +739,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_uefi_fstab(self, mock_get_part_uuid, mkdir_mock,
environ_mock, mock_md_get_raid_devices,
mock_is_md_device, mock_exists,
@@ -834,7 +836,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_uefi_no_fstab(
self, mock_get_part_uuid,
mkdir_mock,
@@ -948,7 +950,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_uefi_partition_image_with_loader(
self, mock_get_part_uuid, mkdir_mock,
environ_mock, mock_md_get_raid_devices,
@@ -1032,7 +1034,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_uefi_partition_image_with_loader_with_grubcfg(
self, mock_get_part_uuid, mkdir_mock,
environ_mock, mock_md_get_raid_devices,
@@ -1115,7 +1117,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_uefi_partition_image_with_preserve_failure(
self, mock_get_part_uuid, mkdir_mock,
environ_mock, mock_md_get_raid_devices,
@@ -1229,7 +1231,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_uefi_partition_image_with_preserve_failure2(
self, mock_get_part_uuid, mkdir_mock,
environ_mock, mock_md_get_raid_devices,
@@ -1351,7 +1353,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_uefi_partition_image_with_loader_grubcfg_fails(
self, mock_get_part_uuid, mkdir_mock,
environ_mock, mock_md_get_raid_devices,
@@ -1440,7 +1442,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_uefi_partition_image_with_no_loader(
self, mock_get_part_uuid, mkdir_mock,
environ_mock, mock_md_get_raid_devices,
@@ -1538,7 +1540,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_uefi_umount_fails(
self, mock_get_part_uuid, mkdir_mock, environ_mock,
mock_md_get_raid_devices, mock_is_md_device, mock_execute,
@@ -1598,7 +1600,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_uefi_mount_fails(
self, mock_get_part_uuid, mkdir_mock, environ_mock,
mock_is_md_device, mock_md_get_raid_devices, mock_execute,
@@ -1637,7 +1639,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
mock_execute.assert_has_calls(expected)
@mock.patch.object(image, '_is_bootloader_loaded', lambda *_: False)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
def test__install_grub2_command_fail(self, mock_get_part_uuid,
mock_execute,
mock_dispatch):
@@ -1851,7 +1853,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
return_value=['/dev/sda', '/dev/sdb'])
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
@mock.patch.object(image, '_prepare_boot_partitions_for_softraid',
autospec=True,
return_value='/dev/md/esp')
@@ -1969,7 +1971,7 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
return_value=['/dev/sda', '/dev/sdb'])
@mock.patch.object(os, 'environ', autospec=True)
@mock.patch.object(os, 'makedirs', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
+ @mock.patch.object(partition_utils, 'get_partition', autospec=True)
@mock.patch.object(image, '_prepare_boot_partitions_for_softraid',
autospec=True,
return_value=[])
@@ -2053,133 +2055,6 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
mock_holder.assert_called_once_with(self.fake_dev)
mock_dracut.assert_called_once_with(self.fake_dir)
- @mock.patch.object(image, '_is_bootloader_loaded', autospec=True)
- @mock.patch.object(hardware, 'is_md_device', autospec=True)
- def test__get_partition(self, mock_is_md_device, mock_is_bootloader,
- mock_execute, mock_dispatch):
- mock_is_md_device.side_effect = [False]
- mock_is_md_device.side_effect = [False, False]
- lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
- KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
- KNAME="test2" UUID="%s" TYPE="part"''' % self.fake_root_uuid)
- mock_execute.side_effect = (None, None, [lsblk_output])
-
- root_part = image._get_partition(self.fake_dev, self.fake_root_uuid)
- self.assertEqual('/dev/test2', root_part)
- expected = [mock.call('partx', '-a', self.fake_dev, attempts=3,
- delay_on_retry=True),
- mock.call('udevadm', 'settle'),
- mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
- self.fake_dev)]
- mock_execute.assert_has_calls(expected)
- self.assertFalse(mock_dispatch.called)
- self.assertFalse(mock_is_bootloader.called)
-
- @mock.patch.object(hardware, 'is_md_device', autospec=True)
- def test__get_partition_no_device_found(self, mock_is_md_device,
- mock_execute, mock_dispatch):
- mock_is_md_device.side_effect = [False, False]
- lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
- KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
- KNAME="test2" UUID="" TYPE="part"''')
- mock_execute.side_effect = (
- None, None, [lsblk_output],
- processutils.ProcessExecutionError('boom'),
- processutils.ProcessExecutionError('kaboom'))
-
- self.assertRaises(errors.DeviceNotFound,
- image._get_partition, self.fake_dev,
- self.fake_root_uuid)
- expected = [mock.call('partx', '-a', self.fake_dev, attempts=3,
- delay_on_retry=True),
- mock.call('udevadm', 'settle'),
- mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
- self.fake_dev)]
- mock_execute.assert_has_calls(expected)
- self.assertFalse(mock_dispatch.called)
-
- @mock.patch.object(hardware, 'is_md_device', autospec=True)
- def test__get_partition_fallback_partuuid(self, mock_is_md_device,
- mock_execute, mock_dispatch):
- mock_is_md_device.side_effect = [False]
- lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
- KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
- KNAME="test2" UUID="" TYPE="part"''')
- findfs_output = ('/dev/loop0\n', None)
- mock_execute.side_effect = (
- None, None, [lsblk_output],
- processutils.ProcessExecutionError('boom'),
- findfs_output)
-
- result = image._get_partition(self.fake_dev, self.fake_root_uuid)
- self.assertEqual('/dev/loop0', result)
- expected = [mock.call('partx', '-a', self.fake_dev, attempts=3,
- delay_on_retry=True),
- mock.call('udevadm', 'settle'),
- mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
- self.fake_dev),
- mock.call('findfs', 'UUID=%s' % self.fake_root_uuid),
- mock.call('findfs', 'PARTUUID=%s' % self.fake_root_uuid)]
- mock_execute.assert_has_calls(expected)
- self.assertFalse(mock_dispatch.called)
-
- @mock.patch.object(hardware, 'is_md_device', autospec=True)
- def test__get_partition_command_fail(self, mock_is_md_device,
- mock_execute, mock_dispatch):
- mock_is_md_device.side_effect = [False, False]
- mock_execute.side_effect = (None, None,
- processutils.ProcessExecutionError('boom'))
- self.assertRaises(errors.CommandExecutionError,
- image._get_partition, self.fake_dev,
- self.fake_root_uuid)
-
- expected = [mock.call('partx', '-a', self.fake_dev, attempts=3,
- delay_on_retry=True),
- mock.call('udevadm', 'settle'),
- mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
- self.fake_dev)]
- mock_execute.assert_has_calls(expected)
- self.assertFalse(mock_dispatch.called)
-
- @mock.patch.object(hardware, 'is_md_device', autospec=True)
- def test__get_partition_partuuid(self, mock_is_md_device, mock_execute,
- mock_dispatch):
- mock_is_md_device.side_effect = [False, False]
- lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
- KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
- KNAME="test2" UUID="903e7bf9-8a13-4f7f-811b-25dc16faf6f7" TYPE="part" \
- LABEL="%s"''' % self.fake_root_uuid)
- mock_execute.side_effect = (None, None, [lsblk_output])
-
- root_part = image._get_partition(self.fake_dev, self.fake_root_uuid)
- self.assertEqual('/dev/test2', root_part)
- expected = [mock.call('partx', '-a', self.fake_dev, attempts=3,
- delay_on_retry=True),
- mock.call('udevadm', 'settle'),
- mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
- self.fake_dev)]
- mock_execute.assert_has_calls(expected)
- self.assertFalse(mock_dispatch.called)
-
- @mock.patch.object(hardware, 'is_md_device', autospec=True)
- def test__get_partition_label(self, mock_is_md_device, mock_execute,
- mock_dispatch):
- mock_is_md_device.side_effect = [False, False]
- lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
- KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
- KNAME="test2" PARTUUID="%s" TYPE="part"''' % self.fake_root_uuid)
- mock_execute.side_effect = (None, None, [lsblk_output])
-
- root_part = image._get_partition(self.fake_dev, self.fake_root_uuid)
- self.assertEqual('/dev/test2', root_part)
- expected = [mock.call('partx', '-a', self.fake_dev, attempts=3,
- delay_on_retry=True),
- mock.call('udevadm', 'settle'),
- mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
- self.fake_dev)]
- mock_execute.assert_has_calls(expected)
- self.assertFalse(mock_dispatch.called)
-
def test__is_bootloader_loaded(self, mock_execute,
mock_dispatch):
mock_dispatch.return_value = hardware.BootInfo(
@@ -2248,302 +2123,6 @@ Boot0004* ironic1 HD(1,GPT,55db8d03-c8f6-4a5b-9155-790dddc348fa,0x800,0x640
mock_dispatch.assert_any_call('get_boot_info')
self.assertEqual(0, mock_execute.call_count)
- @mock.patch.object(image, '_get_partition', autospec=True)
- @mock.patch.object(utils, 'get_efi_part_on_device', autospec=True)
- def test__manage_uefi_no_partition(self, mock_utils_efi_part,
- mock_get_part_uuid,
- mock_execute, mock_dispatch):
- mock_utils_efi_part.return_value = None
- self.assertRaises(errors.DeviceNotFound,
- image._manage_uefi, self.fake_dev, None)
- self.assertFalse(mock_get_part_uuid.called)
-
- @mock.patch.object(image, '_get_partition', autospec=True)
- @mock.patch.object(utils, 'get_efi_part_on_device', autospec=True)
- def test__manage_uefi_empty_partition_by_uuid(self, mock_utils_efi_part,
- mock_get_part_uuid,
- mock_execute, mock_dispatch):
- mock_utils_efi_part.return_value = None
- mock_get_part_uuid.return_value = self.fake_root_part
- result = image._manage_uefi(self.fake_dev, self.fake_root_uuid)
- self.assertFalse(result)
-
- @mock.patch.object(os.path, 'exists', lambda *_: False)
- @mock.patch.object(image, '_get_efi_bootloaders', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
- @mock.patch.object(utils, 'get_efi_part_on_device', autospec=True)
- @mock.patch.object(os, 'makedirs', autospec=True)
- def test__manage_uefi(self, mkdir_mock, mock_utils_efi_part,
- mock_get_part_uuid, mock_efi_bl, mock_execute,
- mock_dispatch):
- mock_utils_efi_part.return_value = '1'
- mock_get_part_uuid.return_value = self.fake_dev
-
- mock_efi_bl.return_value = ['EFI/BOOT/BOOTX64.EFI']
-
- mock_execute.side_effect = iter([('', ''), ('', ''),
- ('', ''), ('', ''),
- ('', ''), ('', ''),
- ('', '')])
-
- expected = [mock.call('partx', '-a', '/dev/fake', attempts=3,
- delay_on_retry=True),
- mock.call('udevadm', 'settle'),
- mock.call('mount', self.fake_efi_system_part,
- self.fake_dir + '/boot/efi'),
- mock.call('efibootmgr', '-v'),
- mock.call('efibootmgr', '-v', '-c', '-d', self.fake_dev,
- '-p', '1', '-w',
- '-L', 'ironic1', '-l',
- '\\EFI\\BOOT\\BOOTX64.EFI'),
- mock.call('umount', self.fake_dir + '/boot/efi',
- attempts=3, delay_on_retry=True),
- mock.call('sync')]
-
- result = image._manage_uefi(self.fake_dev, self.fake_root_uuid)
- 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)
- self.assertEqual(7, mock_execute.call_count)
-
- @mock.patch.object(os.path, 'exists', lambda *_: False)
- @mock.patch.object(image, '_get_efi_bootloaders', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
- @mock.patch.object(utils, 'get_efi_part_on_device', autospec=True)
- @mock.patch.object(os, 'makedirs', autospec=True)
- def test__manage_uefi_found_csv(self, mkdir_mock, mock_utils_efi_part,
- mock_get_part_uuid, mock_efi_bl,
- mock_execute, mock_dispatch):
- mock_utils_efi_part.return_value = '1'
- mock_get_part_uuid.return_value = self.fake_dev
- mock_efi_bl.return_value = ['EFI/vendor/BOOTX64.CSV']
-
- # Format is <file>,<entry_name>,<options>,humanfriendlytextnotused
- # https://www.rodsbooks.com/efi-bootloaders/fallback.html
- # Mild difference, Ubuntu ships a file without a 0xFEFF delimiter
- # at the start of the file, where as Red Hat *does*
- csv_file_data = u'shimx64.efi,Vendor String,,Grub2MadeUSDoThis\n'
- # This test also handles deleting a pre-existing matching vendor
- # string in advance.
- dupe_entry = """
-BootCurrent: 0001
-Timeout: 0 seconds
-BootOrder: 0000,00001
-Boot0000* Vendor String HD(1,GPT,4f3c6294-bf9b-4208-9808-be45dfc34b5c)File(\EFI\Boot\BOOTX64.EFI)
-Boot0001 Vendor String HD(2,GPT,4f3c6294-bf9b-4208-9808-be45dfc34b5c)File(\EFI\Boot\BOOTX64.EFI)
-Boot0002: VENDMAGIC FvFile(9f3c6294-bf9b-4208-9808-be45dfc34b51)
-""" # noqa This is a giant literal string for testing.
-
- mock_execute.side_effect = iter([('', ''), ('', ''),
- ('', ''), (dupe_entry, ''),
- ('', ''), ('', ''),
- ('', ''), ('', ''),
- ('', '')])
-
- expected = [mock.call('partx', '-a', '/dev/fake', attempts=3,
- delay_on_retry=True),
- mock.call('udevadm', 'settle'),
- mock.call('mount', self.fake_efi_system_part,
- self.fake_dir + '/boot/efi'),
- mock.call('efibootmgr', '-v'),
- mock.call('efibootmgr', '-b', '0000', '-B'),
- mock.call('efibootmgr', '-b', '0001', '-B'),
- mock.call('efibootmgr', '-v', '-c', '-d', self.fake_dev,
- '-p', '1', '-w',
- '-L', 'Vendor String', '-l',
- '\\EFI\\vendor\\shimx64.efi'),
- mock.call('umount', self.fake_dir + '/boot/efi',
- attempts=3, delay_on_retry=True),
- mock.call('sync')]
- with mock.patch('builtins.open',
- mock.mock_open(read_data=csv_file_data)):
- result = image._manage_uefi(self.fake_dev, self.fake_root_uuid)
- 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)
- self.assertEqual(9, mock_execute.call_count)
-
- @mock.patch.object(os.path, 'exists', lambda *_: False)
- @mock.patch.object(image, '_get_efi_bootloaders', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
- @mock.patch.object(utils, 'get_efi_part_on_device', autospec=True)
- @mock.patch.object(os, 'makedirs', autospec=True)
- def test__manage_uefi_nvme_device(self, mkdir_mock, mock_utils_efi_part,
- mock_get_part_uuid, mock_efi_bl,
- mock_execute, mock_dispatch):
- mock_utils_efi_part.return_value = '1'
- mock_get_part_uuid.return_value = '/dev/fakenvme0p1'
-
- mock_efi_bl.return_value = ['EFI/BOOT/BOOTX64.EFI']
-
- mock_execute.side_effect = iter([('', ''), ('', ''),
- ('', ''), ('', ''),
- ('', ''), ('', ''),
- ('', '')])
-
- expected = [mock.call('partx', '-a', '/dev/fakenvme0', attempts=3,
- delay_on_retry=True),
- mock.call('udevadm', 'settle'),
- mock.call('mount', '/dev/fakenvme0p1',
- self.fake_dir + '/boot/efi'),
- mock.call('efibootmgr', '-v'),
- mock.call('efibootmgr', '-v', '-c', '-d', '/dev/fakenvme0',
- '-p', '1', '-w',
- '-L', 'ironic1', '-l',
- '\\EFI\\BOOT\\BOOTX64.EFI'),
- mock.call('umount', self.fake_dir + '/boot/efi',
- attempts=3, delay_on_retry=True),
- mock.call('sync')]
-
- result = image._manage_uefi('/dev/fakenvme0', self.fake_root_uuid)
- 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)
- self.assertEqual(7, mock_execute.call_count)
-
- @mock.patch.object(os.path, 'exists', lambda *_: False)
- @mock.patch.object(image, '_get_efi_bootloaders', autospec=True)
- @mock.patch.object(image, '_get_partition', autospec=True)
- @mock.patch.object(utils, 'get_efi_part_on_device', autospec=True)
- @mock.patch.object(os, 'makedirs', autospec=True)
- def test__manage_uefi_wholedisk(
- self, mkdir_mock, mock_utils_efi_part,
- mock_get_part_uuid, mock_efi_bl, mock_execute,
- mock_dispatch):
- mock_utils_efi_part.return_value = '1'
- mock_get_part_uuid.side_effect = Exception
-
- mock_efi_bl.return_value = ['EFI/BOOT/BOOTX64.EFI']
-
- mock_execute.side_effect = iter([('', ''), ('', ''),
- ('', ''), ('', ''),
- ('', ''), ('', ''),
- ('', '')])
-
- expected = [mock.call('partx', '-a', '/dev/fake', attempts=3,
- delay_on_retry=True),
- mock.call('udevadm', 'settle'),
- mock.call('mount', self.fake_efi_system_part,
- self.fake_dir + '/boot/efi'),
- mock.call('efibootmgr', '-v'),
- mock.call('efibootmgr', '-v', '-c', '-d', self.fake_dev,
- '-p', '1', '-w',
- '-L', 'ironic1', '-l',
- '\\EFI\\BOOT\\BOOTX64.EFI'),
- mock.call('umount', self.fake_dir + '/boot/efi',
- attempts=3, delay_on_retry=True),
- mock.call('sync')]
-
- result = image._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)
- self.assertEqual(7, mock_execute.call_count)
-
- @mock.patch.object(os, 'walk', autospec=True)
- @mock.patch.object(os, 'access', autospec=False)
- def test__no_efi_bootloaders(self, mock_access, mock_walk, mock_execute,
- mock_dispatch):
- # No valid efi file.
- mock_walk.return_value = [
- ('/boot/efi', ['EFI'], []),
- ('/boot/efi/EFI', ['centos', 'BOOT'], []),
- ('/boot/efi/EFI/centos', ['fw', 'fonts'],
- ['shimx64-centos.efi',
- 'MokManager.efi', 'mmx64.efi', 'shim.efi', 'fwupia32.efi',
- 'fwupx64.efi', 'shimx64.efi', 'grubenv', 'grubx64.efi',
- 'grub.cfg']),
- ('/boot/efi/EFI/centos/fw', [], []),
- ('/boot/efi/EFI/centos/fonts', [], ['unicode.pf2']),
- ('/boot/efi/EFI/BOOT', [], [])
- ]
-
- result = image._get_efi_bootloaders("/boot/efi")
- self.assertEqual(result, [])
- mock_access.assert_not_called()
-
- @mock.patch.object(os, 'walk', autospec=True)
- @mock.patch.object(os, 'access', autospec=True)
- def test__get_efi_bootloaders(self, mock_access, mock_walk, mock_execute,
- mock_dispatch):
- mock_walk.return_value = [
- ('/boot/efi', ['EFI'], []),
- ('/boot/efi/EFI', ['centos', 'BOOT'], []),
- ('/boot/efi/EFI/centos', ['fw', 'fonts'],
- ['shimx64-centos.efi', 'BOOTX64.CSV',
- 'MokManager.efi', 'mmx64.efi', 'shim.efi', 'fwupia32.efi',
- 'fwupx64.efi', 'shimx64.efi', 'grubenv', 'grubx64.efi',
- 'grub.cfg']),
- ('/boot/efi/EFI/centos/fw', [], []),
- ('/boot/efi/EFI/centos/fonts', [], ['unicode.pf2']),
- ('/boot/efi/EFI/BOOT', [],
- ['BOOTX64.EFI', 'fallback.efi', 'fbx64.efi'])
- ]
- mock_access.return_value = True
- result = image._get_efi_bootloaders("/boot/efi")
- self.assertEqual(result[0], 'EFI/centos/BOOTX64.CSV')
-
- @mock.patch.object(os, 'walk', autospec=True)
- @mock.patch.object(os, 'access', autospec=True)
- def test__get_efi_bootloaders_no_csv(
- self, mock_access, mock_walk, mock_execute, mock_dispatch):
- mock_walk.return_value = [
- ('/boot/efi', ['EFI'], []),
- ('/boot/efi/EFI', ['centos', 'BOOT'], []),
- ('/boot/efi/EFI/centos', ['fw', 'fonts'],
- ['shimx64-centos.efi',
- 'MokManager.efi', 'mmx64.efi', 'shim.efi', 'fwupia32.efi',
- 'fwupx64.efi', 'shimx64.efi', 'grubenv', 'grubx64.efi',
- 'grub.cfg']),
- ('/boot/efi/EFI/centos/fw', [], []),
- ('/boot/efi/EFI/centos/fonts', [], ['unicode.pf2']),
- ('/boot/efi/EFI/BOOT', [],
- ['BOOTX64.EFI', 'fallback.efi', 'fbx64.efi'])
- ]
- mock_access.return_value = True
- result = image._get_efi_bootloaders("/boot/efi")
- self.assertEqual(result[0], 'EFI/BOOT/BOOTX64.EFI')
-
- @mock.patch.object(os, 'walk', autospec=True)
- @mock.patch.object(os, 'access', autospec=True)
- def test__get_windows_efi_bootloaders(self, mock_access, mock_walk,
- mock_execute, mock_dispatch):
- mock_walk.return_value = [
- ('/boot/efi', ['WINDOWS'], []),
- ('/boot/efi/WINDOWS', ['system32'], []),
- ('/boot/efi/WINDOWS/system32', [],
- ['winload.efi'])
- ]
- mock_access.return_value = True
- result = image._get_efi_bootloaders("/boot/efi")
- self.assertEqual(result[0], 'WINDOWS/system32/winload.efi')
-
- def test__run_efibootmgr_no_bootloaders(self, mock_execute, mock_dispatch):
- result = image._run_efibootmgr([], self.fake_dev,
- self.fake_efi_system_part,
- self.fake_dir)
- expected = []
- self.assertIsNone(result)
- mock_execute.assert_has_calls(expected)
-
- def test__run_efibootmgr(self, mock_execute, mock_dispatch):
- mock_execute.return_value = ('', '')
- result = image._run_efibootmgr(['EFI/BOOT/BOOTX64.EFI'],
- self.fake_dev,
- self.fake_efi_system_part,
- self.fake_dir)
- expected = [mock.call('efibootmgr', '-v'),
- mock.call('efibootmgr', '-v', '-c', '-d', self.fake_dev,
- '-p', self.fake_efi_system_part, '-w',
- '-L', 'ironic1', '-l',
- '\\EFI\\BOOT\\BOOTX64.EFI')]
- self.assertIsNone(result)
- mock_execute.assert_has_calls(expected)
-
@mock.patch.object(os.path, 'exists', lambda *_: True)
def test__append_uefi_to_fstab_handles_error(self, mock_execute,
mock_dispatch):
diff --git a/ironic_python_agent/tests/unit/test_efi_utils.py b/ironic_python_agent/tests/unit/test_efi_utils.py
new file mode 100644
index 00000000..f41a3af0
--- /dev/null
+++ b/ironic_python_agent/tests/unit/test_efi_utils.py
@@ -0,0 +1,304 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import os
+import shutil
+import tempfile
+from unittest import mock
+
+from ironic_python_agent import efi_utils
+from ironic_python_agent import errors
+from ironic_python_agent import partition_utils
+from ironic_python_agent.tests.unit import base
+from ironic_python_agent import utils
+
+
+@mock.patch.object(os, 'walk', autospec=True)
+@mock.patch.object(os, 'access', autospec=False)
+class TestGetEfiBootloaders(base.IronicAgentTest):
+
+ def test__no_efi_bootloaders(self, mock_access, mock_walk):
+ # No valid efi file.
+ mock_walk.return_value = [
+ ('/boot/efi', ['EFI'], []),
+ ('/boot/efi/EFI', ['centos', 'BOOT'], []),
+ ('/boot/efi/EFI/centos', ['fw', 'fonts'],
+ ['shimx64-centos.efi',
+ 'MokManager.efi', 'mmx64.efi', 'shim.efi', 'fwupia32.efi',
+ 'fwupx64.efi', 'shimx64.efi', 'grubenv', 'grubx64.efi',
+ 'grub.cfg']),
+ ('/boot/efi/EFI/centos/fw', [], []),
+ ('/boot/efi/EFI/centos/fonts', [], ['unicode.pf2']),
+ ('/boot/efi/EFI/BOOT', [], [])
+ ]
+
+ result = efi_utils._get_efi_bootloaders("/boot/efi")
+ self.assertEqual(result, [])
+ mock_access.assert_not_called()
+
+ def test__get_efi_bootloaders(self, mock_access, mock_walk):
+ mock_walk.return_value = [
+ ('/boot/efi', ['EFI'], []),
+ ('/boot/efi/EFI', ['centos', 'BOOT'], []),
+ ('/boot/efi/EFI/centos', ['fw', 'fonts'],
+ ['shimx64-centos.efi', 'BOOTX64.CSV',
+ 'MokManager.efi', 'mmx64.efi', 'shim.efi', 'fwupia32.efi',
+ 'fwupx64.efi', 'shimx64.efi', 'grubenv', 'grubx64.efi',
+ 'grub.cfg']),
+ ('/boot/efi/EFI/centos/fw', [], []),
+ ('/boot/efi/EFI/centos/fonts', [], ['unicode.pf2']),
+ ('/boot/efi/EFI/BOOT', [],
+ ['BOOTX64.EFI', 'fallback.efi', 'fbx64.efi'])
+ ]
+ mock_access.return_value = True
+ result = efi_utils._get_efi_bootloaders("/boot/efi")
+ self.assertEqual(result[0], 'EFI/centos/BOOTX64.CSV')
+
+ def test__get_efi_bootloaders_no_csv(self, mock_access, mock_walk):
+ mock_walk.return_value = [
+ ('/boot/efi', ['EFI'], []),
+ ('/boot/efi/EFI', ['centos', 'BOOT'], []),
+ ('/boot/efi/EFI/centos', ['fw', 'fonts'],
+ ['shimx64-centos.efi',
+ 'MokManager.efi', 'mmx64.efi', 'shim.efi', 'fwupia32.efi',
+ 'fwupx64.efi', 'shimx64.efi', 'grubenv', 'grubx64.efi',
+ 'grub.cfg']),
+ ('/boot/efi/EFI/centos/fw', [], []),
+ ('/boot/efi/EFI/centos/fonts', [], ['unicode.pf2']),
+ ('/boot/efi/EFI/BOOT', [],
+ ['BOOTX64.EFI', 'fallback.efi', 'fbx64.efi'])
+ ]
+ mock_access.return_value = True
+ result = efi_utils._get_efi_bootloaders("/boot/efi")
+ self.assertEqual(result[0], 'EFI/BOOT/BOOTX64.EFI')
+
+ def test__get_windows_efi_bootloaders(self, mock_access, mock_walk):
+ mock_walk.return_value = [
+ ('/boot/efi', ['WINDOWS'], []),
+ ('/boot/efi/WINDOWS', ['system32'], []),
+ ('/boot/efi/WINDOWS/system32', [],
+ ['winload.efi'])
+ ]
+ mock_access.return_value = True
+ result = efi_utils._get_efi_bootloaders("/boot/efi")
+ self.assertEqual(result[0], 'WINDOWS/system32/winload.efi')
+
+
+@mock.patch.object(utils, 'execute', autospec=True)
+class TestRunEfiBootmgr(base.IronicAgentTest):
+
+ fake_dev = '/dev/fake'
+ fake_efi_system_part = '/dev/fake1'
+ fake_dir = '/tmp/fake-dir'
+
+ def test__run_efibootmgr_no_bootloaders(self, mock_execute):
+ result = efi_utils._run_efibootmgr([], self.fake_dev,
+ self.fake_efi_system_part,
+ self.fake_dir)
+ expected = []
+ self.assertIsNone(result)
+ mock_execute.assert_has_calls(expected)
+
+ def test__run_efibootmgr(self, mock_execute):
+ mock_execute.return_value = ('', '')
+ result = efi_utils._run_efibootmgr(['EFI/BOOT/BOOTX64.EFI'],
+ self.fake_dev,
+ self.fake_efi_system_part,
+ self.fake_dir)
+ expected = [mock.call('efibootmgr', '-v'),
+ mock.call('efibootmgr', '-v', '-c', '-d', self.fake_dev,
+ '-p', self.fake_efi_system_part, '-w',
+ '-L', 'ironic1', '-l',
+ '\\EFI\\BOOT\\BOOTX64.EFI')]
+ self.assertIsNone(result)
+ mock_execute.assert_has_calls(expected)
+
+
+@mock.patch.object(shutil, 'rmtree', lambda *_: None)
+@mock.patch.object(tempfile, 'mkdtemp', lambda *_: '/tmp/fake-dir')
+@mock.patch.object(utils, 'rescan_device', autospec=True)
+@mock.patch.object(utils, 'execute', autospec=True)
+@mock.patch.object(partition_utils, 'get_partition', autospec=True)
+@mock.patch.object(utils, 'get_efi_part_on_device', autospec=True)
+class TestManageUefi(base.IronicAgentTest):
+
+ fake_dev = '/dev/fake'
+ fake_efi_system_part = '/dev/fake1'
+ fake_root_part = '/dev/fake2'
+ fake_root_uuid = '11111111-2222-3333-4444-555555555555'
+ fake_dir = '/tmp/fake-dir'
+
+ def test_no_partition(self, mock_utils_efi_part,
+ mock_get_part_uuid, mock_execute,
+ mock_rescan):
+ mock_utils_efi_part.return_value = None
+ self.assertRaises(errors.DeviceNotFound,
+ efi_utils.manage_uefi, self.fake_dev, None)
+ self.assertFalse(mock_get_part_uuid.called)
+ mock_rescan.assert_called_once_with(self.fake_dev)
+
+ def test_empty_partition_by_uuid(self, mock_utils_efi_part,
+ mock_get_part_uuid, mock_execute,
+ mock_rescan):
+ mock_utils_efi_part.return_value = None
+ mock_get_part_uuid.return_value = self.fake_root_part
+ result = efi_utils.manage_uefi(self.fake_dev, self.fake_root_uuid)
+ self.assertFalse(result)
+ mock_rescan.assert_called_once_with(self.fake_dev)
+
+ @mock.patch.object(os.path, 'exists', lambda *_: False)
+ @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):
+ mock_utils_efi_part.return_value = '1'
+ mock_get_part_uuid.return_value = self.fake_dev
+
+ 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('efibootmgr', '-v'),
+ mock.call('efibootmgr', '-v', '-c', '-d', self.fake_dev,
+ '-p', '1', '-w',
+ '-L', 'ironic1', '-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, self.fake_root_uuid)
+ 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)
+ self.assertEqual(5, mock_execute.call_count)
+ mock_rescan.assert_called_once_with(self.fake_dev)
+
+ @mock.patch.object(os.path, 'exists', lambda *_: False)
+ @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):
+ mock_utils_efi_part.return_value = '1'
+ mock_get_part_uuid.return_value = self.fake_dev
+ mock_efi_bl.return_value = ['EFI/vendor/BOOTX64.CSV']
+
+ # Format is <file>,<entry_name>,<options>,humanfriendlytextnotused
+ # https://www.rodsbooks.com/efi-bootloaders/fallback.html
+ # Mild difference, Ubuntu ships a file without a 0xFEFF delimiter
+ # at the start of the file, where as Red Hat *does*
+ csv_file_data = u'shimx64.efi,Vendor String,,Grub2MadeUSDoThis\n'
+ # This test also handles deleting a pre-existing matching vendor
+ # string in advance.
+ dupe_entry = """
+BootCurrent: 0001
+Timeout: 0 seconds
+BootOrder: 0000,00001
+Boot0000* Vendor String HD(1,GPT,4f3c6294-bf9b-4208-9808-be45dfc34b5c)File(\EFI\Boot\BOOTX64.EFI)
+Boot0001 Vendor String HD(2,GPT,4f3c6294-bf9b-4208-9808-be45dfc34b5c)File(\EFI\Boot\BOOTX64.EFI)
+Boot0002: VENDMAGIC FvFile(9f3c6294-bf9b-4208-9808-be45dfc34b51)
+""" # noqa This is a giant literal string for testing.
+
+ mock_execute.side_effect = iter([('', ''), (dupe_entry, ''),
+ ('', ''), ('', ''),
+ ('', ''), ('', ''),
+ ('', '')])
+
+ expected = [mock.call('mount', self.fake_efi_system_part,
+ self.fake_dir + '/boot/efi'),
+ mock.call('efibootmgr', '-v'),
+ mock.call('efibootmgr', '-b', '0000', '-B'),
+ mock.call('efibootmgr', '-b', '0001', '-B'),
+ mock.call('efibootmgr', '-v', '-c', '-d', self.fake_dev,
+ '-p', '1', '-w',
+ '-L', 'Vendor String', '-l',
+ '\\EFI\\vendor\\shimx64.efi'),
+ mock.call('umount', self.fake_dir + '/boot/efi',
+ attempts=3, delay_on_retry=True),
+ mock.call('sync')]
+ with mock.patch('builtins.open',
+ mock.mock_open(read_data=csv_file_data)):
+ result = efi_utils.manage_uefi(self.fake_dev, self.fake_root_uuid)
+ 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)
+
+ @mock.patch.object(os.path, 'exists', lambda *_: False)
+ @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):
+ mock_utils_efi_part.return_value = '1'
+ mock_get_part_uuid.return_value = '/dev/fakenvme0p1'
+
+ mock_efi_bl.return_value = ['EFI/BOOT/BOOTX64.EFI']
+
+ mock_execute.side_effect = iter([('', ''), ('', ''),
+ ('', ''), ('', ''),
+ ('', ''), ('', ''),
+ ('', '')])
+
+ expected = [mock.call('mount', '/dev/fakenvme0p1',
+ self.fake_dir + '/boot/efi'),
+ mock.call('efibootmgr', '-v'),
+ mock.call('efibootmgr', '-v', '-c', '-d', '/dev/fakenvme0',
+ '-p', '1', '-w',
+ '-L', 'ironic1', '-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('/dev/fakenvme0', self.fake_root_uuid)
+ 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)
+
+ @mock.patch.object(os.path, 'exists', lambda *_: False)
+ @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):
+ mock_utils_efi_part.return_value = '1'
+ mock_get_part_uuid.side_effect = Exception
+
+ 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('efibootmgr', '-v'),
+ mock.call('efibootmgr', '-v', '-c', '-d', self.fake_dev,
+ '-p', '1', '-w',
+ '-L', 'ironic1', '-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_partition_utils.py b/ironic_python_agent/tests/unit/test_partition_utils.py
index 64316dc0..1bae6d15 100644
--- a/ironic_python_agent/tests/unit/test_partition_utils.py
+++ b/ironic_python_agent/tests/unit/test_partition_utils.py
@@ -22,6 +22,8 @@ from ironic_lib import utils
from oslo_concurrency import processutils
import requests
+from ironic_python_agent import errors
+from ironic_python_agent import hardware
from ironic_python_agent import partition_utils
from ironic_python_agent.tests.unit import base
@@ -1173,3 +1175,122 @@ class RealFilePartitioningTestCase(base.IronicAgentTest):
self.assertEqual([6, 3], sizes[:2],
"unexpected partitioning %s" % part_table)
self.assertIn(sizes[2], (9, 10))
+
+
+@mock.patch.object(utils, 'execute', autospec=True)
+@mock.patch.object(hardware, 'is_md_device', autospec=True)
+class TestGetPartition(base.IronicAgentTest):
+
+ fake_dev = '/dev/fake'
+ fake_root_uuid = '11111111-2222-3333-4444-555555555555'
+
+ def test(self, mock_is_md_device, mock_execute):
+ mock_is_md_device.side_effect = [False]
+ mock_is_md_device.side_effect = [False, False]
+ lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
+ KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
+ KNAME="test2" UUID="%s" TYPE="part"''' % self.fake_root_uuid)
+ mock_execute.side_effect = (None, None, [lsblk_output])
+
+ root_part = partition_utils.get_partition(
+ self.fake_dev, self.fake_root_uuid)
+ self.assertEqual('/dev/test2', root_part)
+ expected = [mock.call('partx', '-a', self.fake_dev, attempts=3,
+ delay_on_retry=True),
+ mock.call('udevadm', 'settle'),
+ mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
+ self.fake_dev)]
+ mock_execute.assert_has_calls(expected)
+
+ def test_no_device_found(self, mock_is_md_device, mock_execute):
+ mock_is_md_device.side_effect = [False, False]
+ lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
+ KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
+ KNAME="test2" UUID="" TYPE="part"''')
+ mock_execute.side_effect = (
+ None, None, [lsblk_output],
+ processutils.ProcessExecutionError('boom'),
+ processutils.ProcessExecutionError('kaboom'))
+
+ self.assertRaises(errors.DeviceNotFound,
+ partition_utils.get_partition, self.fake_dev,
+ self.fake_root_uuid)
+ expected = [mock.call('partx', '-a', self.fake_dev, attempts=3,
+ delay_on_retry=True),
+ mock.call('udevadm', 'settle'),
+ mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
+ self.fake_dev)]
+ mock_execute.assert_has_calls(expected)
+
+ def test_fallback_partuuid(self, mock_is_md_device, mock_execute):
+ mock_is_md_device.side_effect = [False]
+ lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
+ KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
+ KNAME="test2" UUID="" TYPE="part"''')
+ findfs_output = ('/dev/loop0\n', None)
+ mock_execute.side_effect = (
+ None, None, [lsblk_output],
+ processutils.ProcessExecutionError('boom'),
+ findfs_output)
+
+ result = partition_utils.get_partition(
+ self.fake_dev, self.fake_root_uuid)
+ self.assertEqual('/dev/loop0', result)
+ expected = [mock.call('partx', '-a', self.fake_dev, attempts=3,
+ delay_on_retry=True),
+ mock.call('udevadm', 'settle'),
+ mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
+ self.fake_dev),
+ mock.call('findfs', 'UUID=%s' % self.fake_root_uuid),
+ mock.call('findfs', 'PARTUUID=%s' % self.fake_root_uuid)]
+ mock_execute.assert_has_calls(expected)
+
+ def test_command_fail(self, mock_is_md_device, mock_execute):
+ mock_is_md_device.side_effect = [False, False]
+ mock_execute.side_effect = (None, None,
+ processutils.ProcessExecutionError('boom'))
+ self.assertRaises(errors.CommandExecutionError,
+ partition_utils.get_partition, self.fake_dev,
+ self.fake_root_uuid)
+
+ expected = [mock.call('partx', '-a', self.fake_dev, attempts=3,
+ delay_on_retry=True),
+ mock.call('udevadm', 'settle'),
+ mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
+ self.fake_dev)]
+ mock_execute.assert_has_calls(expected)
+
+ def test_partuuid(self, mock_is_md_device, mock_execute):
+ mock_is_md_device.side_effect = [False, False]
+ lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
+ KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
+ KNAME="test2" UUID="903e7bf9-8a13-4f7f-811b-25dc16faf6f7" TYPE="part" \
+ LABEL="%s"''' % self.fake_root_uuid)
+ mock_execute.side_effect = (None, None, [lsblk_output])
+
+ root_part = partition_utils.get_partition(
+ self.fake_dev, self.fake_root_uuid)
+ self.assertEqual('/dev/test2', root_part)
+ expected = [mock.call('partx', '-a', self.fake_dev, attempts=3,
+ delay_on_retry=True),
+ mock.call('udevadm', 'settle'),
+ mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
+ self.fake_dev)]
+ mock_execute.assert_has_calls(expected)
+
+ def test_label(self, mock_is_md_device, mock_execute):
+ mock_is_md_device.side_effect = [False, False]
+ lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
+ KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
+ KNAME="test2" PARTUUID="%s" TYPE="part"''' % self.fake_root_uuid)
+ mock_execute.side_effect = (None, None, [lsblk_output])
+
+ root_part = partition_utils.get_partition(
+ self.fake_dev, self.fake_root_uuid)
+ self.assertEqual('/dev/test2', root_part)
+ expected = [mock.call('partx', '-a', self.fake_dev, attempts=3,
+ delay_on_retry=True),
+ mock.call('udevadm', 'settle'),
+ mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
+ self.fake_dev)]
+ mock_execute.assert_has_calls(expected)