Some test targets in "Makefile.am", such as "run-virt-p2v-in-a-vm" and "run-virt-p2v-in-an-nvme-vm", use both the PHYSICAL_MACHINE disk (as the conversion subject) and "virt-p2v.img" (as boot media).
Unless the user overrides the PHYSICAL_MACHINE macro, we generate it with virt-builder, using a distro that we open-code (currently: Fedora 35). "virt-p2v.img" is also generated with virt-builder, but the distro installed in it follows the user's host OS (therefore we have less control over the distro choice in "virt-p2v.img"). The user's host OS may happen to match the OS we hardcode for PHYSICAL_MACHINE (currently: Fedora 35), in which case we end up using the same virt-builder template for both images. This is a problem: the filesystems between both images will have identical UUIDs, which may cause the kernel loaded from "virt-p2v.img" to mount the root filesystem from PHYSICAL_MACHINE. Prevent this by regenerating the filesystem UUIDs in PHYSICAL_MACHINE (whose distro we closely control, unless the user sets PHYSICAL_MACHINE themselves). Instead of the virt-sysprep operation "fs-uuids", which currently cannot update the filesystem UUID references in the guest's config files (<https://libguestfs.org/virt-sysprep.1.html#fs-uuids>, <https://bugzilla.redhat.com/show_bug.cgi?id=991641>), implement a somewhat crude guest-side shell command for the same purpose. Such a command would likely not be flexible / robust enough for "fs-uuids" in virt-sysprep, but -- due to our tight control over the PHYSICAL_MACHINE operating system in virt-p2v -- it should suffice for virt-p2v testing. Signed-off-by: Laszlo Ersek <ler...@redhat.com> --- make-physical-machine.sh | 82 +++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/make-physical-machine.sh b/make-physical-machine.sh index ff6db4940b51..946d59f0c30b 100755 --- a/make-physical-machine.sh +++ b/make-physical-machine.sh @@ -16,11 +16,16 @@ set -e -u -C +GUESTFISH_PID= disk= cleanup() { set +e + if test -n "$GUESTFISH_PID"; then + guestfish --remote -- exit >/dev/null 2>&1 + GUESTFISH_PID= + fi if test -n "$disk"; then rm -f -- "$disk" disk= @@ -32,6 +37,81 @@ trap cleanup EXIT output=$1 outdir=$(dirname -- "$output") disk=$(mktemp -p "$outdir" physical-machine.tmp.XXXXXXXXXX) -virt-builder --format raw -o "$disk" --root-password password:p2v-phys fedora-35 +# Delay the SELinux relabeling. +virt-builder --format raw -o "$disk" --root-password password:p2v-phys \ + --no-selinux-relabel fedora-35 + +# Start a guestfish server on the disk image, so that each of the several +# UUID-manipulation commands below not need a separate guestfish launch. +guestfish_set_pid=$(guestfish --listen --format=raw --add "$disk") +eval "$guestfish_set_pid" +guestfish --remote -- run + +# The array below open-codes the partition:filesystem layout of the virt-builder +# disk template used above. Whenever you bump the Fedora version, update the +# array below as needed. +# +# We cannot use inspection either before or after the filesystem UUID changes: +# +# - the UUID of a mounted filesystem cannot be changed (at least with XFS); +# +# - right after the UUID changes, inspection does not work correctly, as the new +# fs UUIDs are out of sync with the UUID references in those config files that +# inspection relies upon. +# +# Note that the order of entries is important too: the mount points must be +# listed in dependency order (put the dependees first, the dependants last). +fsdevs=(/dev/sda3:/ /dev/sda2:/boot) + +# For each filesystem: +# +# - regenerate the UUID, +# +# - produce a sed command (scriptlet) that performs the same UUID replacement in +# a text file, +# +# - mount the filesystem. +# +# Note that later we're going to rely on the fact that the generated sed +# commands *require no quoting* on the shell command line. +declare -a sed_script +sed_idx=0 +for fsdev in "${fsdevs[@]}"; do + device=${fsdev%:*} + mountpoint=${fsdev#*:} + + old_uuid=$(guestfish --remote -- get-uuid "$device") + guestfish --remote -- set-uuid-random "$device" + new_uuid=$(guestfish --remote -- get-uuid "$device") + + sed_script[sed_idx++]=-e + sed_script[sed_idx++]=s/$old_uuid/$new_uuid/ig + + guestfish --remote -- mount "$device" "$mountpoint" +done + +# Prepare the UUID replacement shell command for the appliance. +refresh_uuid_refs=(find /boot /etc -type f -print0 '|' + xargs -0 -r -- sed -i "${sed_script[@]}" --) + +# Passing the shell command to the appliance is where we rely on the fact that +# the sed commands for replacing UUIDs require no quoting. +guestfish --remote -- sh "${refresh_uuid_refs[*]}" + +# Tear down the guestfish server before we use virt-customize. +waitpid=$GUESTFISH_PID +guestfish --remote -- exit +GUESTFISH_PID= +while kill -s 0 -- "$waitpid" 2>/dev/null; do + sleep 1 +done + +# Reapply the SELinux labels now. Use virt-customize for this, rather than +# guestfish's "selinux-relabel", as virt-customize contains some heavy logic +# related to "specfile". Inspection does work here, because the config files are +# in sync again with the filesystem UUIDs. +virt-customize --format raw --add "$disk" --selinux-relabel + +# We're done; rename the temporary disk image to the expected output file. mv -- "$disk" "$output" disk= _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://listman.redhat.com/mailman/listinfo/libguestfs