cloud-init-dev team mailing list archive
-
cloud-init-dev team
-
Mailing list archive
-
Message #02210
[Merge] ~smoser/cloud-init:bug/1692087-disk_setup-gpt-improvements into cloud-init:master
Scott Moser has proposed merging ~smoser/cloud-init:bug/1692087-disk_setup-gpt-improvements into cloud-init:master.
Commit message:
disk_setup: fix several issues with gpt disk partitions.
This fixes several shortcomings of disk_setup with gpt disks.
* 'sgdisk -p' was being used to determine the size of a disk.
this can fail if it believes there is a bad gpt partition table.
Instead we just use blockdev now for both mbr or gpt disks.
* parsing of sgdisk -p output assumed that the 'name' of the partition
type would not have any spaces (Microsoft basic data)
* interaction with sgdisk did not realize that sgdisk wants input
of '8300' rather than '83' and will output the same.
LP: #1692087
Requested reviews:
cloud-init commiters (cloud-init-dev)
Related bugs:
Bug #1692087 in cloud-init: "check_partition_layout has false positives when partitioned with gpt"
https://bugs.launchpad.net/cloud-init/+bug/1692087
For more details, see:
https://code.launchpad.net/~smoser/cloud-init/+git/cloud-init/+merge/324338
--
Your team cloud-init commiters is requested to review the proposed merge of ~smoser/cloud-init:bug/1692087-disk_setup-gpt-improvements into cloud-init:master.
diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py
index 29eb5dd..e1505b3 100644
--- a/cloudinit/config/cc_disk_setup.py
+++ b/cloudinit/config/cc_disk_setup.py
@@ -431,7 +431,7 @@ def get_dyn_func(*args):
raise Exception("No such function %s to call!" % func_name)
-def get_mbr_hdd_size(device):
+def get_hdd_size(device):
try:
size_in_bytes, _ = util.subp([BLKDEV_CMD, '--getsize64', device])
sector_size, _ = util.subp([BLKDEV_CMD, '--getss', device])
@@ -441,22 +441,6 @@ def get_mbr_hdd_size(device):
return int(size_in_bytes) / int(sector_size)
-def get_gpt_hdd_size(device):
- out, _ = util.subp([SGDISK_CMD, '-p', device], update_env=LANG_C_ENV)
- for line in out.splitlines():
- if line.startswith("Disk"):
- return line.split()[2]
- raise Exception("Failed to get %s size from sgdisk" % (device))
-
-
-def get_hdd_size(table_type, device):
- """
- Returns the hard disk size.
- This works with any disk type, including GPT.
- """
- return get_dyn_func("get_%s_hdd_size", table_type, device)
-
-
def check_partition_mbr_layout(device, layout):
"""
Returns true if the partition layout matches the one on the disk
@@ -504,12 +488,35 @@ def check_partition_gpt_layout(device, layout):
device, e))
out_lines = iter(out.splitlines())
- # Skip header
+ # 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
- return [line.strip().split()[-1] for line in out_lines]
+ 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
def check_partition_layout(table_type, device, layout):
@@ -523,6 +530,8 @@ def check_partition_layout(table_type, device, layout):
found_layout = get_dyn_func(
"check_partition_%s_layout", table_type, device, layout)
+ LOG.debug("called check_partition_%s_layout(%s, %s), returned: %s",
+ table_type, device, layout, found_layout)
if isinstance(layout, bool):
# if we are using auto partitioning, or "True" be happy
# if a single partition exists.
@@ -530,18 +539,17 @@ def check_partition_layout(table_type, device, layout):
return True
return False
- else:
- if len(found_layout) != len(layout):
- return False
- else:
- # This just makes sure that the number of requested
- # partitions and the type labels are right
- for x in range(1, len(layout) + 1):
- if isinstance(layout[x - 1], tuple):
- _, part_type = layout[x]
- if int(found_layout[x]) != int(part_type):
- return False
- return True
+ elif len(found_layout) == len(layout):
+ # This just makes sure that the number of requested
+ # partitions and the type labels are right
+ layout_types = [str(x[1]) if isinstance(x, (tuple, list)) else None
+ for x in layout]
+ LOG.debug("Layout types=%s. Found types=%s",
+ layout_types, found_layout)
+ for itype, ftype in zip(layout_types, found_layout):
+ if itype is not None and str(ftype) != str(itype):
+ return False
+ return True
return False
@@ -704,9 +712,11 @@ def exec_mkpart_gpt(device, layout):
util.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")
util.subp(
- [SGDISK_CMD,
- '-t', '{}:{}'.format(index, partition_type), device])
+ [SGDISK_CMD, '-t', '{}:{}'.format(index, pinput), device])
except Exception:
LOG.warning("Failed to partition device %s", device)
raise
@@ -777,8 +787,8 @@ def mkpart(device, definition):
LOG.debug("Skipping partitioning on configured device %s", device)
return
- LOG.debug("Checking for device size")
- device_size = get_hdd_size(table_type, device)
+ LOG.debug("Checking for device size of %s", device)
+ device_size = get_hdd_size(device)
LOG.debug("Calculating partition layout")
part_definition = get_partition_layout(table_type, device_size, layout)
References