7cd799462e
All the tests failed to run on the Fedora 37 host because the boot partition failed to be mounted and in turn the key kernel cmdline parameters like selinux=0 couldn't be added. The root problem is somehow running lsblk on the second partition returns an empty label unless we wait for enough time. Before figuring out the root cause, simply skip check that the second partition needs to have the boot label. Note the root problem can be produced by building a test image, cd tests ./scripts/build-image.sh Fedora-Cloud-Base-37-1.7.x86_64.qcow2 output_image scripts/build-scripts/base-image_test.sh Source image is qcow2, using snapshot... Formatting 'build/base-image1.building', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=5368709120 backing_file=Fedora-Cloud-Base-37-1.7.x86_64.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 It's a image with multiple partitions, using last partition as main partition grep: /boot/grub2/grubenv: No such file or directory grub2-editenv: error: cannot open `/boot/grub2/grubenv.new': No such file or directory. /dev/nbd0 disconnected Signed-off-by: Coiby Xu <coxu@redhat.com> Reviewed-by: Philipp Rudo <prudo@redhat.com>
276 lines
6.1 KiB
Bash
276 lines
6.1 KiB
Bash
#!/usr/bin/env bash
|
|
[ -z "$TESTDIR" ] && TESTDIR=$(realpath $(dirname "$0")/../)
|
|
|
|
SUDO="sudo"
|
|
|
|
declare -A MNTS=()
|
|
declare -A DEVS=()
|
|
|
|
perror() {
|
|
echo $@>&2
|
|
}
|
|
|
|
perror_exit() {
|
|
echo $@>&2
|
|
exit 1
|
|
}
|
|
|
|
is_mounted()
|
|
{
|
|
findmnt -k -n $1 &>/dev/null
|
|
}
|
|
|
|
clean_up()
|
|
{
|
|
for _mnt in ${MNTS[@]}; do
|
|
is_mounted $_mnt && $SUDO umount -f -R $_mnt
|
|
done
|
|
|
|
for _dev in ${DEVS[@]}; do
|
|
[ ! -e "$_dev" ] && continue
|
|
[[ "$_dev" == "/dev/loop"* ]] && $SUDO losetup -d "$_dev"
|
|
[[ "$_dev" == "/dev/nbd"* ]] && $SUDO qemu-nbd --disconnect "$_dev"
|
|
done
|
|
|
|
[ -d "$TMPDIR" ] && $SUDO rm --one-file-system -rf -- "$TMPDIR";
|
|
|
|
sync
|
|
}
|
|
|
|
trap '
|
|
ret=$?;
|
|
clean_up
|
|
exit $ret;
|
|
' EXIT
|
|
|
|
# clean up after ourselves no matter how we die.
|
|
trap 'exit 1;' SIGINT
|
|
|
|
readonly TMPDIR="$(mktemp -d -t kexec-kdump-test.XXXXXX)"
|
|
[ -d "$TMPDIR" ] || perror_exit "mktemp failed."
|
|
|
|
get_image_fmt() {
|
|
local image=$1 fmt
|
|
|
|
[ ! -e "$image" ] && perror "image: $image doesn't exist" && return 1
|
|
|
|
fmt=$(qemu-img info $image | sed -n "s/file format:\s*\(.*\)/\1/p")
|
|
|
|
[ $? -eq 0 ] && echo $fmt && return 0
|
|
|
|
return 1
|
|
}
|
|
|
|
fmt_is_qcow2() {
|
|
[ "$1" == "qcow2" ] || [ "$1" == "qcow2 backing qcow2" ]
|
|
}
|
|
|
|
# If it's partitioned, return the mountable partition, else return the dev
|
|
get_mountable_dev() {
|
|
local dev=$1 parts
|
|
|
|
$SUDO partprobe $dev && sync
|
|
parts="$(ls -1 ${dev}p*)"
|
|
if [ -n "$parts" ]; then
|
|
if [ $(echo "$parts" | wc -l) -gt 1 ]; then
|
|
perror "It's a image with multiple partitions, using last partition as main partition"
|
|
fi
|
|
echo "$parts" | tail -1
|
|
else
|
|
echo "$dev"
|
|
fi
|
|
}
|
|
|
|
# get the separate boot partition
|
|
# return the 2nd partition as boot partition
|
|
get_mount_boot() {
|
|
local dev=$1 _second_part=${dev}p2
|
|
|
|
# it's better to check if the 2nd partition has the boot label using lsblk
|
|
# but somehow this doesn't work starting with Fedora37
|
|
echo $_second_part
|
|
}
|
|
|
|
|
|
prepare_loop() {
|
|
[ -n "$(lsmod | grep "^loop")" ] && return
|
|
|
|
$SUDO modprobe loop
|
|
|
|
[ ! -e "/dev/loop-control" ] && perror_exit "failed to load loop driver"
|
|
}
|
|
|
|
prepare_nbd() {
|
|
[ -n "$(lsmod | grep "^nbd")" ] && return
|
|
|
|
$SUDO modprobe nbd max_part=4
|
|
|
|
[ ! -e "/dev/nbd0" ] && perror_exit "failed to load nbd driver"
|
|
}
|
|
|
|
mount_nbd() {
|
|
local image=$1 size dev
|
|
for _dev in /sys/class/block/nbd* ; do
|
|
size=$(cat $_dev/size)
|
|
if [ "$size" -eq 0 ] ; then
|
|
dev=/dev/${_dev##*/}
|
|
$SUDO qemu-nbd --connect=$dev $image 1>&2
|
|
[ $? -eq 0 ] && echo $dev && break
|
|
fi
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
image_lock()
|
|
{
|
|
local image=$1 timeout=5 fd
|
|
|
|
eval "exec {fd}>$image.lock"
|
|
if [ $? -ne 0 ]; then
|
|
perror_exit "failed acquiring image lock"
|
|
exit 1
|
|
fi
|
|
|
|
flock -n $fd
|
|
rc=$?
|
|
while [ $rc -ne 0 ]; do
|
|
echo "Another instance is holding the image lock ..."
|
|
flock -w $timeout $fd
|
|
rc=$?
|
|
done
|
|
}
|
|
|
|
# Mount a device, will umount it automatially when shell exits
|
|
mount_image() {
|
|
local image=$1 fmt
|
|
local dev mnt mnt_dev boot root
|
|
|
|
# Lock the image just in case user run this script in parrel
|
|
image_lock $image
|
|
|
|
fmt=$(get_image_fmt $image)
|
|
[ $? -ne 0 ] || [ -z "$fmt" ] && perror_exit "failed to detect image format"
|
|
|
|
if [ "$fmt" == "raw" ]; then
|
|
prepare_loop
|
|
|
|
dev="$($SUDO losetup --show -f $image)"
|
|
[ $? -ne 0 ] || [ -z "$dev" ] && perror_exit "failed to setup loop device"
|
|
|
|
elif fmt_is_qcow2 "$fmt"; then
|
|
prepare_nbd
|
|
|
|
dev=$(mount_nbd $image)
|
|
[ $? -ne 0 ] || [ -z "$dev" ] perror_exit "failed to connect qemu to nbd device '$dev'"
|
|
else
|
|
perror_exit "Unrecognized image format '$fmt'"
|
|
fi
|
|
DEVS[$image]="$dev"
|
|
|
|
mnt="$(mktemp -d -p $TMPDIR -t mount.XXXXXX)"
|
|
[ $? -ne 0 ] || [ -z "$mnt" ] && perror_exit "failed to create tmp mount dir"
|
|
MNTS[$image]="$mnt"
|
|
|
|
mnt_dev=$(get_mountable_dev "$dev")
|
|
[ $? -ne 0 ] || [ -z "$mnt_dev" ] && perror_exit "failed to setup loop device"
|
|
|
|
$SUDO mount $mnt_dev $mnt
|
|
[ $? -ne 0 ] && perror_exit "failed to mount device '$mnt_dev'"
|
|
boot=$(get_mount_boot "$dev")
|
|
if [[ -n "$boot" ]]; then
|
|
root=$(get_image_mount_root $image)
|
|
$SUDO mount $boot $root/boot
|
|
[ $? -ne 0 ] && perror_exit "failed to mount the bootable partition for device '$mnt_dev'"
|
|
fi
|
|
}
|
|
|
|
get_image_mount_root() {
|
|
local image=$1
|
|
local root=${MNTS[$image]}
|
|
|
|
# Starting from Fedora 36, the root node is /root/root of the last partition
|
|
[ -d "$root/root/root" ] && root=$root/root
|
|
echo $root
|
|
|
|
if [ -z "$root" ]; then
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
shell_in_image() {
|
|
local root=$(get_image_mount_root $1) && shift
|
|
|
|
pushd $root
|
|
|
|
$SHELL
|
|
|
|
popd
|
|
}
|
|
|
|
inst_pkg_in_image() {
|
|
local root=$(get_image_mount_root $1) && shift
|
|
|
|
# LSB not available
|
|
# release_info=$($SUDO chroot $root /bin/bash -c "lsb_release -a")
|
|
# release=$(echo "$release_info" | sed -n "s/Release:\s*\(.*\)/\1/p")
|
|
# distro=$(echo "$release_info" | sed -n "s/Distributor ID:\s*\(.*\)/\1/p")
|
|
# if [ "$distro" != "Fedora" ]; then
|
|
# perror_exit "only Fedora image is supported"
|
|
# fi
|
|
release=$(cat $root/etc/fedora-release | sed -n "s/.*[Rr]elease\s*\([0-9]*\).*/\1/p")
|
|
[ $? -ne 0 ] || [ -z "$release" ] && perror_exit "only Fedora image is supported"
|
|
|
|
$SUDO dnf --releasever=$release --installroot=$root install -y $@
|
|
}
|
|
|
|
run_in_image() {
|
|
local root=$(get_image_mount_root $1) && shift
|
|
|
|
$SUDO chroot $root /bin/bash -c "$@"
|
|
}
|
|
|
|
inst_in_image() {
|
|
local image=$1 src=$2 dst=$3
|
|
local root=$(get_image_mount_root $1)
|
|
|
|
$SUDO cp $src $root/$dst
|
|
}
|
|
|
|
# If source image is qcow2, create a snapshot
|
|
# If source image is raw, convert to raw
|
|
# If source image is xz, decompress then repeat the above logic
|
|
#
|
|
# Won't touch source image
|
|
create_image_from_base_image() {
|
|
local image=$1
|
|
local output=$2
|
|
local decompressed_image
|
|
|
|
local ext="${image##*.}"
|
|
if [[ "$ext" == 'xz' ]]; then
|
|
echo "Decompressing base image..."
|
|
xz -d -k $image
|
|
decompressed_image=${image%.xz}
|
|
image=$decompressed_image
|
|
fi
|
|
|
|
local image_fmt=$(get_image_fmt $image)
|
|
if [ "$image_fmt" != "raw" ]; then
|
|
if fmt_is_qcow2 "$image_fmt"; then
|
|
echo "Source image is qcow2, using snapshot..."
|
|
qemu-img create -f qcow2 -b $image -F qcow2 $output
|
|
else
|
|
perror_exit "Unrecognized base image format '$image_mnt'"
|
|
fi
|
|
else
|
|
echo "Source image is raw, converting to qcow2..."
|
|
qemu-img convert -f raw -O qcow2 $image $output
|
|
fi
|
|
|
|
# Clean up decompress temp image
|
|
if [ -n "$decompressed_image" ]; then
|
|
rm $decompressed_image
|
|
fi
|
|
}
|