|
Petr Šabata |
f5bf49 |
#!/usr/bin/env bash
|
|
Petr Šabata |
f5bf49 |
[ -z "$TESTDIR" ] && TESTDIR=$(realpath $(dirname "$0")/../)
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
SUDO="sudo"
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
declare -A MNTS=()
|
|
Petr Šabata |
f5bf49 |
declare -A DEVS=()
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
perror() {
|
|
Petr Šabata |
f5bf49 |
echo $@>&2
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
perror_exit() {
|
|
Petr Šabata |
f5bf49 |
echo $@>&2
|
|
Petr Šabata |
f5bf49 |
exit 1
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
is_mounted()
|
|
Petr Šabata |
f5bf49 |
{
|
|
Petr Šabata |
f5bf49 |
findmnt -k -n $1 &>/dev/null
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
clean_up()
|
|
Petr Šabata |
f5bf49 |
{
|
|
Petr Šabata |
f5bf49 |
for _mnt in ${MNTS[@]}; do
|
|
Petr Šabata |
f5bf49 |
is_mounted $_mnt && $SUDO umount -f $_mnt
|
|
Petr Šabata |
f5bf49 |
done
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
for _dev in ${DEVS[@]}; do
|
|
Petr Šabata |
f5bf49 |
[ ! -e "$_dev" ] && continue
|
|
Petr Šabata |
f5bf49 |
[[ "$_dev" == "/dev/loop"* ]] && $SUDO losetup -d "$_dev"
|
|
Petr Šabata |
f5bf49 |
[[ "$_dev" == "/dev/nbd"* ]] && $SUDO qemu-nbd --disconnect "$_dev"
|
|
Petr Šabata |
f5bf49 |
done
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
[ -d "$TMPDIR" ] && $SUDO rm --one-file-system -rf -- "$TMPDIR";
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
sync
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
trap '
|
|
Petr Šabata |
f5bf49 |
ret=$?;
|
|
Petr Šabata |
f5bf49 |
clean_up
|
|
Petr Šabata |
f5bf49 |
exit $ret;
|
|
Petr Šabata |
f5bf49 |
' EXIT
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
# clean up after ourselves no matter how we die.
|
|
Petr Šabata |
f5bf49 |
trap 'exit 1;' SIGINT
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
readonly TMPDIR="$(mktemp -d -t kexec-kdump-test.XXXXXX)"
|
|
Petr Šabata |
f5bf49 |
[ -d "$TMPDIR" ] || perror_exit "mktemp failed."
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
get_image_fmt() {
|
|
Petr Šabata |
f5bf49 |
local image=$1 fmt
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
[ ! -e "$image" ] && perror "image: $image doesn't exist" && return 1
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
fmt=$(qemu-img info $image | sed -n "s/file format:\s*\(.*\)/\1/p")
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
[ $? -eq 0 ] && echo $fmt && return 0
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
return 1
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
DistroBaker |
17a515 |
fmt_is_qcow2() {
|
|
DistroBaker |
17a515 |
[ "$1" == "qcow2" ] || [ "$1" == "qcow2 backing qcow2" ]
|
|
DistroBaker |
17a515 |
}
|
|
DistroBaker |
17a515 |
|
|
Petr Šabata |
f5bf49 |
# If it's partitioned, return the mountable partition, else return the dev
|
|
Petr Šabata |
f5bf49 |
get_mountable_dev() {
|
|
Petr Šabata |
f5bf49 |
local dev=$1 parts
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
$SUDO partprobe $dev && sync
|
|
Petr Šabata |
f5bf49 |
parts="$(ls -1 ${dev}p*)"
|
|
Petr Šabata |
f5bf49 |
if [ -n "$parts" ]; then
|
|
Petr Šabata |
f5bf49 |
if [ $(echo "$parts" | wc -l) -gt 1 ]; then
|
|
Petr Šabata |
f5bf49 |
perror "It's a image with multiple partitions, using last partition as main partition"
|
|
Petr Šabata |
f5bf49 |
fi
|
|
Petr Šabata |
f5bf49 |
echo "$parts" | tail -1
|
|
Petr Šabata |
f5bf49 |
else
|
|
Petr Šabata |
f5bf49 |
echo "$dev"
|
|
Petr Šabata |
f5bf49 |
fi
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
prepare_loop() {
|
|
Petr Šabata |
f5bf49 |
[ -n "$(lsmod | grep "^loop")" ] && return
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
$SUDO modprobe loop
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
[ ! -e "/dev/loop-control" ] && perror_exit "failed to load loop driver"
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
prepare_nbd() {
|
|
Petr Šabata |
f5bf49 |
[ -n "$(lsmod | grep "^nbd")" ] && return
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
$SUDO modprobe nbd max_part=4
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
[ ! -e "/dev/nbd0" ] && perror_exit "failed to load nbd driver"
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
mount_nbd() {
|
|
Petr Šabata |
f5bf49 |
local image=$1 size dev
|
|
Petr Šabata |
f5bf49 |
for _dev in /sys/class/block/nbd* ; do
|
|
Petr Šabata |
f5bf49 |
size=$(cat $_dev/size)
|
|
Petr Šabata |
f5bf49 |
if [ "$size" -eq 0 ] ; then
|
|
Petr Šabata |
f5bf49 |
dev=/dev/${_dev##*/}
|
|
Petr Šabata |
f5bf49 |
$SUDO qemu-nbd --connect=$dev $image 1>&2
|
|
Petr Šabata |
f5bf49 |
[ $? -eq 0 ] && echo $dev && break
|
|
Petr Šabata |
f5bf49 |
fi
|
|
Petr Šabata |
f5bf49 |
done
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
return 1
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
image_lock()
|
|
Petr Šabata |
f5bf49 |
{
|
|
Petr Šabata |
f5bf49 |
local image=$1 timeout=5 fd
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
eval "exec {fd}>$image.lock"
|
|
Petr Šabata |
f5bf49 |
if [ $? -ne 0 ]; then
|
|
Petr Šabata |
f5bf49 |
perror_exit "failed acquiring image lock"
|
|
Petr Šabata |
f5bf49 |
exit 1
|
|
Petr Šabata |
f5bf49 |
fi
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
flock -n $fd
|
|
Petr Šabata |
f5bf49 |
rc=$?
|
|
Petr Šabata |
f5bf49 |
while [ $rc -ne 0 ]; do
|
|
Petr Šabata |
f5bf49 |
echo "Another instance is holding the image lock ..."
|
|
Petr Šabata |
f5bf49 |
flock -w $timeout $fd
|
|
Petr Šabata |
f5bf49 |
rc=$?
|
|
Petr Šabata |
f5bf49 |
done
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
# Mount a device, will umount it automatially when shell exits
|
|
Petr Šabata |
f5bf49 |
mount_image() {
|
|
Petr Šabata |
f5bf49 |
local image=$1 fmt
|
|
Petr Šabata |
f5bf49 |
local dev mnt mnt_dev
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
# Lock the image just in case user run this script in parrel
|
|
Petr Šabata |
f5bf49 |
image_lock $image
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
fmt=$(get_image_fmt $image)
|
|
Petr Šabata |
f5bf49 |
[ $? -ne 0 ] || [ -z "$fmt" ] && perror_exit "failed to detect image format"
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
if [ "$fmt" == "raw" ]; then
|
|
Petr Šabata |
f5bf49 |
prepare_loop
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
dev="$($SUDO losetup --show -f $image)"
|
|
Petr Šabata |
f5bf49 |
[ $? -ne 0 ] || [ -z "$dev" ] && perror_exit "failed to setup loop device"
|
|
Petr Šabata |
f5bf49 |
|
|
DistroBaker |
17a515 |
elif fmt_is_qcow2 "$fmt"; then
|
|
Petr Šabata |
f5bf49 |
prepare_nbd
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
dev=$(mount_nbd $image)
|
|
Petr Šabata |
f5bf49 |
[ $? -ne 0 ] || [ -z "$dev" ] perror_exit "failed to connect qemu to nbd device '$dev'"
|
|
Petr Šabata |
f5bf49 |
else
|
|
Petr Šabata |
f5bf49 |
perror_exit "Unrecognized image format '$fmt'"
|
|
Petr Šabata |
f5bf49 |
fi
|
|
Petr Šabata |
f5bf49 |
DEVS[$image]="$dev"
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
mnt="$(mktemp -d -p $TMPDIR -t mount.XXXXXX)"
|
|
Petr Šabata |
f5bf49 |
[ $? -ne 0 ] || [ -z "$mnt" ] && perror_exit "failed to create tmp mount dir"
|
|
Petr Šabata |
f5bf49 |
MNTS[$image]="$mnt"
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
mnt_dev=$(get_mountable_dev "$dev")
|
|
Petr Šabata |
f5bf49 |
[ $? -ne 0 ] || [ -z "$mnt_dev" ] && perror_exit "failed to setup loop device"
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
$SUDO mount $mnt_dev $mnt
|
|
Petr Šabata |
f5bf49 |
[ $? -ne 0 ] && perror_exit "failed to mount device '$mnt_dev'"
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
get_image_mount_root() {
|
|
Petr Šabata |
f5bf49 |
local image=$1
|
|
Petr Šabata |
f5bf49 |
local root=${MNTS[$image]}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
echo $root
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
if [ -z "$root" ]; then
|
|
Petr Šabata |
f5bf49 |
return 1
|
|
Petr Šabata |
f5bf49 |
fi
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
shell_in_image() {
|
|
Petr Šabata |
f5bf49 |
local root=$(get_image_mount_root $1) && shift
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
pushd $root
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
$SHELL
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
popd
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
inst_pkg_in_image() {
|
|
Petr Šabata |
f5bf49 |
local root=$(get_image_mount_root $1) && shift
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
# LSB not available
|
|
Petr Šabata |
f5bf49 |
# release_info=$($SUDO chroot $root /bin/bash -c "lsb_release -a")
|
|
Petr Šabata |
f5bf49 |
# release=$(echo "$release_info" | sed -n "s/Release:\s*\(.*\)/\1/p")
|
|
Petr Šabata |
f5bf49 |
# distro=$(echo "$release_info" | sed -n "s/Distributor ID:\s*\(.*\)/\1/p")
|
|
Petr Šabata |
f5bf49 |
# if [ "$distro" != "Fedora" ]; then
|
|
Petr Šabata |
f5bf49 |
# perror_exit "only Fedora image is supported"
|
|
Petr Šabata |
f5bf49 |
# fi
|
|
Petr Šabata |
f5bf49 |
release=$(cat $root/etc/fedora-release | sed -n "s/.*[Rr]elease\s*\([0-9]*\).*/\1/p")
|
|
Petr Šabata |
f5bf49 |
[ $? -ne 0 ] || [ -z "$release" ] && perror_exit "only Fedora image is supported"
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
$SUDO dnf --releasever=$release --installroot=$root install -y $@
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
run_in_image() {
|
|
Petr Šabata |
f5bf49 |
local root=$(get_image_mount_root $1) && shift
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
$SUDO chroot $root /bin/bash -c "$@"
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
inst_in_image() {
|
|
Petr Šabata |
f5bf49 |
local image=$1 src=$2 dst=$3
|
|
Petr Šabata |
f5bf49 |
local root=${MNTS[$image]}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
$SUDO cp $src $root/$dst
|
|
Petr Šabata |
f5bf49 |
}
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
# If source image is qcow2, create a snapshot
|
|
Petr Šabata |
f5bf49 |
# If source image is raw, convert to raw
|
|
Petr Šabata |
f5bf49 |
# If source image is xz, decompress then repeat the above logic
|
|
Petr Šabata |
f5bf49 |
#
|
|
Petr Šabata |
f5bf49 |
# Won't touch source image
|
|
Petr Šabata |
f5bf49 |
create_image_from_base_image() {
|
|
Petr Šabata |
f5bf49 |
local image=$1
|
|
Petr Šabata |
f5bf49 |
local output=$2
|
|
Petr Šabata |
f5bf49 |
local decompressed_image
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
local ext="${image##*.}"
|
|
Petr Šabata |
f5bf49 |
if [[ "$ext" == 'xz' ]]; then
|
|
Petr Šabata |
f5bf49 |
echo "Decompressing base image..."
|
|
Petr Šabata |
f5bf49 |
xz -d -k $image
|
|
Petr Šabata |
f5bf49 |
decompressed_image=${image%.xz}
|
|
Petr Šabata |
f5bf49 |
image=$decompressed_image
|
|
Petr Šabata |
f5bf49 |
fi
|
|
Petr Šabata |
f5bf49 |
|
|
DistroBaker |
17a515 |
local image_fmt=$(get_image_fmt $image)
|
|
Petr Šabata |
f5bf49 |
if [ "$image_fmt" != "raw" ]; then
|
|
DistroBaker |
17a515 |
if fmt_is_qcow2 "$image_fmt"; then
|
|
Petr Šabata |
f5bf49 |
echo "Source image is qcow2, using snapshot..."
|
|
Petr Šabata |
f5bf49 |
qemu-img create -f qcow2 -b $image $output
|
|
Petr Šabata |
f5bf49 |
else
|
|
DistroBaker |
17a515 |
perror_exit "Unrecognized base image format '$image_mnt'"
|
|
Petr Šabata |
f5bf49 |
fi
|
|
Petr Šabata |
f5bf49 |
else
|
|
Petr Šabata |
f5bf49 |
echo "Source image is raw, converting to qcow2..."
|
|
Petr Šabata |
f5bf49 |
qemu-img convert -f raw -O qcow2 $image $output
|
|
Petr Šabata |
f5bf49 |
fi
|
|
Petr Šabata |
f5bf49 |
|
|
Petr Šabata |
f5bf49 |
# Clean up decompress temp image
|
|
Petr Šabata |
f5bf49 |
if [ -n "$decompressed_image" ]; then
|
|
Petr Šabata |
f5bf49 |
rm $decompressed_image
|
|
Petr Šabata |
f5bf49 |
fi
|
|
Petr Šabata |
f5bf49 |
}
|