Skip to content

Commit 3aa5928

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Use a pre-defined partition UUID to detect configdrive on GPT" into stable/xena
2 parents 067cf9b + 1ec0f70 commit 3aa5928

File tree

3 files changed

+58
-39
lines changed

3 files changed

+58
-39
lines changed

ironic_python_agent/partition_utils.py

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@
3333
from oslo_log import log
3434
from oslo_utils import excutils
3535
from oslo_utils import units
36+
from oslo_utils import uuidutils
3637
import requests
3738

39+
from ironic_python_agent import errors
40+
from ironic_python_agent.extensions import image
3841
from ironic_python_agent import utils as ipa_utils
3942

4043

@@ -373,14 +376,18 @@ def create_config_drive_partition(node_uuid, device, configdrive):
373376
"%(part)s",
374377
{'node': node_uuid, 'part': config_drive_part})
375378
else:
376-
cur_parts = set(part['number']
377-
for part in disk_utils.list_partitions(device))
378-
379+
part_uuid = None
379380
if disk_utils.get_partition_table_type(device) == 'gpt':
381+
part_uuid = uuidutils.generate_uuid()
380382
create_option = '0:-%dMB:0' % MAX_CONFIG_DRIVE_SIZE_MB
381-
utils.execute('sgdisk', '-n', create_option, device,
383+
uuid_option = '0:%s' % part_uuid
384+
utils.execute('sgdisk', '-n', create_option,
385+
'-u', uuid_option, device,
382386
run_as_root=True)
383387
else:
388+
cur_parts = set(part['number']
389+
for part in disk_utils.list_partitions(device))
390+
384391
# Check if the disk has 4 partitions. The MBR based disk
385392
# cannot have more than 4 partitions.
386393
# TODO(stendulker): One can use logical partitions to create
@@ -422,17 +429,29 @@ def create_config_drive_partition(node_uuid, device, configdrive):
422429
# Trigger device rescan
423430
disk_utils.trigger_device_rescan(device)
424431

425-
upd_parts = set(part['number']
426-
for part in disk_utils.list_partitions(device))
427-
new_part = set(upd_parts) - set(cur_parts)
428-
if len(new_part) != 1:
429-
raise exception.InstanceDeployFailure(
430-
'Disk partitioning failed on device %(device)s. '
431-
'Unable to retrieve config drive partition information.'
432-
% {'device': device})
432+
if part_uuid is None:
433+
new_parts = {part['number']: part
434+
for part in disk_utils.list_partitions(device)}
435+
new_part = set(new_parts) - set(cur_parts)
436+
if len(new_part) != 1:
437+
raise exception.InstanceDeployFailure(
438+
'Disk partitioning failed on device %(device)s. '
439+
'Unable to retrieve config drive partition '
440+
'information.' % {'device': device})
433441

434-
config_drive_part = disk_utils.partition_index_to_path(
435-
device, new_part.pop())
442+
config_drive_part = disk_utils.partition_index_to_path(
443+
device, new_part.pop())
444+
else:
445+
try:
446+
config_drive_part = image._get_partition(device, part_uuid)
447+
except errors.DeviceNotFound:
448+
msg = ('Failed to create config drive on disk %(disk)s '
449+
'for node %(node)s. Partition with UUID %(uuid)s '
450+
'has not been found after creation.') % {
451+
'disk': device, 'node': node_uuid,
452+
'uuid': part_uuid}
453+
LOG.error(msg)
454+
raise exception.InstanceDeployFailure(msg)
436455

437456
disk_utils.udev_settle()
438457

ironic_python_agent/tests/unit/test_partition_utils.py

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from oslo_concurrency import processutils
2323
import requests
2424

25+
from ironic_python_agent.extensions import image
2526
from ironic_python_agent import partition_utils
2627
from ironic_python_agent.tests.unit import base
2728

@@ -654,6 +655,7 @@ def test_create_partition_exists(self, mock_get_configdrive,
654655
mock_dd.assert_called_with(configdrive_file, configdrive_part)
655656
mock_unlink.assert_called_with(configdrive_file)
656657

658+
@mock.patch('oslo_utils.uuidutils.generate_uuid', lambda: 'fake-uuid')
657659
@mock.patch.object(utils, 'execute', autospec=True)
658660
@mock.patch.object(utils, 'unlink_without_raise',
659661
autospec=True)
@@ -663,50 +665,32 @@ def test_create_partition_exists(self, mock_get_configdrive,
663665
autospec=True)
664666
@mock.patch.object(disk_utils, 'get_partition_table_type',
665667
autospec=True)
666-
@mock.patch.object(disk_utils, 'list_partitions',
667-
autospec=True)
668+
@mock.patch.object(image, '_get_partition', autospec=True)
668669
@mock.patch.object(partition_utils, 'get_labelled_partition',
669670
autospec=True)
670671
@mock.patch.object(partition_utils, 'get_configdrive',
671672
autospec=True)
672673
def test_create_partition_gpt(self, mock_get_configdrive,
673674
mock_get_labelled_partition,
674-
mock_list_partitions, mock_table_type,
675+
mock_get_partition_by_uuid,
676+
mock_table_type,
675677
mock_fix_gpt_partition,
676678
mock_dd, mock_unlink, mock_execute):
677679
config_url = 'http://1.2.3.4/cd'
678680
configdrive_file = '/tmp/xyz'
679681
configdrive_mb = 10
680682

681-
initial_partitions = [{'end': 49152, 'number': 1, 'start': 1,
682-
'flags': 'boot', 'filesystem': 'ext4',
683-
'size': 49151},
684-
{'end': 51099, 'number': 3, 'start': 49153,
685-
'flags': '', 'filesystem': '', 'size': 2046},
686-
{'end': 51099, 'number': 5, 'start': 49153,
687-
'flags': '', 'filesystem': '', 'size': 2046}]
688-
updated_partitions = [{'end': 49152, 'number': 1, 'start': 1,
689-
'flags': 'boot', 'filesystem': 'ext4',
690-
'size': 49151},
691-
{'end': 51099, 'number': 3, 'start': 49153,
692-
'flags': '', 'filesystem': '', 'size': 2046},
693-
{'end': 51099, 'number': 4, 'start': 49153,
694-
'flags': '', 'filesystem': '', 'size': 2046},
695-
{'end': 51099, 'number': 5, 'start': 49153,
696-
'flags': '', 'filesystem': '', 'size': 2046}]
697-
698683
mock_get_configdrive.return_value = (configdrive_mb, configdrive_file)
699684
mock_get_labelled_partition.return_value = None
700685

701686
mock_table_type.return_value = 'gpt'
702-
mock_list_partitions.side_effect = [initial_partitions,
703-
updated_partitions]
704687
expected_part = '/dev/fake4'
688+
mock_get_partition_by_uuid.return_value = expected_part
705689
partition_utils.create_config_drive_partition(self.node_uuid, self.dev,
706690
config_url)
707691
mock_execute.assert_has_calls([
708-
mock.call('sgdisk', '-n', '0:-64MB:0', self.dev,
709-
run_as_root=True),
692+
mock.call('sgdisk', '-n', '0:-64MB:0', '-u', '0:fake-uuid',
693+
self.dev, run_as_root=True),
710694
mock.call('sync'),
711695
mock.call('udevadm', 'settle'),
712696
mock.call('partprobe', self.dev, attempts=10, run_as_root=True),
@@ -717,7 +701,6 @@ def test_create_partition_gpt(self, mock_get_configdrive,
717701
delay_on_retry=True)
718702
])
719703

720-
self.assertEqual(2, mock_list_partitions.call_count)
721704
mock_table_type.assert_called_with(self.dev)
722705
mock_fix_gpt_partition.assert_called_with(self.dev, self.node_uuid)
723706
mock_dd.assert_called_with(configdrive_file, expected_part)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
issues:
3+
- |
4+
Creating a configdrive partition on a devicemapper device (e.g. a multipath
5+
storage device) with MBR partitioning may fail with the following error::
6+
7+
Command execution failed: Failed to create config drive on disk /dev/dm-0
8+
for node 168af30d-0fad-4d67-af99-b28b3238e977. Error: Unexpected error
9+
while running command.
10+
11+
Use GPT partitioning instead.
12+
fixes:
13+
- |
14+
Fixes creating a configdrive partition on a devicemapper device (e.g.
15+
a multipath storage device) with GPT partitioning. The newly created
16+
partition is now detected by a pre-generated UUID rather than by comparing
17+
partition numbers.

0 commit comments

Comments
 (0)