Refactor: block-device partitioning cleanup
Now that the main partitioning refactor patch is merged, there is a small relict of handling partitions still in the disk-image-create main. This patch moves the functionality from disk-image-create to the block-device/partitioning module: it is mostly a rewrite of the original bash code in python. Change-Id: Ia73baeca74180a7bc9ea487da03ff56d6a3070ce Signed-off-by: Andreas Florath <andreas@florath.net>
This commit is contained in:
parent
f1776d72aa
commit
866a06f92d
@ -30,6 +30,47 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BlockDevice(object):
|
||||
"""Handles block devices.
|
||||
|
||||
This class handles the complete setup and deletion of all aspects
|
||||
of the block device level.
|
||||
|
||||
A typical call sequence:
|
||||
|
||||
cmd_create: creates all the different aspects of the block
|
||||
device. When this call is successful, the complete block level
|
||||
device is set up, filesystems are created and are mounted at
|
||||
the correct position.
|
||||
After this call it is possible to copy / install all the needed
|
||||
files into the appropriate directories.
|
||||
|
||||
cmd_umount: unmount and detaches all directories and used many
|
||||
resources. After this call the used (e.g.) images are still
|
||||
available for further handling, e.g. converting from raw in
|
||||
some other format.
|
||||
|
||||
cmd_cleanup: removes everything that was created with the
|
||||
'cmd_create' call, i.e. all images files themselves and
|
||||
internal temporary configuration.
|
||||
|
||||
cmd_delete: unmounts and removes everything that was created
|
||||
during the 'cmd_create' all. This call should be used in error
|
||||
conditions when there is the need to remove all allocated
|
||||
resources immediately and as good as possible.
|
||||
From the functional point of view this is mostly the same as a
|
||||
call to 'cmd_umount' and 'cmd_cleanup' - but is typically more
|
||||
error tolerance.
|
||||
|
||||
In a script this should be called in the following way:
|
||||
|
||||
dib-block-device --phase=create ...
|
||||
trap "dib-block-device --phase=delete ..." EXIT
|
||||
# copy / install files
|
||||
dib-block-device --phase=umount ...
|
||||
# convert image(s)
|
||||
dib-block-device --phase=cleanup ...
|
||||
trap - EXIT
|
||||
"""
|
||||
|
||||
# Default configuration:
|
||||
# one image, one partition, mounted under '/'
|
||||
|
@ -19,6 +19,8 @@ from diskimage_builder.block_device.utils import parse_abs_size_spec
|
||||
from diskimage_builder.block_device.utils import parse_rel_size_spec
|
||||
from diskimage_builder.graph.digraph import Digraph
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -148,6 +150,51 @@ class Partitioning(object):
|
||||
for _, part in self.partitions.items():
|
||||
dg.add_node(part)
|
||||
|
||||
def _exec_sudo(self, cmd):
|
||||
sudo_cmd = ["sudo"]
|
||||
sudo_cmd.extend(cmd)
|
||||
logger.info("Calling [%s]" % " ".join(sudo_cmd))
|
||||
subp = subprocess.Popen(sudo_cmd)
|
||||
rval = subp.wait()
|
||||
if rval != 0:
|
||||
logger.error("Calling [%s] failed with [%s]" %
|
||||
(" ".join(sudo_cmd), rval))
|
||||
logger.error("Trying to continue")
|
||||
|
||||
def _all_part_devices_exist(self, expected_part_devices):
|
||||
for part_device in expected_part_devices:
|
||||
logger.debug("Checking if partition device [%s] exists" %
|
||||
part_device)
|
||||
if not os.path.exists(part_device):
|
||||
logger.info("Partition device [%s] does not exists"
|
||||
% part_device)
|
||||
return False
|
||||
logger.debug("Partition already exists [%s]" % part_device)
|
||||
return True
|
||||
|
||||
def _notify_os_of_partition_changes(self, device_path, partition_devices):
|
||||
"""Notify of of partition table changes
|
||||
|
||||
There is the need to call some programs to inform the operating
|
||||
system of partition tables changes.
|
||||
These calls are highly distribution and version specific. Here
|
||||
a couple of different methods are used to get the best result.
|
||||
"""
|
||||
self._exec_sudo(["partprobe", device_path])
|
||||
self._exec_sudo(["udevadm", "settle"])
|
||||
|
||||
if self._all_part_devices_exist(partition_devices):
|
||||
return
|
||||
# If running inside Docker, make our nodes manually, because udev
|
||||
# will not be working.
|
||||
if os.path.exists("/.dockerenv"):
|
||||
# kpartx cannot run in sync mode in docker.
|
||||
self._exec_sudo(["kpartx", "-av", device_path])
|
||||
self._exec_sudo(["dmsetup", "--noudevsync", "mknodes"])
|
||||
return
|
||||
|
||||
self._exec_sudo(["kpartx", "-avs", device_path])
|
||||
|
||||
def create(self, result, rollback):
|
||||
image_path = result[self.base]['image']
|
||||
device_path = result[self.base]['device']
|
||||
@ -160,6 +207,7 @@ class Partitioning(object):
|
||||
|
||||
assert self.label == 'mbr'
|
||||
|
||||
partition_devices = set()
|
||||
disk_size = self._size_of_block_dev(image_path)
|
||||
with MBR(image_path, disk_size, self.align) as part_impl:
|
||||
for part_name, part_cfg in self.partitions.items():
|
||||
@ -178,7 +226,10 @@ class Partitioning(object):
|
||||
part_size, part_type)
|
||||
logger.debug("Create partition [%s] [%d]" %
|
||||
(part_name, part_no))
|
||||
result[part_name] = {'device': device_path + "p%d" % part_no}
|
||||
partition_device_name = device_path + "p%d" % part_no
|
||||
result[part_name] = {'device': partition_device_name}
|
||||
partition_devices.add(partition_device_name)
|
||||
|
||||
self.already_created = True
|
||||
self._notify_os_of_partition_changes(device_path, partition_devices)
|
||||
return
|
||||
|
@ -415,31 +415,6 @@ export EXTRA_DETACH="detach_loopback ${IMAGE_BLOCK_DEVICE_WITHOUT_PART}"
|
||||
export EXTRA_UNMOUNT="dib-block-device --phase=cleanup \
|
||||
--build-dir=\"${TMP_BUILD_DIR}\""
|
||||
|
||||
# Create the partitions and make them visible to the system
|
||||
|
||||
sudo partprobe $IMAGE_BLOCK_DEVICE_WITHOUT_PART
|
||||
|
||||
# To ensure no race conditions exist from calling partprobe
|
||||
sudo udevadm settle
|
||||
|
||||
# If the partition isn't under /dev/loop*p1, create it with kpartx
|
||||
DM=
|
||||
if [ ! -e "${IMAGE_BLOCK_DEVICE}" ]; then
|
||||
DM=${IMAGE_BLOCK_DEVICE/#\/dev/\/dev\/mapper}
|
||||
# If running inside Docker, make our nodes manually, because udev will not be working.
|
||||
if [ -f /.dockerenv ]; then
|
||||
# kpartx cannot run in sync mode in docker.
|
||||
sudo kpartx -av ${IMAGE_BLOCK_DEVICE_WITHOUT_PART}
|
||||
sudo dmsetup --noudevsync mknodes
|
||||
else
|
||||
sudo kpartx -asv ${IMAGE_BLOCK_DEVICE_WITHOUT_PART}
|
||||
fi
|
||||
elif [[ "$ARCH" =~ "ppc" ]]; then
|
||||
sudo kpartx -asv ${IMAGE_BLOCK_DEVICE_WITHOUT_PART}
|
||||
fi
|
||||
|
||||
# End: Creation of the partitions
|
||||
|
||||
sudo mkfs -t $FS_TYPE $MKFS_OPTS -L ${DIB_ROOT_LABEL} ${IMAGE_BLOCK_DEVICE}
|
||||
# Tuning the rootfs uuid works only for ext filesystems.
|
||||
if echo "$FS_TYPE" | grep -q "^ext"; then
|
||||
|
Loading…
Reference in New Issue
Block a user