From fc185dae8c5aff94e170c063772660893c0350f0 Mon Sep 17 00:00:00 2001 From: Nikita Dubrovskii Date: Fri, 26 Jan 2024 14:18:21 +0100 Subject: [PATCH] support user-defined partition numbers for GPT disks Partitions by default are indexed starting at 1, but in some cases, such as CoreOS for IBM Z, it may be usefull to set the 'partnum' for GPT disks explicitly, without creating dummy partitions. Now user can define an image: ``` mpp-define-images: - id: image size: 10737418240 table: uuid: 00000000-0000-4000-a000-000000000001 label: gpt partitions: - name: boot type: 0FC63DAF-8483-4772-8E79-3D69D8477DE4 partnum: 3 size: 786432 - name: root type: 0FC63DAF-8483-4772-8E79-3D69D8477DE4 partnum: 4 size: 4194304 ``` So target disk would look like: ``` Disklabel type: gpt Disk identifier: 00000000-0000-4000-A000-000000000001 Device Start End Sectors Size Type /dev/loop0p3 2048 788479 786432 384M Linux filesystem /dev/loop0p4 788480 4982783 4194304 2G Linux filesystem ``` This patch updates the osbuild-mpp tool and the sgdisk and sfdisk stages to support this. Co-authored-by: Dusty Mabe --- stages/org.osbuild.sfdisk | 19 ++++++++++++++++--- stages/org.osbuild.sgdisk | 9 ++++++++- .../manifests/fedora-coreos-container.json | 8 ++++++++ .../fedora-coreos-container.mpp.yaml | 4 ++++ test/data/manifests/fedora-ostree-image.json | 4 ++++ .../manifests/fedora-ostree-image.mpp.yaml | 4 ++++ tools/osbuild-mpp | 18 +++++++++++++----- 7 files changed, 57 insertions(+), 9 deletions(-) diff --git a/stages/org.osbuild.sfdisk b/stages/org.osbuild.sfdisk index 9887a02e..108866c4 100755 --- a/stages/org.osbuild.sfdisk +++ b/stages/org.osbuild.sfdisk @@ -4,6 +4,7 @@ Partition a target using sfdisk(8) """ import json +import re import subprocess import sys from typing import Optional @@ -50,6 +51,10 @@ SCHEMA_2 = r""" "description": "The partition name (GPT)", "type": "string" }, + "partnum": { + "description": "The partition number", + "type": "integer" + }, "size": { "description": "The size of this partition", "type": "integer" @@ -88,6 +93,7 @@ SCHEMA_2 = r""" class Partition: def __init__(self, pttype: str = None, + partnum: int = None, start: int = None, size: int = None, bootable: bool = False, @@ -95,13 +101,15 @@ class Partition: uuid: str = None, attrs: int = None): self.type = pttype + self.partnum = partnum self.start = start self.size = size self.bootable = bootable self.name = name self.uuid = uuid - self.index = None self.attrs = attrs + self.index = partnum - 1 if partnum else None + self.partnum = partnum if partnum else None @property def start_in_bytes(self): @@ -167,7 +175,10 @@ class PartitionTable: fields += [f'{field}="{value}"'] if partition.bootable: fields += ["bootable"] - command += "\n" + ", ".join(fields) + if partition.partnum: + command += "\n" + f'{target}p{partition.partnum}: ' + ", ".join(fields) + else: + command += "\n" + ", ".join(fields) print(command) @@ -190,7 +201,8 @@ class PartitionTable: assert len(disk_parts) == len(self.partitions) for i, part in enumerate(self.partitions): - part.index = i + part.partnum = int(re.findall(r'\d+$', disk_parts[i]["node"])[0]) + part.index = part.partnum - 1 part.start = disk_parts[i]["start"] part.size = disk_parts[i]["size"] part.type = disk_parts[i].get("type") @@ -200,6 +212,7 @@ class PartitionTable: def partition_from_json(js) -> Partition: p = Partition(pttype=js.get("type"), + partnum=js.get("partnum"), start=js.get("start"), size=js.get("size"), bootable=js.get("bootable"), diff --git a/stages/org.osbuild.sgdisk b/stages/org.osbuild.sgdisk index e11e0119..1627a90f 100755 --- a/stages/org.osbuild.sgdisk +++ b/stages/org.osbuild.sgdisk @@ -50,6 +50,10 @@ SCHEMA_2 = r""" "description": "The partition name", "type": "string" }, + "partnum": { + "description": "The partition number", + "type": "integer" + }, "size": { "description": "The size of this partition", "type": "integer" @@ -88,6 +92,7 @@ SCHEMA_2 = r""" class Partition: def __init__(self, pttype: str = None, + partnum: int = None, start: int = None, size: int = None, bootable: bool = False, @@ -95,6 +100,7 @@ class Partition: uuid: str = None, attrs: int = None): self.type = pttype + self.partnum = partnum self.start = start self.size = size self.name = name @@ -129,7 +135,7 @@ class PartitionTable: command += ["-U", self.uuid] for i, part in enumerate(self.partitions): - idx = i + 1 # partitions are 1-indexed + idx = part.partnum if part.partnum else i + 1 # partitions are 1-indexed # format is 'partnum:start:end' size = "0" @@ -173,6 +179,7 @@ class PartitionTable: def partition_from_json(js) -> Partition: p = Partition(pttype=js.get("type"), + partnum=js.get("partnum"), start=js.get("start"), size=js.get("size"), bootable=js.get("bootable"), diff --git a/test/data/manifests/fedora-coreos-container.json b/test/data/manifests/fedora-coreos-container.json index fb56b861..ba1f0ad4 100644 --- a/test/data/manifests/fedora-coreos-container.json +++ b/test/data/manifests/fedora-coreos-container.json @@ -560,6 +560,7 @@ "partitions": [ { "start": 2048, + "partnum": 1, "size": 2048, "type": "21686148-6449-6E6F-744E-656564454649", "bootable": true, @@ -567,18 +568,21 @@ }, { "start": 4096, + "partnum": 2, "size": 260096, "type": "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", "name": "EFI-SYSTEM" }, { "start": 264192, + "partnum": 3, "size": 786432, "type": "0FC63DAF-8483-4772-8E79-3D69D8477DE4", "name": "boot" }, { "start": 1050624, + "partnum": 4, "size": 4194304, "type": "0FC63DAF-8483-4772-8E79-3D69D8477DE4", "name": "root" @@ -806,6 +810,7 @@ "partitions": [ { "start": 256, + "partnum": 1, "size": 256, "type": "21686148-6449-6E6F-744E-656564454649", "bootable": true, @@ -813,18 +818,21 @@ }, { "start": 512, + "partnum": 2, "size": 32512, "type": "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", "name": "EFI-SYSTEM" }, { "start": 33024, + "partnum": 3, "size": 98304, "type": "0FC63DAF-8483-4772-8E79-3D69D8477DE4", "name": "boot" }, { "start": 131328, + "partnum": 4, "size": 524288, "type": "0FC63DAF-8483-4772-8E79-3D69D8477DE4", "name": "root" diff --git a/test/data/manifests/fedora-coreos-container.mpp.yaml b/test/data/manifests/fedora-coreos-container.mpp.yaml index 2494b867..d6f220d3 100644 --- a/test/data/manifests/fedora-coreos-container.mpp.yaml +++ b/test/data/manifests/fedora-coreos-container.mpp.yaml @@ -31,18 +31,22 @@ mpp-define-images: bootable: true size: mpp-format-int: "{bios_boot_size_mb * 1024 * 1024 / sector_size}" + partnum: 1 - name: EFI-SYSTEM type: C12A7328-F81F-11D2-BA4B-00A0C93EC93B size: mpp-format-int: "{efi_system_size_mb * 1024 * 1024 / sector_size}" + partnum: 2 - name: boot type: 0FC63DAF-8483-4772-8E79-3D69D8477DE4 size: mpp-format-int: "{boot_size_mb * 1024 * 1024 / sector_size}" + partnum: 3 - name: root type: 0FC63DAF-8483-4772-8E79-3D69D8477DE4 size: mpp-format-int: "{root_size_mb * 1024 * 1024 / sector_size}" + partnum: 4 - id: image4k sector_size: mpp-format-int: "{four_k_sector_size}" diff --git a/test/data/manifests/fedora-ostree-image.json b/test/data/manifests/fedora-ostree-image.json index 55c8d179..df769a7a 100644 --- a/test/data/manifests/fedora-ostree-image.json +++ b/test/data/manifests/fedora-ostree-image.json @@ -1231,6 +1231,7 @@ "partitions": [ { "start": 2048, + "partnum": 1, "size": 2048, "type": "21686148-6449-6E6F-744E-656564454649", "bootable": true, @@ -1238,18 +1239,21 @@ }, { "start": 4096, + "partnum": 2, "size": 204800, "type": "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", "uuid": "68B2905B-DF3E-4FB3-80FA-49D1E773AA33" }, { "start": 208896, + "partnum": 3, "size": 204800, "type": "0FC63DAF-8483-4772-8E79-3D69D8477DE4", "uuid": "61B2905B-DF3E-4FB3-80FA-49D1E773AA32" }, { "start": 413696, + "partnum": 4, "size": 20555776, "type": "0FC63DAF-8483-4772-8E79-3D69D8477DE4", "uuid": "CA7D7CCB-63ED-4C53-861C-1742536059CC" diff --git a/test/data/manifests/fedora-ostree-image.mpp.yaml b/test/data/manifests/fedora-ostree-image.mpp.yaml index 52bf80dd..f93e8a0e 100644 --- a/test/data/manifests/fedora-ostree-image.mpp.yaml +++ b/test/data/manifests/fedora-ostree-image.mpp.yaml @@ -11,17 +11,21 @@ mpp-define-image: type: 21686148-6449-6E6F-744E-656564454649 bootable: true uuid: FAC7F1FB-3E8D-4137-A512-961DE09A5549 + partnum: 1 - id: efi size: 204800 type: C12A7328-F81F-11D2-BA4B-00A0C93EC93B uuid: 68B2905B-DF3E-4FB3-80FA-49D1E773AA33 + partnum: 2 - id: boot size: 204800 type: 0FC63DAF-8483-4772-8E79-3D69D8477DE4 uuid: 61B2905B-DF3E-4FB3-80FA-49D1E773AA32 + partnum: 3 - id: luks type: 0FC63DAF-8483-4772-8E79-3D69D8477DE4 uuid: CA7D7CCB-63ED-4C53-861C-1742536059CC + partnum: 4 pipelines: - mpp-import-pipelines: path: fedora-vars.ipp.yaml diff --git a/tools/osbuild-mpp b/tools/osbuild-mpp index cf74488e..7bf93a18 100755 --- a/tools/osbuild-mpp +++ b/tools/osbuild-mpp @@ -357,6 +357,7 @@ import hashlib import json import os import pathlib +import re import string import subprocess import sys @@ -815,6 +816,7 @@ class Partition: def __init__(self, uid: str = None, pttype: str = None, + partnum: int = None, start: int = None, size: int = None, bootable: bool = False, @@ -830,8 +832,8 @@ class Partition: self.name = name self.uuid = uuid self.attrs = attrs - self.index = None - self.partnum = None + self.index = partnum - 1 if partnum else None + self.partnum = partnum if partnum else None @property def start_in_bytes(self): @@ -845,6 +847,7 @@ class Partition: def from_dict(cls, js): p = cls(uid=js.get("id"), pttype=js.get("type"), + partnum=js.get("partnum"), start=js.get("start"), size=js.get("size"), bootable=js.get("bootable"), @@ -858,6 +861,8 @@ class Partition: if self.start: data["start"] = self.start + if self.partnum: + data["partnum"] = self.partnum if self.size: data["size"] = self.size if self.type: @@ -915,7 +920,10 @@ class PartitionTable: fields += [f'{field}="{value}"'] if partition.bootable: fields += ["bootable"] - command += "\n" + ", ".join(fields) + if partition.partnum: + command += "\n" + f'{target}p{partition.partnum}: ' + ", ".join(fields) + else: + command += "\n" + ", ".join(fields) subprocess.run(["sfdisk", "-q", "--no-tell-kernel", target], input=command, @@ -936,8 +944,8 @@ class PartitionTable: assert len(disk_parts) == len(self.partitions) for i, part in enumerate(self.partitions): - part.index = i - part.partnum = i + 1 + part.partnum = int(re.findall(r'\d+$', disk_parts[i]["node"])[0]) + part.index = part.partnum - 1 part.start = disk_parts[i]["start"] part.size = disk_parts[i]["size"] part.type = disk_parts[i].get("type")