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 <dusty@dustymabe.com>
This commit is contained in:
Nikita Dubrovskii 2024-01-26 14:18:21 +01:00 committed by Achilleas Koutsou
parent 6b8c1872f6
commit fc185dae8c
7 changed files with 57 additions and 9 deletions

View file

@ -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"),

View file

@ -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"),

View file

@ -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"

View file

@ -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}"

View file

@ -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"

View file

@ -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

View file

@ -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")