Merged PR #711 - Fixing disk "ghosting" issues using partprobe

* Adding partprobe at strategic places.
* Swapped `for partition in blockdevice` to `for uuid, partition in blockdevice.partitions.items()` instead as `__iter__` for debugging purposes.
* `get_mount_info()` now causes a exception rather than returning nothing if there is nothing to be shown. This to avoid issues where in places this is crucial information and it went by unnoticeable. Using exception handlers where it doesn't matter if there's any information or not.
This commit is contained in:
Anton Hvornum 2021-11-11 18:11:38 +00:00 committed by GitHub
commit ca52c796a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 39 additions and 28 deletions

View File

@ -112,8 +112,8 @@ class BlockDevice:
@property
def partitions(self):
from .filesystem import Partition
SysCommand(['partprobe', self.path])
self.partprobe()
result = SysCommand(['/usr/bin/lsblk', '-J', self.path])
if b'not a block device' in result:
@ -202,6 +202,9 @@ class BlockDevice:
info = space_info
return info
def partprobe(self):
SysCommand(['partprobe', self.path])
def has_partitions(self):
return len(self.partitions)
@ -217,7 +220,7 @@ class BlockDevice:
def get_partition(self, uuid):
count = 0
while count < 5:
for partition in self:
for partition_uuid, partition in self.partitions.items():
if partition.uuid == uuid:
return partition
else:
@ -226,4 +229,7 @@ class BlockDevice:
count += 1
else:
log(f"Could not find {uuid} in disk after 5 retries",level=logging.INFO)
print(f"Cache: {self.part_cache}")
print(f"Partitions: {self.partitions.items()}")
print(f"UUID: {[uuid]}")
raise DiskError(f"New partition {uuid} never showed up after adding new partition on {self}")

View File

@ -20,24 +20,8 @@ class Filesystem:
self.mode = mode
def __enter__(self, *args, **kwargs):
if self.blockdevice.keep_partitions is False:
log(f'Wiping {self.blockdevice} by using partition format {self.mode}', level=logging.DEBUG)
if self.mode == GPT:
if self.parted_mklabel(self.blockdevice.device, "gpt"):
self.blockdevice.flush_cache()
return self
else:
raise DiskError('Problem setting the disk label type to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt')
elif self.mode == MBR:
if self.parted_mklabel(self.blockdevice.device, "msdos"):
return self
else:
raise DiskError('Problem setting the disk label type to msdos:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel msdos')
else:
raise DiskError(f'Unknown mode selected to format in: {self.mode}')
# TODO: partition_table_type is hardcoded to GPT at the moment. This has to be changed.
elif self.mode == self.blockdevice.partition_table_type:
if self.mode == self.blockdevice.partition_table_type:
log(f'Kept partition format {self.mode} for {self.blockdevice}', level=logging.DEBUG)
else:
raise DiskError(f'The selected partition table format {self.mode} does not match that of {self.blockdevice}.')
@ -74,6 +58,8 @@ class Filesystem:
if not self.parted_mklabel(self.blockdevice.device, "msdos"):
raise KeyError(f"Could not create a MSDOS label on {self}")
self.blockdevice.flush_cache()
# We then iterate the partitions in order
for partition in layout.get('partitions', []):
# We don't want to re-add an existing partition (those containing a UUID already)
@ -132,6 +118,9 @@ class Filesystem:
if partition.target_mountpoint == mountpoint or partition.mountpoint == mountpoint:
return partition
def partprobe(self):
SysCommand(f'bash -c "partprobe"')
def raw_parted(self, string: str):
if (cmd_handle := SysCommand(f'/usr/bin/parted -s {string}')).exit_code != 0:
log(f"Parted ended with a bad exit code: {cmd_handle}", level=logging.ERROR, fg="red")
@ -146,6 +135,7 @@ class Filesystem:
:type string: str
"""
if (parted_handle := self.raw_parted(string)).exit_code == 0:
self.partprobe()
return True
else:
raise DiskError(f"Parted failed to add a partition: {parted_handle}")
@ -176,7 +166,15 @@ class Filesystem:
if len(new_uuid_set) > 0:
new_uuid = new_uuid_set.pop()
if new_uuid:
return self.blockdevice.get_partition(new_uuid)
try:
return self.blockdevice.get_partition(new_uuid)
except Exception as err:
print('Blockdevice:', self.blockdevice)
print('Partitions:', self.blockdevice.partitions)
print('Partition set:', new_uuid_set)
print('New UUID:', [new_uuid])
print('get_partition():', self.blockdevice.get_partition)
raise err
else:
count += 1
log(f"Could not get uuid for partition. Waiting for the {count} time",level=logging.DEBUG)
@ -199,4 +197,5 @@ class Filesystem:
SysCommand(f'bash -c "umount {device}?"')
except:
pass
self.partprobe()
return self.raw_parted(f'{device} mklabel {disk_label}').exit_code == 0

View File

@ -121,7 +121,7 @@ def harddrive(size=None, model=None, fuzzy=False):
def get_mount_info(path :Union[pathlib.Path, str], traverse=False, return_real_path=False) -> dict:
for traversal in list(map(str, [str(path)] + list(pathlib.Path(str(path)).parents))):
try:
log(f"Getting mount information at location {traversal}", level=logging.INFO)
log(f"Getting mount information for device path {traversal}", level=logging.INFO)
output = SysCommand(f'/usr/bin/findmnt --json {traversal}').decode('UTF-8')
if output:
break
@ -132,10 +132,7 @@ def get_mount_info(path :Union[pathlib.Path, str], traverse=False, return_real_p
break
if not output:
if return_real_path:
return {}, None
else:
return {}
raise DiskError(f"Could not get mount information for device path {path}")
output = json.loads(output)
if 'filesystems' in output:

View File

@ -32,7 +32,10 @@ class Partition:
if mountpoint:
self.mount(mountpoint)
mount_information = get_mount_info(self.path)
try:
mount_information = get_mount_info(self.path)
except DiskError:
mount_information = {}
if self.mountpoint != mount_information.get('target', None) and mountpoint:
raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {mount_information.get('target', None)}")
@ -145,8 +148,11 @@ class Partition:
it doesn't seam to be able to detect md raid partitions.
"""
lsblk = json.loads(SysCommand(f'lsblk -J -o+PARTUUID {self.path}').decode('UTF-8'))
for partition in lsblk['blockdevices']:
partuuid_struct = SysCommand(f'lsblk -J -o+PARTUUID {self.path}')
if not partuuid_struct.exit_code == 0:
raise DiskError(f"Could not get PARTUUID for {self.path}: {partuuid_struct}")
for partition in json.loads(partuuid_struct.decode('UTF-8'))['blockdevices']:
return partition.get('partuuid', None)
return None

View File

@ -61,6 +61,8 @@ class luks2:
with open(key_file, 'wb') as fh:
fh.write(password)
SysCommand(f'bash -c "partprobe"') # Might be redundant
cryptsetup_args = shlex.join([
'/usr/bin/cryptsetup',
'--batch-mode',
@ -86,6 +88,7 @@ class luks2:
# Get crypt-information about the device by doing a reverse lookup starting with the partition path
# For instance: /dev/sda
SysCommand(f'bash -c "partprobe"')
devinfo = json.loads(b''.join(SysCommand(f"lsblk --fs -J {partition.path}")).decode('UTF-8'))['blockdevices'][0]
# For each child (sub-partition/sub-device)