Add support for discoverable partitions

Set PARTUUID according to systemd-id128 if applicable
This Fixes #1385
This commit is contained in:
Marcus Schäfer 2024-02-24 10:57:32 +01:00
parent 6dc4ef2570
commit 2540d56602
No known key found for this signature in database
GPG Key ID: A16C1128698C8CAC
9 changed files with 223 additions and 7 deletions

View File

@ -98,6 +98,17 @@ class PartitionerBase:
"""
raise NotImplementedError
def set_uuid(self, partition_id: int, uuid: str):
"""
Set partition UUID
Implementation in specialized partitioner class
:param int partition_id: unused
:param string uuid: unused
"""
raise NotImplementedError
def set_hybrid_mbr(self):
"""
Turn partition table into hybrid table if supported

View File

@ -83,6 +83,17 @@ class PartitionerDasd(PartitionerBase):
# that point.
log.debug('potential fdasd errors were ignored')
def set_uuid(self, partition_id: int, uuid: str) -> None:
"""
Set partition UUID
Nothing to be done here for DASD devices
:param int partition_id: unused
:param string uuid: unused
"""
pass # pragma: nocover
def resize_table(self, entries: int = None) -> None:
"""
Resize partition table

View File

@ -114,6 +114,21 @@ class PartitionerGpt(PartitionerBase):
else:
log.warning('Flag %s ignored on GPT', flag_name)
def set_uuid(self, partition_id: int, uuid: str) -> None:
"""
Set partition UUID (GUID)
:param int partition_id: partition number
:param string uuid: UUID
"""
Command.run(
[
'sgdisk',
'--partition-guid', f'{partition_id}:{uuid}',
self.disk_device
]
)
def set_hybrid_mbr(self) -> None:
"""
Turn partition table into hybrid GPT/MBR table

View File

@ -121,6 +121,17 @@ class PartitionerMsDos(PartitionerBase):
"""
pass
def set_uuid(self, partition_id: int, uuid: str) -> None:
"""
Set partition UUID
Nothing to be done here for MSDOS devices
:param int partition_id: unused
:param string uuid: unused
"""
pass # pragma: nocover
def set_start_sector(self, start_sector: int):
"""
Set start sector of first partition as configured.

View File

@ -29,7 +29,11 @@ from kiwi.storage.device_provider import DeviceProvider
from kiwi.storage.mapped_device import MappedDevice
from kiwi.partitioner import Partitioner
from kiwi.runtime_config import RuntimeConfig
from kiwi.exceptions import KiwiCustomPartitionConflictError
from kiwi.exceptions import (
KiwiCustomPartitionConflictError,
KiwiCommandError,
KiwiCommandNotFound
)
ptable_entry_type = NamedTuple(
'ptable_entry_type', [
@ -86,6 +90,9 @@ class Disk(DeviceProvider):
'efi'
]
#: Unified partition UUIDs according to systemd
self.gUID = self.get_discoverable_partition_ids()
self.partition_map: Dict[str, str] = {}
self.public_partition_id_map: Dict[str, str] = {}
self.partition_id_map: Dict[str, str] = {}
@ -161,6 +168,11 @@ class Disk(DeviceProvider):
)
self._add_to_map(map_name)
self._add_to_public_id_map(id_name)
part_uuid = self.gUID.get(entry.partition_name)
if part_uuid:
self.partitioner.set_uuid(
self.partition_id_map[map_name], part_uuid
)
def create_root_partition(self, mbsize: str, clone: int = 0):
"""
@ -182,6 +194,11 @@ class Disk(DeviceProvider):
self._add_to_public_id_map('kiwi_RWPart')
if 'kiwi_BootPart' not in self.public_partition_id_map:
self._add_to_public_id_map('kiwi_BootPart')
root_uuid = self.gUID.get('root')
if root_uuid:
self.partitioner.set_uuid(
self.partition_id_map['root'], root_uuid
)
def create_root_lvm_partition(self, mbsize: str, clone: int = 0):
"""
@ -198,6 +215,11 @@ class Disk(DeviceProvider):
self.partitioner.create('p.lxlvm', mbsize, 't.lvm')
self._add_to_map('root')
self._add_to_public_id_map('kiwi_RootPart')
root_uuid = self.gUID.get('root')
if root_uuid:
self.partitioner.set_uuid(
self.partition_id_map['root'], root_uuid
)
def create_root_raid_partition(self, mbsize: str, clone: int = 0):
"""
@ -217,6 +239,11 @@ class Disk(DeviceProvider):
self._add_to_map('root')
self._add_to_public_id_map('kiwi_RootPart')
self._add_to_public_id_map('kiwi_RaidPart')
root_uuid = self.gUID.get('root')
if root_uuid:
self.partitioner.set_uuid(
self.partition_id_map['root'], root_uuid
)
def create_root_readonly_partition(self, mbsize: str, clone: int = 0):
"""
@ -236,6 +263,11 @@ class Disk(DeviceProvider):
self.partitioner.create('p.lxreadonly', mbsize, 't.linux')
self._add_to_map('readonly')
self._add_to_public_id_map('kiwi_ROPart')
root_uuid = self.gUID.get('root')
if root_uuid:
self.partitioner.set_uuid(
self.partition_id_map['readonly'], root_uuid
)
def create_boot_partition(self, mbsize: str, clone: int = 0):
"""
@ -252,6 +284,11 @@ class Disk(DeviceProvider):
self.partitioner.create('p.lxboot', mbsize, 't.linux')
self._add_to_map('boot')
self._add_to_public_id_map('kiwi_BootPart')
boot_uuid = self.gUID.get('xbootldr')
if boot_uuid:
self.partitioner.set_uuid(
self.partition_id_map['boot'], boot_uuid
)
def create_prep_partition(self, mbsize: str):
"""
@ -291,6 +328,11 @@ class Disk(DeviceProvider):
self.partitioner.create('p.swap', mbsize, 't.swap')
self._add_to_map('swap')
self._add_to_public_id_map('kiwi_SwapPart')
swap_uuid = self.gUID.get('swap')
if swap_uuid:
self.partitioner.set_uuid(
self.partition_id_map['swap'], swap_uuid
)
def create_efi_csm_partition(self, mbsize: str):
"""
@ -317,6 +359,11 @@ class Disk(DeviceProvider):
self.partitioner.create('p.UEFI', mbsize, 't.efi')
self._add_to_map('efi')
self._add_to_public_id_map('kiwi_EfiPart')
esp_uuid = self.gUID.get('esp')
if esp_uuid:
self.partitioner.set_uuid(
self.partition_id_map['efi'], esp_uuid
)
def activate_boot_partition(self):
"""
@ -424,6 +471,37 @@ class Disk(DeviceProvider):
sorted(self.public_partition_id_map.items())
)
def get_discoverable_partition_ids(self) -> Dict[str, str]:
"""
Ask systemd for a list of standardized GUIDs for the
current architecture and return them in a dictionary.
If there is no such information available an empty
dictionary is returned
:return: key:value dict from systemd-id128
:rtype: dict
"""
discoverable_ids = {}
try:
raw_lines = Command.run(
['systemd-id128', 'show']
).output.split(os.linesep)[1:]
for line in raw_lines:
if line:
line = ' '.join(line.split())
partition_name, uuid = line.split(' ')
discoverable_ids[partition_name] = uuid
except KiwiCommandNotFound as issue:
log.warning(
f'Failed to call systemd-id128: {issue}'
)
except KiwiCommandError as issue:
log.warning(
f'Failed to obtain discoverable partition IDs: {issue}'
)
return discoverable_ids
def _create_clones(
self, name: str, clone: int, type_flag: str, mbsize: str
) -> None:

View File

@ -0,0 +1,46 @@
NAME ID
root-x86 44479540f29741b29af7d131d5f0458a
root-x86-verity d13c5d3bb5d1422ab29f9454fdc89d76
root-x86-64 4f68bce3e8cd4db196e7fbcaf984b709
root-x86-64-verity 2c7357edebd246d9aec123d437ec2bf5
root-arm 69dad7102ce44e3cb16c21a1d49abed3
root-arm-verity 7386cdf2203c47a9a498f2ecce45a2d6
root-arm64 b921b0451df041c3af444c6f280d3fae
root-arm64-verity df3300ced69f4c92978c9bfb0f38d820
root-ia64 993d8d3df80e4225855a9daf8ed7ea97
root-ia64-verity 86ed10d5b60745bb8957d350f23d0571
root-riscv32 60d5a7fe8e7d435cb7143dd8162144e1
root-riscv32-verity ae0253be11674007ac6843926c14c5de
root-riscv64 72ec70a6cf7440e6bd494bda08e8f224
root-riscv64-verity b6ed5582440b4209b8da5ff7c419ea3d
root 4f68bce3e8cd4db196e7fbcaf984b709
root-verity 2c7357edebd246d9aec123d437ec2bf5
root-secondary 44479540f29741b29af7d131d5f0458a
root-secondary-verity d13c5d3bb5d1422ab29f9454fdc89d76
usr-x86 75250d768cc6458ebd66bd47cc81a812
usr-x86-verity 8f461b0d14ee4e819aa9049b6fb97abd
usr-x86-64 8484680c952148c69c11b0720656f69e
usr-x86-64-verity 77ff5f63e7b64633acf41565b864c0e6
usr-arm 7d0359a302b34f0a865c654403e70625
usr-arm-verity c215d7517bcd4649be906627490a4c05
usr-arm64 b0e01050ee5f4390949a9101b17104e9
usr-arm64-verity 6e11a4e7fbca4dedb9e9e1a512bb664e
usr-ia64 4301d2a64e3b4b2abb949e0b2c4225ea
usr-ia64-verity 6a491e033be745458e3883320e0ea880
usr-riscv32 b933fb225c3f4f91af90e2bb0fa50702
usr-riscv32-verity cb1ee4e38cd04136a0a4aa61a32e8730
usr-riscv64 beaec34b8442439ba40b984381ed097d
usr-riscv64-verity 8f1056be9b0547c481d6be53128e5b54
usr 8484680c952148c69c11b0720656f69e
usr-verity 77ff5f63e7b64633acf41565b864c0e6
usr-secondary 75250d768cc6458ebd66bd47cc81a812
usr-secondary-verity 8f461b0d14ee4e819aa9049b6fb97abd
esp c12a7328f81f11d2ba4b00a0c93ec93b
xbootldr bc13c2ff59e64262a352b275fd6f7172
swap 0657fd6da4ab43c484e50933c84b4f4f
home 933ac7e12eb44f13b8440e14e2aef915
srv 3b8f842520e04f3b907f1a25a76f98e8
var 4d21b016b53445c2a9fb5c16e091fd2d
tmp 7ec6f5573bc54acab29316ef5df639d1
user-home 773f91ef66d449b5bd83d683bf40ad16
linux-generic 0fc63daf848347728e793d69d8477de4

View File

@ -18,6 +18,10 @@ class TestPartitionerBase:
def test_get_id(self):
assert self.partitioner.get_id() == 0
def test_set_uuid(self):
with raises(NotImplementedError):
self.partitioner.set_uuid(100, 'ID')
def test_create(self):
with raises(NotImplementedError):
self.partitioner.create('name', 100, 'type', ['flag'])

View File

@ -116,3 +116,10 @@ class TestPartitionerGpt:
mock_command.assert_called_once_with(
['sgdisk', '--resize-table', '42', '/dev/loop0']
)
@patch('kiwi.partitioner.gpt.Command.run')
def test_set_uuid(self, mock_Command_run):
self.partitioner.set_uuid(42, 'ID')
mock_Command_run.assert_called_once_with(
['sgdisk', '--partition-guid', '42:ID', '/dev/loop0']
)

View File

@ -10,7 +10,11 @@ import unittest.mock as mock
from kiwi.storage.disk import ptable_entry_type
from kiwi.storage.disk import Disk
from kiwi.exceptions import KiwiCustomPartitionConflictError
from kiwi.exceptions import (
KiwiCustomPartitionConflictError,
KiwiCommandError,
KiwiCommandNotFound
)
class TestDisk:
@ -18,9 +22,13 @@ class TestDisk:
def inject_fixtures(self, caplog):
self._caplog = caplog
@patch.object(Disk, 'get_discoverable_partition_ids')
@patch('kiwi.storage.disk.Partitioner.new')
@patch('kiwi.storage.disk.RuntimeConfig')
def setup(self, mock_RuntimeConfig, mock_partitioner):
def setup(
self, mock_RuntimeConfig, mock_partitioner,
mock_get_discoverable_partition_ids
):
runtime_config = Mock()
runtime_config.get_mapper_tool.return_value = 'partx'
mock_RuntimeConfig.return_value = runtime_config
@ -304,8 +312,11 @@ class TestDisk:
['partprobe', '/dev/loop0']
)
@patch.object(Disk, 'get_discoverable_partition_ids')
@patch('kiwi.storage.disk.Command.run')
def test_destructor_partx_loop_cleanup_failed(self, mock_command):
def test_context_manager_exit_partx_loop_cleanup_failed(
self, mock_command, mock_get_discoverable_partition_ids
):
mock_command.side_effect = Exception
with Disk('gpt', self.storage_provider) as disk:
disk.is_mapped = True
@ -315,8 +326,11 @@ class TestDisk:
['partx', '--delete', '/dev/loop0']
)
@patch.object(Disk, 'get_discoverable_partition_ids')
@patch('kiwi.storage.disk.Command.run')
def test_destructor_dm_loop_cleanup_failed(self, mock_command):
def test_context_manager_exit_dm_loop_cleanup_failed(
self, mock_command, mock_get_discoverable_partition_ids
):
mock_command.side_effect = Exception
with Disk('gpt', self.storage_provider) as disk:
disk.partition_mapper = 'kpartx'
@ -327,8 +341,11 @@ class TestDisk:
['dmsetup', 'remove', '/dev/mapper/loop0p1']
)
@patch.object(Disk, 'get_discoverable_partition_ids')
@patch('kiwi.storage.disk.Command.run')
def test_destructor_partx(self, mock_command):
def test_context_manager_exit_partx(
self, mock_command, mock_get_discoverable_partition_ids
):
with Disk('gpt', self.storage_provider) as disk:
disk.is_mapped = True
disk.partition_map = {'root': '/dev/loop0p1'}
@ -336,8 +353,11 @@ class TestDisk:
call(['partx', '--delete', '/dev/loop0'])
]
@patch.object(Disk, 'get_discoverable_partition_ids')
@patch('kiwi.storage.disk.Command.run')
def test_destructor_kpartx(self, mock_command):
def test_context_manager_exit_kpartx(
self, mock_command, mock_get_discoverable_partition_ids
):
with Disk('gpt', self.storage_provider) as disk:
disk.partition_mapper = 'kpartx'
disk.is_mapped = True
@ -371,3 +391,16 @@ class TestDisk:
(size, clone_size) = self.disk._parse_size('clone:100:all_free')
assert size == '100'
assert clone_size == 'all_free'
@patch('kiwi.storage.disk.Command.run')
def test_get_discoverable_partition_ids(self, mock_Command_run):
command = Mock()
with open('../data/systemd-id128.out') as ids:
command.output = ids.read()
mock_Command_run.return_value = command
assert self.disk.get_discoverable_partition_ids()['root'] == \
'4f68bce3e8cd4db196e7fbcaf984b709'
mock_Command_run.side_effect = KiwiCommandError('issue')
assert self.disk.get_discoverable_partition_ids().get('root') is None
mock_Command_run.side_effect = KiwiCommandNotFound('issue')
assert self.disk.get_discoverable_partition_ids().get('root') is None