260 lines
7.2 KiB
Bash
Executable File
260 lines
7.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# vim: softtabstop=2 shiftwidth=2 expandtab
|
|
|
|
cleanup() {
|
|
if [ -n "${CHROOT_MNT}" ]; then
|
|
echo "Cleaning up chroot mount '${CHROOT_MNT}'"
|
|
mountpoint -q "${CHROOT_MNT}" && umount -R "${CHROOT_MNT}"
|
|
[ -d "${CHROOT_MNT}" ] && rmdir "${CHROOT_MNT}"
|
|
unset CHROOT_MNT
|
|
fi
|
|
|
|
if [ -n "${ZBM_POOL}" ]; then
|
|
echo "Exporting pool '${ZBM_POOL}'"
|
|
zpool export "${ZBM_POOL}"
|
|
unset ZBM_POOL
|
|
fi
|
|
|
|
if [ -n "${LOOP_DEV}" ]; then
|
|
echo "Deleting loopback device '${LOOP_DEV}'"
|
|
losetup -d "${LOOP_DEV}"
|
|
unset LOOP_DEV
|
|
fi
|
|
|
|
exit
|
|
}
|
|
|
|
TESTDIR="${1?Usage: $0 <testdir> <size> <distro> <pool name>}"
|
|
SIZE="${2?Usage: $0 <testdir> <size> <distro> <pool name>}"
|
|
DISTRO="${3?Usage: $0 <testdir> <size> <distro> <pool name>}"
|
|
zpool_name="${4?Usage: $0 <testdir> <size> <distro> <pool name>}"
|
|
|
|
if [ -z "${TESTDIR}" ] || [ ! -d "${TESTDIR}" ]; then
|
|
echo "ERROR: test directory must be specified and must exist"
|
|
exit 1
|
|
fi
|
|
|
|
INSTALL_SCRIPT="./helpers/install-${DISTRO}.sh"
|
|
if [ ! -x "${INSTALL_SCRIPT}" ]; then
|
|
echo "ERROR: install script '${INSTALL_SCRIPT}' missing or not executable"
|
|
exit 1
|
|
fi
|
|
|
|
CHROOT_SCRIPT="./helpers/chroot-${DISTRO}.sh"
|
|
if [ ! -x "${CHROOT_SCRIPT}" ]; then
|
|
echo "ERROR: chroot script '${CHROOT_SCRIPT}' missing or not executable"
|
|
exit 1
|
|
fi
|
|
|
|
export ZBM_POOL=""
|
|
export LOOP_DEV=""
|
|
|
|
CHROOT_MNT="$( mktemp -d )" || exit 1
|
|
export CHROOT_MNT
|
|
|
|
# Perform all necessary cleanup for this script
|
|
trap cleanup EXIT INT TERM
|
|
|
|
ZBMIMG="${TESTDIR}/${zpool_name}-pool.img"
|
|
USERGROUP="$( stat -c %U . ):$( stat -c %G . )"
|
|
|
|
if [ -z "${EXISTING_POOL}" ]; then
|
|
|
|
qemu-img create "${ZBMIMG}" "${SIZE}"
|
|
chown "${USERGROUP}" "${ZBMIMG}"
|
|
|
|
# When a new pool should be encrypted, it needs a key
|
|
if [ -n "${ENCRYPT}" ]; then
|
|
echo "zfsbootmenu" > "${TESTDIR}/${zpool_name}.key"
|
|
chown "${USERGROUP}" "${TESTDIR}/${zpool_name}.key"
|
|
fi
|
|
elif [ ! -e "${ZBMIMG}" ]; then
|
|
echo "ERROR: cannot use non-existent image ${ZBMIMG} as existing pool"
|
|
exit 1
|
|
fi
|
|
|
|
if ENCRYPT_KEYFILE="$( realpath -e "${TESTDIR}/${zpool_name}.key" 2>/dev/null )"; then
|
|
export ENCRYPT_KEYFILE
|
|
elif [ -n "${ENCRYPT}" ]; then
|
|
echo "ERROR: unable to find real path to encryption key file"
|
|
exit 1
|
|
fi
|
|
|
|
if ! LOOP_DEV="$( losetup -f --show "${ZBMIMG}" )"; then
|
|
echo "ERROR: unable to attach loopback device"
|
|
exit 1
|
|
else
|
|
export LOOP_DEV
|
|
fi
|
|
|
|
if [ -z "${EXISTING_POOL}" ]; then
|
|
kpartx -u "${LOOP_DEV}"
|
|
|
|
echo 'label: gpt' | sfdisk "${LOOP_DEV}"
|
|
|
|
ENCRYPT_OPTS=()
|
|
if [ -r "${ENCRYPT_KEYFILE}" ]; then
|
|
ENCRYPT_OPTS=( "-O" "encryption=aes-256-gcm" "-O" "keyformat=passphrase" )
|
|
ENCRYPT_OPTS+=( "-O" "keylocation=file://${ENCRYPT_KEYFILE}" )
|
|
fi
|
|
|
|
if [ -n "${POOL_COMPAT}" ]; then
|
|
COMPAT_OPTS=( "-o" "compatibility=${POOL_COMPAT}" )
|
|
else
|
|
COMPAT_OPTS=( )
|
|
fi
|
|
|
|
if zpool create -f -m none \
|
|
-O compression=lz4 \
|
|
-O acltype=posixacl \
|
|
-O xattr=sa \
|
|
-O relatime=on \
|
|
-o autotrim=on \
|
|
-o cachefile=none \
|
|
"${COMPAT_OPTS[@]}" \
|
|
"${ENCRYPT_OPTS[@]}" \
|
|
"${zpool_name}" "${LOOP_DEV}"; then
|
|
export ZBM_POOL="${zpool_name}"
|
|
else
|
|
echo "ERROR: unable to create pool ${zpool_name}"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -r "${ENCRYPT_KEYFILE}" ]; then
|
|
zfs set "keylocation=file:///etc/zfs/${ZBM_POOL}.key" "${ZBM_POOL}"
|
|
fi
|
|
|
|
zfs snapshot -r "${ZBM_POOL}@barepool"
|
|
zfs create -o mountpoint=none "${ZBM_POOL}/ROOT"
|
|
|
|
zpool export "${ZBM_POOL}"
|
|
export ZBM_POOL=""
|
|
fi
|
|
|
|
if ! zpool import -o cachefile=none -R "${CHROOT_MNT}" "${zpool_name}"; then
|
|
echo "ERROR: unable to import ZFS pool ${zpool_name}"
|
|
exit 1
|
|
else
|
|
export ZBM_POOL="${zpool_name}"
|
|
fi
|
|
|
|
ZBM_ROOT="${ZBM_POOL}/ROOT/${DISTRO}"
|
|
if zfs list -o name -H "${ZBM_ROOT}" >/dev/null 2>&1; then
|
|
echo "ERROR: ZFS filesystem ${ZBM_ROOT} already exists"
|
|
exit 1
|
|
fi
|
|
|
|
case "$( zfs get -H -o value encryptionroot "${ZBM_POOL}" 2>/dev/null )" in
|
|
"-"|"")
|
|
;;
|
|
*)
|
|
if [ -r "${ENCRYPT_KEYFILE}" ]; then
|
|
zfs load-key -L "file://${ENCRYPT_KEYFILE}" "${ZBM_POOL}"
|
|
else
|
|
zfs load-key -L prompt "${ZBM_POOL}"
|
|
export ENCRYPT_KEYFILE=""
|
|
fi
|
|
esac
|
|
|
|
zfs create -o mountpoint=/ -o canmount=noauto "${ZBM_ROOT}"
|
|
zfs snapshot -r "${ZBM_ROOT}@barebe"
|
|
|
|
zfs set org.zfsbootmenu:commandline="spl_hostid=$( hostid ) rw loglevel=4 console=tty1 console=ttyS0" "${ZBM_ROOT}"
|
|
zpool set bootfs="${ZBM_ROOT}" "${ZBM_POOL}"
|
|
|
|
if ! zfs mount "${ZBM_ROOT}"; then
|
|
echo "ERROR: unable to mount ${ZBM_ROOT}"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -r "${ENCRYPT_KEYFILE}" ]; then
|
|
# Make sure the ZFS key exists in the BE
|
|
mkdir -p "${CHROOT_MNT}/etc/zfs"
|
|
cp "${ENCRYPT_KEYFILE}" "${CHROOT_MNT}/etc/zfs/"
|
|
|
|
# Set a ZBM key source if one is not already provided
|
|
if [ "$( zfs get -o value -H org.zfsbootmenu:keysource "${ZBM_POOL}" )" = "-" ]; then
|
|
zfs set "org.zfsbootmenu:keysource=${ZBM_ROOT}" "${ZBM_POOL}"
|
|
fi
|
|
fi
|
|
|
|
# Create a cache directory and mount in the target
|
|
if CACHEDIR="$( realpath -e "${CACHEDIR:-./cache}" )"; then
|
|
HOSTCACHE="${CHROOT_MNT}/hostcache"
|
|
if [ -d "${CACHEDIR}" ]; then
|
|
mkdir -p "${CACHEDIR}/${DISTRO}" && \
|
|
mkdir -p "${HOSTCACHE}" && \
|
|
mount -B "${CACHEDIR}/${DISTRO}" "${HOSTCACHE}" && \
|
|
mount --make-slave "${HOSTCACHE}"
|
|
fi
|
|
fi
|
|
|
|
if ! "${INSTALL_SCRIPT}"; then
|
|
echo "ERROR: install script '${INSTALL_SCRIPT}' failed"
|
|
exit 1
|
|
fi
|
|
|
|
zfs snapshot -r "${ZBM_ROOT}@pre-chroot"
|
|
|
|
# Make sure the chroot script exists
|
|
mkdir -p "${CHROOT_MNT}/root"
|
|
cp "${CHROOT_SCRIPT}" "${CHROOT_MNT}/root/"
|
|
|
|
# Make sure special filesystems are mounted
|
|
mkdir -p "${CHROOT_MNT}"/{proc,sys,dev/pts}
|
|
mount -t proc proc "${CHROOT_MNT}/proc"
|
|
mount -t sysfs sys "${CHROOT_MNT}/sys"
|
|
mount -B /dev "${CHROOT_MNT}/dev" && mount --make-slave "${CHROOT_MNT}/dev"
|
|
mount -t devpts pts "${CHROOT_MNT}/dev/pts"
|
|
|
|
# Make sure the zpool information is cached
|
|
mkdir -p "${CHROOT_MNT}/etc/zfs"
|
|
zpool set cachefile="${CHROOT_MNT}/etc/zfs/zpool.cache" "${ZBM_POOL}"
|
|
|
|
# Set hostname for environment
|
|
echo "${DISTRO}" > "${CHROOT_MNT}/etc/hostname"
|
|
|
|
# Pre-populate SSH keys, if available
|
|
if [ -d "./keys/etc/ssh" ]; then
|
|
cp -R "./keys/etc/ssh" "${CHROOT_MNT}/etc/"
|
|
fi
|
|
|
|
# Pre-populate authorized keys, if available
|
|
if [ -r "./keys/authorized_keys" ]; then
|
|
mkdir -p "${CHROOT_MNT}/root/.ssh"
|
|
chmod 700 "${CHROOT_MNT}/root/.ssh"
|
|
cp "./keys/authorized_keys" "${CHROOT_MNT}/root/.ssh/"
|
|
fi
|
|
|
|
# Launch the chroot script
|
|
if ! chroot "${CHROOT_MNT}" "/root/${CHROOT_SCRIPT##*/}"; then
|
|
echo "ERROR: chroot script '${CHROOT_SCRIPT}' failed"
|
|
exit 1
|
|
fi
|
|
|
|
# Pre-populate the test environment with ZBM from the testbed
|
|
if [ -d "${CHROOT_MNT}/zfsbootmenu" ]; then
|
|
if chroot "${CHROOT_MNT}" /usr/bin/generate-zbm --prefix vmlinuz; then
|
|
for f in vmlinuz-bootmenu initramfs-bootmenu.img; do
|
|
file="${CHROOT_MNT}/zfsbootmenu/build/${f}"
|
|
[ -f "${file}" ] || continue
|
|
|
|
cp "${file}" "${TESTDIR}/${f}.${DISTRO}"
|
|
chmod 644 "${TESTDIR}/${f}.${DISTRO}"
|
|
chown "${USERGROUP}" "${TESTDIR}/${f}.${DISTRO}"
|
|
|
|
if [ ! -e "${TESTDIR}/${f}" ] || [ -L "${TESTDIR}/${f}" ]; then
|
|
ln -sf "${f}.${DISTRO}" "${TESTDIR}/${f}"
|
|
fi
|
|
done
|
|
fi
|
|
fi
|
|
|
|
zfs snapshot -r "${ZBM_ROOT}@full-setup"
|
|
|
|
touch "${CHROOT_MNT}/root/IN_THE_MATRIX"
|
|
zfs snapshot -r "${ZBM_ROOT}@minor-changes"
|
|
|
|
rm "${CHROOT_MNT}/root/IN_THE_MATRIX"
|
|
rm "${CHROOT_MNT}/root/${CHROOT_SCRIPT##*/}"
|