From 49a7762e6cbc8bc4f106ea08071450c6aaf7a3a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20K=C3=B6rber?= Date: Mon, 22 Apr 2024 14:16:40 +0200 Subject: [PATCH] Add test script using QEMU --- install_scripts/neptune.sh | 13 +- test.sh | 266 +++++++++++++++++++++++++++++++++++++ 2 files changed, 274 insertions(+), 5 deletions(-) create mode 100755 test.sh diff --git a/install_scripts/neptune.sh b/install_scripts/neptune.sh index 7dc5ec9..a04280c 100755 --- a/install_scripts/neptune.sh +++ b/install_scripts/neptune.sh @@ -115,11 +115,14 @@ EOF # ExecStartPost=/bin/rmdir /etc/systemd/system/getty@tty1.service.d/ # Run -cat << EOF > /root/.bash_profile -if /var/lib/dotfiles/install.sh ; then - rm -f /root/.bash_profile - reboot -fi +cat << 'EOF' > /root/.bash_profile + if [[ "\$(tty)" == "/dev/tty1" ]] ; then + rm -rf /etc/systemd/system/getty@tty1.service.d/ + if /var/lib/dotfiles/install.sh ; then + rm -f /root/.bash_profile + reboot + fi + fi EOF CHROOTSCRIPT diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..73e7e93 --- /dev/null +++ b/test.sh @@ -0,0 +1,266 @@ +#!/usr/bin/env bash + +set -o nounset +set -o errexit +set -o pipefail + +tmpdir="$(mktemp -d --tmpdir=/var/tmp)" + +trap cleanup EXIT + +ISO_MIRROR="https://ftp.fau.de/archlinux/iso/latest/" +ISO_MIRROR="https://ftp.acc.umu.se/mirror/archlinux/iso/latest/" + +iso_dir="${XDG_DATA_HOME}/arch-iso/" +iso_path="${iso_dir}/archlinux-x86_64.iso" + +cleanup() { + rm -rf "${tmpdir}" + pids=() + jobs -p | while IFS="" read -r line; do pids+=("$line"); done + kill "${pids[@]}" +} + +download_iso() { + mkdir -p "${iso_dir}" + ( + cd "${iso_dir}" + wget \ + --timestamping \ + --no-hsts \ + "${ISO_MIRROR}sha256sums.txt" + + if [[ ! -e "${iso_path}" ]] || ! sha256sum --ignore-missing --check ./sha256sums.txt; then + wget \ + --no-hsts \ + --output-document "${iso_path}" \ + "${ISO_MIRROR}archlinux-x86_64.iso" + fi + ) +} + +disk="${tmpdir}/disk.qcow2" + +mon_sock="${tmpdir}/mon.sock" + +sshopts=( + -o StrictHostKeyChecking=no + -o UserKnownHostsFile=/dev/null + -o PreferredAuthentications=publickey + -o ConnectTimeout=1s + -i "${tmpdir}/ssh.key" + -l root + -p 60022 + 127.0.0.1 +) + +wait_for_ssh() { + echo "waiting for ssh" + set +o errexit + maxtries=60 + tries=0 + while ! ssh -q "${sshopts[@]}" true; do + ((tries++)) + if ((tries > maxtries)); then + echo "ssh did not become available" + exit 3 + fi + sleep 1 + done + echo "ssh available" + set -o errexit +} + +qemuopts=( + "-m" "size=8G" + "-drive" "file=${disk},format=qcow2,if=none,id=root" + + "-accel" "kvm" + + "-drive" "if=pflash,format=raw,readonly=true,file=/usr/share/ovmf/x64/OVMF_CODE.fd" + "-drive" "if=pflash,format=raw,file=${tmpdir}/efivars.fd" + "-machine" "q35,smm=on,acpi=on" + "-smp" "cpus=8,sockets=1,cores=8,threads=1" + "-cpu" "host" + + "-netdev" "user,id=net0,hostfwd=tcp::60022-:22" + "-device" "virtio-net-pci,netdev=net0" + + "-nodefaults" + + "-vga" "virtio" + "-display" "spice-app" +) + +send_mon() { + local socket="${1}" + patterns=( + -e 's/ /spc/' + -e 's/\./dot/' + -e 's/,/comma/' -e 's/-/slash/' + -e 's/\//shift-7/' + -e 's/\([A-Z]\)/shift-\L\1/' + -e 's/=/shift-0/' + -e 's/"/shift-2/' + -e "s/'/shift-0x2b/" + # ^ is a dead key, we would have to send a space to be precise. but it's + # going to work out as long as the following char does not combine + -e 's/\^/0x29/' + -e 's/#/0x2b/' + -e 's/\?/shift-0x0c/' + -e 's/\\/alt_r-0x0c/' # altgr is alt_r + -e 's/\*/shift-0x1b/' + -e 's/(/shift-0x09/' + -e 's/)/shift-0x0a/' + -e 's/^/sendkey /' + ) + + cat \ + <(fold -w 1 | + sed "${patterns[@]}") \ + <(echo "sendkey ret") | + nc -N -U "${socket}" + + echo "sendkey ret" | nc -N -U "${socket}" +} + +install_from_iso() { + local hostname="${1}" + shift + local hostqemuopts=("$@") + rm -rf "${tmpdir:?}"/* + + ssh-keygen -f "${tmpdir}"/ssh.key -N '' -t ed25519 -C 'archiso-tmp' + + cloud-localds "${tmpdir}/userdata.img" <( + cat < /tmp/specials.sh + if [[ "\\\$(tty)" == "/dev/tty1" ]] ; then + mkdir /var/cache/pacman-cache-host + mount -t 9p -o trans=virtio,version=9p2000.L,ro pacman-cache /var/cache/pacman-cache-host + + # Uncomment CacheDir and prepend the host pacman cache as cachedir + # At worst, the cache directory will be ignored if it does not exist + # Pacman will always use the first directory with write access for downloads + sed -i 's/^#\?\(CacheDir.*\)/\1\nCacheDir = \/var\/cache\/pacman-cache-host\//' /etc/pacman.conf + fi +SPECIALS + + mv /mnt/root/.bash_profile /tmp/rest.sh + + cat /tmp/specials.sh /tmp/rest.sh > /mnt/root/.bash_profile + + rsync -rl /repo/ /mnt/var/lib/dotfiles/ + + umount /mnt + + poweroff +EOF + + wait +} + +configure_new_system() { + local hostname="${1}" + shift + local hostqemuopts=("${@}") + + opts=( + "-fsdev" "local,id=pacman-cache,path=share,path=/var/cache/pacman/pkg/,readonly=on,security_model=none" + "-device" "virtio-9p-pci,fsdev=pacman-cache,mount_tag=pacman-cache" + + "-monitor" "unix:${mon_sock},server=on,wait=off" + ) + + qemu-system-x86_64 -name "${hostname}" "${qemuopts[@]}" "${hostqemuopts[@]}" "${opts[@]}" & + + # 5s for grub timeout, 5s for kernel boot + echo waiting for luks password prompt ... + sleep 10s + echo 'lukspw' | send_mon "${mon_sock}" + + echo waiting for boot ... + sleep 10s + wait +} + +machines=(ares neptune) +if (($# > 0)); then + machines=("${@}") +fi + +download_iso + +for hostname in "${machines[@]}"; do + case "${hostname}" in + ares) + hostqemuopts=("-device" "ide-hd,drive=root") + ;; + neptune) + hostqemuopts=("-device" "nvme,serial=rootnvme,drive=root") + ;; + *) + exit 1 + ;; + esac + [[ ! "${hostqemuopts[*]}" ]] && exit 1 + install_from_iso "${hostname}" "${hostqemuopts[@]}" + configure_new_system "${hostname}" "${hostqemuopts[@]}" +done