Files
2026-10-15 20:44:05 -03:00

91 lines
4.0 KiB
Bash
Executable File

#!/bin/bash
# Test virtual machine for the built image (build/acpc2026.qcow2).
#
# tests/check_vm.sh start [--wrong-clock] [--usb] boot a throwaway copy
# tests/check_vm.sh stop power it off, delete the copy
#
# The copy (tests/work/check.qcow2) opens SSH for the tests: password login,
# no DenyGroups, and the firewall accepts tcp 22. The built image itself is
# not modified. --wrong-clock starts with the hardware clock 3 hours behind
# (as on a lab machine running Windows), --usb adds a USB controller so that
# USB devices can be plugged in with tests/usb.sh.
set -eu
cd "$(dirname "$0")/.."
W=tests/work
MON=$W/monitor.sock
BUILT=$(realpath build/acpc2026.qcow2)
running() { pgrep -f "^qemu-system-x86_64 -name acpc2026-check" >/dev/null; }
case "${1:-}" in
start)
shift
running && { echo "The test VM is already running." >&2; exit 1; }
mkdir -p "$W"
qemu-img create -q -f qcow2 -b "$BUILT" -F qcow2 "$W/check.qcow2"
for d in /usr/share/edk2/x64 /usr/share/OVMF /usr/share/edk2/ovmf; do
for c in OVMF_CODE.4m.fd OVMF_CODE_4M.fd OVMF_CODE.fd; do
[ -f "$d/$c" ] && { CODE=$d/$c; VARS=$d/${c/CODE/VARS}; break 2; }
done
done
cp "$VARS" "$W/vars.fd"
# Open SSH in the copy, offline
touch "$W/fuse.raw"
qemu-storage-daemon --blockdev driver=file,node-name=f,filename="$W/check.qcow2" \
--blockdev driver=qcow2,node-name=q,file=f \
--export type=fuse,id=e,node-name=q,mountpoint="$W/fuse.raw",writable=on > "$W/qsd.log" 2>&1 &
for _ in $(seq 1 20); do mountpoint -q "$W/fuse.raw" && break; sleep 0.5; done
start=$(sfdisk -J "$W/fuse.raw" | python3 -I -c 'import json,sys; p=json.load(sys.stdin)["partitiontable"]["partitions"]; print(max(p,key=lambda x:x["size"])["start"])')
D="$W/fuse.raw?offset=$((start * 512))"
printf 'PasswordAuthentication yes\n' > "$W/00-test.conf"
w() { debugfs -w -R "$1" "$D" >/dev/null 2>&1 || true; }
w "rm /etc/ssh/sshd_config.d/icpc.conf"
w "write $W/00-test.conf /etc/ssh/sshd_config.d/00-test.conf"
w "mkdir /etc/systemd/system/firewall.service.d"
w "write tests/test-ssh.conf /etc/systemd/system/firewall.service.d/test-ssh.conf"
for f in /etc/ssh/sshd_config.d/00-test.conf /etc/systemd/system/firewall.service.d/test-ssh.conf; do
for x in "mode 0100644" "uid 0" "gid 0"; do w "set_inode_field $f $x"; done
done
for x in "mode 040755" "uid 0" "gid 0"; do w "set_inode_field /etc/systemd/system/firewall.service.d $x"; done
fusermount3 -u "$W/fuse.raw"
pkill -f "^qemu-storage-daemon .*$W/check.qcow2" || true
sleep 1
EXTRA=()
for a in "$@"; do
case "$a" in
--wrong-clock) EXTRA+=(-rtc "base=$(date -u -d '-3 hours' +%Y-%m-%dT%H:%M:%S)") ;;
--usb) EXTRA+=(-device qemu-xhci,id=xhci) ;;
esac
done
setsid qemu-system-x86_64 -name acpc2026-check -machine q35,accel=kvm -cpu host -m 6144 -smp 4 \
-drive if=pflash,format=raw,readonly=on,file="$CODE" \
-drive if=pflash,format=raw,file="$W/vars.fd" \
-drive id=disk0,file="$W/check.qcow2",format=qcow2,if=none \
-device virtio-blk-pci,drive=disk0,bootindex=1 \
-netdev user,id=net0,hostfwd=tcp:127.0.0.1:2222-:22 -device virtio-net-pci,netdev=net0 \
-vga virtio -display none -monitor unix:"$MON",server,nowait \
-serial file:"$W/serial.log" "${EXTRA[@]}" > "$W/qemu.log" 2>&1 &
for _ in $(seq 1 120); do
tests/vssh.sh team true 2>/dev/null && break
sleep 3
done
# Wait for the desktop session of the team account
for _ in $(seq 1 60); do
tests/vssh.sh team 'loginctl list-sessions --no-legend' 2>/dev/null | grep -q seat0 && break
sleep 2
done
echo "Test VM ready (SSH 127.0.0.1:2222, monitor $MON)."
;;
stop)
if running; then
python3 -I tests/monitor.py "$MON" quit || true
for _ in $(seq 1 30); do running || break; sleep 1; done
fi
rm -rf "$W"
echo "Test VM stopped."
;;
*)
sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//'
exit 2
;;
esac