summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2022-05-18 19:38:18 +0000
committerGerrit Code Review <review@openstack.org>2022-05-18 19:38:18 +0000
commitdfd1b00769102d97541e92c2c28b68144c88a986 (patch)
treea3543e552212a92bbb5ae9024cbafe58d7354522
parent4856a9ab3d447e3780451d5534cce4a4e5188cef (diff)
parentd60de5baa78db1e50a51d02fd796168ed541212c (diff)
downloadironic-python-agent-dfd1b00769102d97541e92c2c28b68144c88a986.tar.gz
Merge "Use a pre-defined partition UUID to detect configdrive on GPT" into bugfix/8.3
-rw-r--r--ironic_python_agent/partition_utils.py45
-rw-r--r--ironic_python_agent/tests/unit/test_partition_utils.py31
-rw-r--r--releasenotes/notes/configdrive-partuuid-3259cfb7428c1483.yaml17
3 files changed, 55 insertions, 38 deletions
diff --git a/ironic_python_agent/partition_utils.py b/ironic_python_agent/partition_utils.py
index 18b4cfdb..1060e77d 100644
--- a/ironic_python_agent/partition_utils.py
+++ b/ironic_python_agent/partition_utils.py
@@ -35,6 +35,7 @@ from oslo_config import cfg
from oslo_log import log
from oslo_utils import excutils
from oslo_utils import units
+from oslo_utils import uuidutils
import requests
from ironic_python_agent import errors
@@ -374,14 +375,18 @@ def create_config_drive_partition(node_uuid, device, configdrive):
"%(part)s",
{'node': node_uuid, 'part': config_drive_part})
else:
- cur_parts = set(part['number']
- for part in disk_utils.list_partitions(device))
-
+ part_uuid = None
if disk_utils.get_partition_table_type(device) == 'gpt':
+ part_uuid = uuidutils.generate_uuid()
create_option = '0:-%dMB:0' % MAX_CONFIG_DRIVE_SIZE_MB
- utils.execute('sgdisk', '-n', create_option, device,
+ uuid_option = '0:%s' % part_uuid
+ utils.execute('sgdisk', '-n', create_option,
+ '-u', uuid_option, device,
run_as_root=True)
else:
+ cur_parts = set(part['number']
+ for part in disk_utils.list_partitions(device))
+
# Check if the disk has 4 partitions. The MBR based disk
# cannot have more than 4 partitions.
# TODO(stendulker): One can use logical partitions to create
@@ -423,17 +428,29 @@ def create_config_drive_partition(node_uuid, device, configdrive):
# Trigger device rescan
disk_utils.trigger_device_rescan(device)
- upd_parts = set(part['number']
- for part in disk_utils.list_partitions(device))
- new_part = set(upd_parts) - set(cur_parts)
- if len(new_part) != 1:
- raise exception.InstanceDeployFailure(
- 'Disk partitioning failed on device %(device)s. '
- 'Unable to retrieve config drive partition information.'
- % {'device': device})
+ if part_uuid is None:
+ new_parts = {part['number']: part
+ for part in disk_utils.list_partitions(device)}
+ new_part = set(new_parts) - set(cur_parts)
+ if len(new_part) != 1:
+ raise exception.InstanceDeployFailure(
+ 'Disk partitioning failed on device %(device)s. '
+ 'Unable to retrieve config drive partition '
+ 'information.' % {'device': device})
- config_drive_part = disk_utils.partition_index_to_path(
- device, new_part.pop())
+ config_drive_part = disk_utils.partition_index_to_path(
+ device, new_part.pop())
+ else:
+ try:
+ config_drive_part = get_partition(device, part_uuid)
+ except errors.DeviceNotFound:
+ msg = ('Failed to create config drive on disk %(disk)s '
+ 'for node %(node)s. Partition with UUID %(uuid)s '
+ 'has not been found after creation.') % {
+ 'disk': device, 'node': node_uuid,
+ 'uuid': part_uuid}
+ LOG.error(msg)
+ raise exception.InstanceDeployFailure(msg)
disk_utils.udev_settle()
diff --git a/ironic_python_agent/tests/unit/test_partition_utils.py b/ironic_python_agent/tests/unit/test_partition_utils.py
index f6f56695..9fa67b53 100644
--- a/ironic_python_agent/tests/unit/test_partition_utils.py
+++ b/ironic_python_agent/tests/unit/test_partition_utils.py
@@ -647,6 +647,7 @@ class CreateConfigDriveTestCases(base.IronicAgentTest):
mock_dd.assert_called_with(configdrive_file, configdrive_part)
mock_unlink.assert_called_with(configdrive_file)
+ @mock.patch('oslo_utils.uuidutils.generate_uuid', lambda: 'fake-uuid')
@mock.patch.object(utils, 'execute', autospec=True)
@mock.patch.object(utils, 'unlink_without_raise',
autospec=True)
@@ -656,7 +657,7 @@ class CreateConfigDriveTestCases(base.IronicAgentTest):
autospec=True)
@mock.patch.object(disk_utils, 'get_partition_table_type',
autospec=True)
- @mock.patch.object(disk_utils, 'list_partitions',
+ @mock.patch.object(partition_utils, 'get_partition',
autospec=True)
@mock.patch.object(partition_utils, 'get_labelled_partition',
autospec=True)
@@ -664,42 +665,25 @@ class CreateConfigDriveTestCases(base.IronicAgentTest):
autospec=True)
def test_create_partition_gpt(self, mock_get_configdrive,
mock_get_labelled_partition,
- mock_list_partitions, mock_table_type,
+ mock_get_partition_by_uuid,
+ mock_table_type,
mock_fix_gpt_partition,
mock_dd, mock_unlink, mock_execute):
config_url = 'http://1.2.3.4/cd'
configdrive_file = '/tmp/xyz'
configdrive_mb = 10
- initial_partitions = [{'end': 49152, 'number': 1, 'start': 1,
- 'flags': 'boot', 'filesystem': 'ext4',
- 'size': 49151},
- {'end': 51099, 'number': 3, 'start': 49153,
- 'flags': '', 'filesystem': '', 'size': 2046},
- {'end': 51099, 'number': 5, 'start': 49153,
- 'flags': '', 'filesystem': '', 'size': 2046}]
- updated_partitions = [{'end': 49152, 'number': 1, 'start': 1,
- 'flags': 'boot', 'filesystem': 'ext4',
- 'size': 49151},
- {'end': 51099, 'number': 3, 'start': 49153,
- 'flags': '', 'filesystem': '', 'size': 2046},
- {'end': 51099, 'number': 4, 'start': 49153,
- 'flags': '', 'filesystem': '', 'size': 2046},
- {'end': 51099, 'number': 5, 'start': 49153,
- 'flags': '', 'filesystem': '', 'size': 2046}]
-
mock_get_configdrive.return_value = (configdrive_mb, configdrive_file)
mock_get_labelled_partition.return_value = None
mock_table_type.return_value = 'gpt'
- mock_list_partitions.side_effect = [initial_partitions,
- updated_partitions]
expected_part = '/dev/fake4'
+ mock_get_partition_by_uuid.return_value = expected_part
partition_utils.create_config_drive_partition(self.node_uuid, self.dev,
config_url)
mock_execute.assert_has_calls([
- mock.call('sgdisk', '-n', '0:-64MB:0', self.dev,
- run_as_root=True),
+ mock.call('sgdisk', '-n', '0:-64MB:0', '-u', '0:fake-uuid',
+ self.dev, run_as_root=True),
mock.call('sync'),
mock.call('udevadm', 'settle'),
mock.call('partprobe', self.dev, attempts=10, run_as_root=True),
@@ -710,7 +694,6 @@ class CreateConfigDriveTestCases(base.IronicAgentTest):
delay_on_retry=True)
])
- self.assertEqual(2, mock_list_partitions.call_count)
mock_table_type.assert_called_with(self.dev)
mock_fix_gpt_partition.assert_called_with(self.dev, self.node_uuid)
mock_dd.assert_called_with(configdrive_file, expected_part)
diff --git a/releasenotes/notes/configdrive-partuuid-3259cfb7428c1483.yaml b/releasenotes/notes/configdrive-partuuid-3259cfb7428c1483.yaml
new file mode 100644
index 00000000..95344273
--- /dev/null
+++ b/releasenotes/notes/configdrive-partuuid-3259cfb7428c1483.yaml
@@ -0,0 +1,17 @@
+---
+issues:
+ - |
+ Creating a configdrive partition on a devicemapper device (e.g. a multipath
+ storage device) with MBR partitioning may fail with the following error::
+
+ Command execution failed: Failed to create config drive on disk /dev/dm-0
+ for node 168af30d-0fad-4d67-af99-b28b3238e977. Error: Unexpected error
+ while running command.
+
+ Use GPT partitioning instead.
+fixes:
+ - |
+ Fixes creating a configdrive partition on a devicemapper device (e.g.
+ a multipath storage device) with GPT partitioning. The newly created
+ partition is now detected by a pre-generated UUID rather than by comparing
+ partition numbers.