From f1fdff22c356fcfb6ef546633e7872313dca36d1 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 7 Aug 2024 16:47:52 +0200 Subject: [PATCH 2/2] Get rid of gdisk dependency RH-Author: Vitaly Kuznetsov RH-MergeRequest: 106: Get rid of gdisk dependency RH-Jira: RHEL-36093 RH-Acked-by: Emanuele Giuseppe Esposito RH-Acked-by: Cathy Avery RH-Commit: [2/2] 7814ff343d4f8e7db95ca1853ea0079fe577354a (vkuznets/cloud-init) gdisk is not going to be shipped in RHEL10 as sfdisk is perfectly capable of dealing with GPT partition tables. cloud-init's upstream still relies on sgdisk for GPT and is reluctant to do the switch, do this downstream only for now. X-downstream-only: true Signed-off-by: Vitaly Kuznetsov --- .distro/cloud-init.spec | 1 - cloudinit/config/cc_disk_setup.py | 98 +++++++++++++------------------ 2 files changed, 42 insertions(+), 57 deletions(-) diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py index fa6a52d3..7638b425 100644 --- a/cloudinit/config/cc_disk_setup.py +++ b/cloudinit/config/cc_disk_setup.py @@ -10,6 +10,7 @@ import logging import os import shlex +import json from textwrap import dedent from cloudinit import subp, util @@ -21,7 +22,6 @@ from cloudinit.settings import PER_INSTANCE # Define the commands to use SFDISK_CMD = subp.which("sfdisk") -SGDISK_CMD = subp.which("sgdisk") LSBLK_CMD = subp.which("lsblk") BLKID_CMD = subp.which("blkid") BLKDEV_CMD = subp.which("blockdev") @@ -856,44 +856,32 @@ sgdisk_to_gpt_id = { gpt_id_to_sgdisk = {v: k for k, v in reversed(sgdisk_to_gpt_id.items())} def check_partition_gpt_layout(device, layout): - prt_cmd = [SGDISK_CMD, "-p", device] + # Use sfdisk's JSON output for reliability + prt_cmd = [SFDISK_CMD, "-l", "-J", device] try: out, _err = subp.subp(prt_cmd, update_env=LANG_C_ENV) + ptable = json.loads(out)["partitiontable"] + if "partitions" in ptable: + partitions = ptable["partitions"] + else: + partitions = [] + except Exception as e: raise RuntimeError( "Error running partition command on %s\n%s" % (device, e) ) from e - out_lines = iter(out.splitlines()) - # Skip header. Output looks like: - # *************************************************************** - # Found invalid GPT and valid MBR; converting MBR to GPT format - # in memory. - # *************************************************************** - # - # Disk /dev/vdb: 83886080 sectors, 40.0 GiB - # Logical sector size: 512 bytes - # Disk identifier (GUID): 8A7F11AD-3953-491B-8051-077E01C8E9A7 - # Partition table holds up to 128 entries - # First usable sector is 34, last usable sector is 83886046 - # Partitions will be aligned on 2048-sector boundaries - # Total free space is 83476413 sectors (39.8 GiB) - # - # Number Start (sector) End (sector) Size Code Name - # 1 2048 206847 100.0 MiB 0700 Microsoft basic data - for line in out_lines: - if line.strip().startswith("Number"): - break - - codes = [line.strip().split()[5] for line in out_lines] - cleaned = [] - - # user would expect a code '83' to be Linux, but sgdisk outputs 8300. - for code in codes: - if len(code) == 4 and code.endswith("00"): - code = code[0:2] - cleaned.append(code) - return cleaned + found_layout = [] + for part in partitions: + if part["type"] in gpt_id_to_sgdisk: + ptype = gpt_id_to_sgdisk[part["type"]] + if len(ptype) == 4 and ptype[-2:] == "00": + ptype = ptype[0:2] + found_layout.append(ptype) + else: + # Unknown GPT UUID, using standard Linux + found_layout.append("83") + return found_layout def check_partition_layout(table_type, device, layout): @@ -1066,11 +1054,11 @@ def get_partition_layout(table_type, size, layout): This is a future proofing function. To add support for other layouts, simply add a "get_partition_%s_layout" function. + + RHEL-only: sfdisk is used both for GPT and MBR """ - if "mbr" == table_type: + if table_type in ["gpt", "mbr"]: return get_partition_mbr_layout(size, layout) - elif "gpt" == table_type: - return get_partition_gpt_layout(size, layout) raise RuntimeError("Unable to determine table type") @@ -1110,28 +1098,26 @@ def exec_mkpart_mbr(device, layout): def exec_mkpart_gpt(device, layout): + prt_cmd = [SFDISK_CMD, "-X", "gpt", "--force", device] try: - subp.subp([SGDISK_CMD, "-Z", device]) - for index, (partition_type, (start, end)) in enumerate(layout): - index += 1 - subp.subp( - [ - SGDISK_CMD, - "-n", - "{}:{}:{}".format(index, start, end), - device, - ] - ) - if partition_type is not None: - # convert to a 4 char (or more) string right padded with 0 - # 82 -> 8200. 'Linux' -> 'Linux' - pinput = str(partition_type).ljust(4, "0") - subp.subp( - [SGDISK_CMD, "-t", "{}:{}".format(index, pinput), device] - ) - except Exception: - LOG.warning("Failed to partition device %s", device) - raise + layout_fixed = [] + # convert partition UUIDs to GPT UUIDs + for part in layout.split('\n'): + (pstart, psize, ptype) = part.split(',') + if len(ptype) == 2: + ptype = ptype + "00" + if ptype.upper() in sgdisk_to_gpt_id: + ptype = sgdisk_to_gpt_id[ptype] + else: + # Use standard Linux for unknown ids + ptype = "0FC63DAF-8483-4772-8E79-3D69D8477DE4" + layout_fixed.append(','.join([pstart, psize, ptype])) + layout = '\n'.join(layout_fixed) + subp.subp(prt_cmd, data="%s\n" % layout) + except Exception as e: + raise RuntimeError( + "Failed to partition device %s\n%s" % (device, e) + ) from e read_parttbl(device) -- 2.39.3