Survey the machine, and say what an install would do to it

The first two pieces of the installer, and deliberately the two that change
nothing: what this machine is, and what would happen to it.

The survey is the floor under every later choice -- a component can only
offer a container shape if Docker answers for this user, or a host shape on
a systemd machine with what that shape needs. It reports what it could not
establish as unknown rather than guessing: an unprivileged probe of port 25
means "I may not bind this", not "something is listening", and reporting
the first as the second is a lie an operator would act on.

The plan is one list, and it will have three readers: --dry-run prints it,
the interface will show it before anything happens, and apply will walk it.
What you are shown is what runs.

Tested on a fresh Debian 13 in qemu, which has neither Docker nor Node and
so exercises every unavailable shape: 23 checks, including that nothing was
created by any of it. The lab that machine runs in is in e2e/vm.
This commit is contained in:
2026-09-22 17:56:20 -07:00
commit f97fd12556
13 changed files with 2046 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
# SPDX-FileCopyrightText: 2026 Coffey Labs
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Shared by the four scripts beside it: how the lab machine is started,
# stopped and talked to. Sourced, never run.
#
# One machine at a time, identified by its pid file. qemu is given a monitor
# on a unix socket so a stop is a clean powerdown rather than pulling the
# plug on a filesystem we are about to copy.
#
# Keep the default VGA device. `-vga none` looks right for a headless machine
# and is not: this image's GRUB hands over to a kernel that never prints, and
# the machine resets in a loop at "Booting Debian GNU/Linux" forever. -display
# none is what makes it headless; the adapter has to be there.
vm_running() {
[ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null
}
vm_start() {
qemu-system-x86_64 \
-enable-kvm -cpu host -m "$MEM" -smp "$VCPUS" \
-drive "file=$DISK,if=virtio,format=qcow2" \
-drive "file=$SEED,if=virtio,format=raw,readonly=on" \
-netdev "user,id=n0,hostfwd=tcp:127.0.0.1:$SSH_PORT-:22" \
-device virtio-net-pci,netdev=n0 \
-display none -serial "file:$LOG" \
-monitor "unix:$LAB/monitor.sock,server,nowait" \
-pidfile "$PIDFILE" \
-daemonize
}
vm_stop() {
vm_running || return 0
printf 'system_powerdown\n' | timeout 5 socat - "unix-connect:$LAB/monitor.sock" >/dev/null 2>&1 \
|| printf 'system_powerdown\n' | timeout 5 nc -U "$LAB/monitor.sock" >/dev/null 2>&1 \
|| true
for _ in $(seq 1 30); do
vm_running || return 0
sleep 1
done
# It had its chance.
kill "$(cat "$PIDFILE")" 2>/dev/null || true
sleep 1
}
vm_ssh() {
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
-o ConnectTimeout=3 -o BatchMode=yes -o LogLevel=ERROR \
-p "$SSH_PORT" [email protected] "$@"
}
vm_scp() {
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
-o LogLevel=ERROR -P "$SSH_PORT" "$@"
}