Encapsulate test environments within subdirectories

It is sometimes helpful to have multiple active test setups, and it is
also convenient to be able to destroy a test setup with one command
rather than having to delete multiple different files and directories.

This command adds a `-D` argument to setup.sh, allowing all activity in
the setup script to occur within a specified directory. When a
subdirectory is not specified, a default of `test.$(uname -r)` is used.

The run.sh script is also now aware of the test directory, searching for
a default of `test.$(uname -r)` and allowing manual specification by
setting the TESTDIR environment variable. If the TESTDIR does not exist,
run.sh reverts to running from the CWD.

Also, the image-creation script has been pulled out of a heredoc in
setup.sh into a standalone script, making maintenance a little easier.
This commit is contained in:
Andrew J. Hesford 2020-11-16 12:19:15 -05:00
parent 65a1a337d8
commit 095c328d42
6 changed files with 250 additions and 169 deletions

1
testing/.gitignore vendored
View File

@ -7,3 +7,4 @@ local.yaml
.config .config
dracut dracut
dracut.conf.d dracut.conf.d
generate-zbm

View File

@ -10,11 +10,13 @@ The testing environment setup and runtime depends on the following tools:
# Creating a ZFSBootMenu Test Pool for QEMU # Creating a ZFSBootMenu Test Pool for QEMU
First, run `./setup.sh -a` to: First, run `./setup.sh -a`; this will create, if necessary, a test directory
(chosen automatically or specified with the `-D` command-line flag) and, within
the test directory:
* Create a test pool * Create a test pool
1. Create a 1GB RAW image file, 1. Create a 2GB RAW image file,
2. Attach it to the `loop0` loopback device, 2. Attach it to a loopback device,
3. Create a GPT label and a ZFS pool `ztest`, 3. Create a GPT label and a ZFS pool `ztest`,
4. Install Void base-minimal onto the pool, 4. Install Void base-minimal onto the pool,
5. Configure the installation, and 5. Configure the installation, and

View File

@ -9,7 +9,7 @@ xbps-reconfigure -f glibc-locales
# Install a kernel and ZFS # Install a kernel and ZFS
xbps-install -S xbps-install -S
xbps-install -y linux5.8 linux5.8-headers zfs xbps-install -y linux5.9 linux5.9-headers zfs
# Setup ZFS in Dracut # Setup ZFS in Dracut
cat << EOF > /etc/dracut.conf.d/zol.conf cat << EOF > /etc/dracut.conf.d/zol.conf
@ -18,7 +18,7 @@ add_dracutmodules+=" zfs "
omit_dracutmodules+=" btrfs " omit_dracutmodules+=" btrfs "
EOF EOF
xbps-reconfigure -f linux5.8 xbps-reconfigure -f linux5.9
# Set kernel commandline # Set kernel commandline
case "$(uname -m)" in case "$(uname -m)" in

105
testing/image.sh Executable file
View File

@ -0,0 +1,105 @@
#!/bin/bash
# vim: softtabstop=2 shiftwidth=2 expandtab
TESTDIR="${1?Usage: $0 <testdir>}"
if [ -z "${TESTDIR}" ] || [ ! -d "${TESTDIR}" ]; then
echo "ERROR: test directory must be specified and must exist"
exit 1
fi
XBPS_ARCH="$(uname -m)"
case "${XBPS_ARCH}" in
ppc64le)
URL="https://mirrors.servercentral.com/void-ppc/current"
;;
x86_64)
URL="https://mirrors.servercentral.com/voidlinux/current"
;;
*)
echo "ERROR: unsupported architecture"
exit 1
;;
esac
if [ -n "${MUSL}" ]; then
URL="${URL}/musl"
XBPS_ARCH="${XBPS_ARCH}-musl"
fi
export XBPS_ARCH
MNT="$( mktemp -d )" || exit 1
# shellcheck disable=SC2064
trap "rmdir '${MNT}'" EXIT
qemu-img create "${TESTDIR}/zfsbootmenu-pool.img" 2G
chown "$( stat -c %U . ):$( stat -c %G . )" "${TESTDIR}/zfsbootmenu-pool.img"
LOOP="$( losetup -f )" || exit 1
losetup "${LOOP}" "${TESTDIR}/zfsbootmenu-pool.img" || exit 1
# shellcheck disable=SC2064
trap "rmdir '${MNT}'; losetup -d '${LOOP}'" EXIT
kpartx -u "${LOOP}"
echo 'label: gpt' | sfdisk "${LOOP}"
zpool create -f \
-O compression=lz4 \
-O acltype=posixacl \
-O xattr=sa \
-O relatime=on \
-o autotrim=on \
-o cachefile=none \
-m none ztest "${LOOP}"
zfs snapshot -r ztest@barepool
zfs create -o mountpoint=none ztest/ROOT
zfs create -o mountpoint=/ -o canmount=noauto ztest/ROOT/void
zfs snapshot -r ztest@barebe
zfs set org.zfsbootmenu:commandline="spl_hostid=$( hostid ) ro quiet" ztest/ROOT
zpool set bootfs=ztest/ROOT/void ztest
zpool export ztest
zpool import -o cachefile=none -R "${MNT}" ztest || exit 1
# shellcheck disable=SC2064
trap "zpool export ztest; rmdir '${MNT}'; losetup -d '${LOOP}'" EXIT
zfs mount ztest/ROOT/void || exit 1
# shellcheck disable=SC2064
trap "umount -R '${MNT}'; zpool export ztest; rmdir '${MNT}'; losetup -d '${LOOP}'" EXIT
# https://github.com/project-trident/trident-installer/blob/master/src-sh/void-install-zfs.sh#L541
mkdir -p "${MNT}/var/db/xbps/keys"
cp /var/db/xbps/keys/*.plist "${MNT}/var/db/xbps/keys/."
mkdir -p "${MNT}/etc/xbps.d"
cp /etc/xbps.d/*.conf "${MNT}/etc/xbps.d/."
# /etc/runit/core-services/03-console-setup.sh depends on loadkeys from kbd
# /etc/runit/core-services/05-misc.sh depends on ip from iproute2
xbps-install -y -M -r "${MNT}" --repository="${URL}" \
base-minimal dracut ncurses-base kbd iproute2 dhclient openssh
cp /etc/hostid "${MNT}/etc/"
cp /etc/resolv.conf "${MNT}/etc/"
cp /etc/rc.conf "${MNT}/etc/"
mkdir -p "${MNT}/etc/xbps.d"
echo "repository=${URL}" > "${MNT}/etc/xbps.d/00-repository-main.conf"
mount -t proc proc "${MNT}/proc"
mount -t sysfs sys "${MNT}/sys"
mount -B /dev "${MNT}/dev"
mount -t devpts pts "${MNT}/dev/pts"
zfs snapshot -r ztest@pre-chroot
cp chroot.sh "${MNT}/root"
chroot "${MNT}" /root/chroot.sh

View File

@ -1,4 +1,5 @@
#!/bin/bash #!/bin/bash
# vim: softtabstop=2 shiftwidth=2 expandtab
usage() { usage() {
cat <<EOF cat <<EOF
@ -9,58 +10,17 @@ Usage: $0 [options]
-n Do not recreate the initramfs -n Do not recreate the initramfs
-s Enable serial console on stdio -s Enable serial console on stdio
-v Set type of qemu display to use -v Set type of qemu display to use
-D Set test directory
EOF EOF
} }
# Support x86_64 and ppc64(le) CMDOPTS="D:A:a:d:nsv:h"
case "$(uname -m)" in
ppc64*)
BIN="qemu-system-ppc64"
KERNEL="vmlinux-bootmenu"
MACHINE="pseries,accel=kvm,kvm-type=HV,cap-hpt-max-page-size=4096"
APPEND="loglevel=7 timeout=5 root=zfsbootmenu:POOL=ztest"
SERDEV="hvc0"
;;
x86_64)
BIN="qemu-system-x86_64"
KERNEL="vmlinuz-bootmenu"
MACHINE="type=q35,accel=kvm"
APPEND="loglevel=7 timeout=5 root=zfsbootmenu:POOL=ztest"
SERDEV="ttyS0"
;;
esac
DRIVE="-drive format=raw,file=zfsbootmenu-pool.img" # First-pass option parsing just looks for test directory
INITRD="initramfs-bootmenu.img" while getopts "${CMDOPTS}" opt; do
MEMORY="2048M"
SMP="2"
CREATE=1
SERIAL=0
DISPLAY_TYPE=
# Override any default variables
#shellcheck disable=SC1091
[ -f .config ] && source .config
while getopts "A:a:d:nsv:h" opt; do
case "${opt}" in case "${opt}" in
A) D)
AAPPEND+=( "$OPTARG" ) TESTDIR="${OPTARG}"
;;
a)
APPEND="${OPTARG}"
;;
d)
MDRIVE+=("-drive" "format=raw,file=${OPTARG}")
;;
n)
CREATE=0
;;
s)
SERIAL=1
;;
v)
DISPLAY_TYPE="${OPTARG}"
;; ;;
\?|h) \?|h)
usage usage
@ -71,10 +31,79 @@ while getopts "A:a:d:nsv:h" opt; do
esac esac
done done
if [ "${#MDRIVE[@]}" -gt 0 ]; then if [ -n "${TESTDIR}" ]; then
DRIVE="${MDRIVE[*]}" # If a test directory was specified, it must exist
if [ ! -d "${TESTDIR}" ]; then
echo "ERROR: test directory '${TESTDIR}' does not exist"
exit 1
fi
else
# If a test directory was not specified, try a default
TESTDIR="./test.$(uname -m)"
[ -d "${TESTDIR}" ] || TESTDIR="."
fi fi
# Support x86_64 and ppc64(le)
case "$(uname -m)" in
ppc64*)
BIN="qemu-system-ppc64"
KERNEL="${TESTDIR}/vmlinux-bootmenu"
MACHINE="pseries,accel=kvm,kvm-type=HV,cap-hpt-max-page-size=4096"
APPEND="loglevel=7 timeout=5 root=zfsbootmenu:POOL=ztest"
SERDEV="hvc0"
;;
x86_64)
BIN="qemu-system-x86_64"
KERNEL="${TESTDIR}/vmlinuz-bootmenu"
MACHINE="type=q35,accel=kvm"
APPEND="loglevel=7 timeout=5 root=zfsbootmenu:POOL=ztest"
SERDEV="ttyS0"
;;
esac
DRIVE=("-drive" "format=raw,file=${TESTDIR}/zfsbootmenu-pool.img")
INITRD="${TESTDIR}/initramfs-bootmenu.img"
MEMORY="2048M"
SMP="2"
CREATE=1
SERIAL=0
DISPLAY_TYPE=
# Override any default variables
#shellcheck disable=SC1091
[ -f .config ] && source .config
# Second-pass option parsing grabs all other options
OPTIND=1
while getopts "${CMDOPTS}" opt; do
case "${opt}" in
A)
AAPPEND+=( "$OPTARG" )
;;
a)
APPEND="${OPTARG}"
;;
d)
if ! _dimg="$(realpath -e "${TESTDIR}/${OPTARG}")"; then
echo "ERROR: disk image '${TESTDIR}/${OPTARG}' does not exist"
exit 1
fi
DRIVE+=("-drive" "format=raw,file=${_dimg}")
;;
n)
CREATE=0
;;
s)
SERIAL=1
;;
v)
DISPLAY_TYPE="${OPTARG}"
;;
*)
;;
esac
done
if [ -n "${DISPLAY_TYPE}" ]; then if [ -n "${DISPLAY_TYPE}" ]; then
# Use the indicated graphical display # Use the indicated graphical display
DISPLAY_ARGS=( "-display" "${DISPLAY_TYPE}" ) DISPLAY_ARGS=( "-display" "${DISPLAY_TYPE}" )
@ -103,24 +132,27 @@ if ((CREATE)) ; then
[ -f "${KERNEL}" ] && rm "${KERNEL}" [ -f "${KERNEL}" ] && rm "${KERNEL}"
[ -f "${INITRD}" ] && rm "${INITRD}" [ -f "${INITRD}" ] && rm "${INITRD}"
# Try to find the local dracut first # Try to find the local dracut and generate-zbm first
PATH=./dracut:${PATH} ../bin/generate-zbm -c ./local.yaml if ! ( cd "${TESTDIR}" && PATH=./dracut:${PATH} ./generate-zbm -c ./local.yaml ); then
echo "ERROR: unable to create ZFSBootMenu images"
exit 1
fi
fi fi
# Ensure kernel and initramfs exist # Ensure kernel and initramfs exist
if [ ! -f "${KERNEL}" ] ; then if [ ! -f "${KERNEL}" ] ; then
echo "Missing kernel: ${KERNEL}" echo "Missing kernel: ${KERNEL}"
exit exit 1
elif [ ! -f "${INITRD}" ] ; then elif [ ! -f "${INITRD}" ] ; then
echo "Missing initramfs: ${INITRD}" echo "Missing initramfs: ${INITRD}"
exit exit 1
fi fi
# shellcheck disable=SC2086 # shellcheck disable=SC2086
"${BIN}" \ "${BIN}" \
-kernel "${KERNEL}" \ -kernel "${KERNEL}" \
-initrd "${INITRD}" \ -initrd "${INITRD}" \
${DRIVE} \ "${DRIVE[@]}" \
-m "${MEMORY}" \ -m "${MEMORY}" \
-smp "${SMP}" \ -smp "${SMP}" \
-cpu host \ -cpu host \
@ -130,8 +162,8 @@ fi
"${DISPLAY_ARGS[@]}" \ "${DISPLAY_ARGS[@]}" \
-serial mon:stdio \ -serial mon:stdio \
-netdev user,id=n1,hostfwd=tcp::2222-:22 -device virtio-net-pci,netdev=n1 \ -netdev user,id=n1,hostfwd=tcp::2222-:22 -device virtio-net-pci,netdev=n1 \
-append "${APPEND}" -append "${APPEND}" || exit 1
if ((SERIAL)) ; then if ((SERIAL)); then
reset reset
fi fi

View File

@ -1,5 +1,8 @@
#!/bin/bash #!/bin/bash
# vim: softtabstop=2 shiftwidth=2 expandtab
YAML=0 YAML=0
GENZBM=0
IMAGE=0 IMAGE=0
CONFD=0 CONFD=0
DRACUT=0 DRACUT=0
@ -8,11 +11,13 @@ usage() {
cat <<EOF cat <<EOF
Usage: $0 [options] Usage: $0 [options]
-y Create local.yaml -y Create local.yaml
-g Create a generate-zbm symlink
-c Create dracut.conf.d -c Create dracut.conf.d
-d Create a local dracut tree for local mode -d Create a local dracut tree for local mode
-i Create a test VM image -i Create a test VM image
-a Perform all setup options -a Perform all setup options
-m When making an image, use musl instead of glibc -m When making an image, use musl instead of glibc
-D Specify a test directory to use
EOF EOF
} }
@ -21,7 +26,7 @@ if [ $# -eq 0 ]; then
exit exit
fi fi
while getopts "ycdaim" opt; do while getopts "ycgdaimD:" opt; do
case "${opt}" in case "${opt}" in
y) y)
YAML=1 YAML=1
@ -35,24 +40,44 @@ while getopts "ycdaim" opt; do
d) d)
DRACUT=1 DRACUT=1
;; ;;
g)
GENZBM=1
;;
a) a)
YAML=1 YAML=1
CONFD=1 CONFD=1
IMAGE=1 IMAGE=1
DRACUT=1 DRACUT=1
GENZBM=1
;; ;;
m) m)
MUSL=1 MUSL=1
;; ;;
D)
TESTDIR="${OPTARG}"
;;
\?) \?)
usage usage
exit exit
esac esac
done done
if ((CONFD)) ; then # Assign a default dest directory if one was not provided
if [ -z "${TESTDIR}" ]; then
TESTDIR="./test.$(uname -m)"
if ((MUSL)); then
TESTDIR="${TESTDIR}-musl"
fi
fi
TESTDIR="$(realpath "${TESTDIR}")" || exit 1
# Make sure the test directory exists
mkdir -p "${TESTDIR}" || exit 1
if ((CONFD)) && [ ! -d "${TESTDIR}/dracut.conf.d" ]; then
echo "Creating dracut.conf.d" echo "Creating dracut.conf.d"
test -d "dracut.conf.d" || cp -Rp ../etc/zfsbootmenu/dracut.conf.d . cp -Rp ../etc/zfsbootmenu/dracut.conf.d "${TESTDIR}"
fi fi
if ((DRACUT)) ; then if ((DRACUT)) ; then
@ -67,122 +92,38 @@ if ((DRACUT)) ; then
exit 1 exit 1
fi fi
if [ ! -d dracut ]; then if [ ! -d "${TESTDIR}/dracut" ]; then
echo "Creating local dracut tree" echo "Creating local dracut tree"
cp -a /usr/lib/dracut . cp -a /usr/lib/dracut "${TESTDIR}"
cp "${DRACUTBIN}" ./dracut cp "${DRACUTBIN}" "${TESTDIR}/dracut"
fi fi
# Make sure the zfsbootmenu module is a link to the repo version # Make sure the zfsbootmenu module is a link to the repo version
test -d dracut/modules.d/90zfsbootmenu && rm -rf dracut/modules.d/90zfsbootmenu _dracut_mods="${TESTDIR}/dracut/modules.d"
test -L dracut/modules.d/90zfsbootmenu || ln -s ../../../90zfsbootmenu dracut/modules.d test -d "${_dracut_mods}" && rm -rf "${_dracut_mods}/90zfsbootmenu"
ln -s "$(realpath -e ../90zfsbootmenu)" "${_dracut_mods}"
fi fi
if ((GENZBM)) ; then
rm -f "${TESTDIR}/generate-zbm"
ln -s "$(realpath -e ../bin/generate-zbm)" "${TESTDIR}/generate-zbm"
fi
# Setup a local config file # Setup a local config file
if ((YAML)) ; then if ((YAML)) ; then
echo "Configuring local.yaml" echo "Configuring local.yaml"
cp ../etc/zfsbootmenu/config.yaml local.yaml cp ../etc/zfsbootmenu/config.yaml "${TESTDIR}/local.yaml"
yq-go w -i local.yaml Components.ImageDir "$( pwd )" yq-go w -i "${TESTDIR}/local.yaml" Components.ImageDir "${TESTDIR}"
yq-go w -i local.yaml Components.Versions false yq-go w -i "${TESTDIR}/local.yaml" Components.Versions false
yq-go w -i local.yaml Global.ManageImages true yq-go w -i "${TESTDIR}/local.yaml" Global.ManageImages true
yq-go w -i local.yaml Global.DracutConfDir "$( pwd )/dracut.conf.d" yq-go w -i "${TESTDIR}/local.yaml" Global.DracutConfDir "${TESTDIR}/dracut.conf.d"
yq-go w -i local.yaml Global.DracutFlags[+] -- "--local" yq-go w -i "${TESTDIR}/local.yaml" Global.DracutFlags[+] -- "--local"
yq-go d -i local.yaml Global.BootMountPoint yq-go d -i "${TESTDIR}/local.yaml" Global.BootMountPoint
yq-go r -P -C local.yaml yq-go r -P -C "${TESTDIR}/local.yaml"
fi fi
# Create an image # Create an image
if ((IMAGE)) ; then if ((IMAGE)) ; then
sudo env MUSL="${MUSL}" /bin/bash <<"EOF" sudo env MUSL="${MUSL}" ./image.sh "${TESTDIR}"
XBPS_ARCH="$(uname -m)"
case "${XBPS_ARCH}" in
ppc64le)
URL="https://mirrors.servercentral.com/void-ppc/current"
;;
x86_64)
URL="https://mirrors.servercentral.com/voidlinux/current"
;;
*)
echo "ERROR: unsupported architecture"
exit 1
;;
esac
if [ -n "${MUSL}" ]; then
URL="${URL}/musl"
XBPS_ARCH="${XBPS_ARCH}-musl"
fi
export XBPS_ARCH
MNT="$( mktemp -d )"
LOOP="$( losetup -f )"
qemu-img create zfsbootmenu-pool.img 2G
losetup "${LOOP}" zfsbootmenu-pool.img
kpartx -u "${LOOP}"
echo 'label: gpt' | sfdisk "${LOOP}"
zpool create -f \
-O compression=lz4 \
-O acltype=posixacl \
-O xattr=sa \
-O relatime=on \
-o autotrim=on \
-o cachefile=none \
-m none ztest "${LOOP}"
zfs snapshot -r ztest@barepool
zfs create -o mountpoint=none ztest/ROOT
zfs create -o mountpoint=/ -o canmount=noauto ztest/ROOT/void
zfs snapshot -r ztest@barebe
zfs set org.zfsbootmenu:commandline="spl_hostid=$( hostid ) ro quiet" ztest/ROOT
zpool set bootfs=ztest/ROOT/void ztest
zpool export ztest
zpool import -R "${MNT}" ztest
zfs mount ztest/ROOT/void
# https://github.com/project-trident/trident-installer/blob/master/src-sh/void-install-zfs.sh#L541
mkdir -p "${MNT}/var/db/xbps/keys"
cp /var/db/xbps/keys/*.plist "${MNT}/var/db/xbps/keys/."
mkdir -p "${MNT}/etc/xbps.d"
cp /etc/xbps.d/*.conf "${MNT}/etc/xbps.d/."
# /etc/runit/core-services/03-console-setup.sh depends on loadkeys from kbd
# /etc/runit/core-services/05-misc.sh depends on ip from iproute2
xbps-install -y -S -M -r "${MNT}" --repository="${URL}" \
base-minimal dracut ncurses-base kbd iproute2 dhclient openssh
cp /etc/hostid "${MNT}/etc/"
cp /etc/resolv.conf "${MNT}/etc/"
cp /etc/rc.conf "${MNT}/etc/"
mkdir -p "${MNT}/etc/xbps.d"
echo "repository=${URL}" > "${MNT}/etc/xbps.d/00-repository-main.conf"
mount -t proc proc "${MNT}/proc"
mount -t sysfs sys "${MNT}/sys"
mount -B /dev "${MNT}/dev"
mount -t devpts pts "${MNT}/dev/pts"
zfs snapshot -r ztest@pre-chroot
cp chroot.sh "${MNT}/root"
chroot "${MNT}" /root/chroot.sh
umount -R "${MNT}" && rmdir "${MNT}"
zpool export ztest
losetup -d "${LOOP}"
chown "$( stat -c %U . ):$( stat -c %G . )" zfsbootmenu-pool.img
EOF
fi fi