Scripts that turn an installed Omarchy disk into a downloadable VM image
As they were tested by hand on the 4.0.4 ISO, before any of it is wired
into a workflow:
vm-install unattended install of an ISO into a qcow2, through cidata
vm-seal makes the disk publishable: SSH takes keys only, no machine
ID, host keys, build key or build logs left, compressed
with zstd, with checksums and the kernel pulled out for
direct boot
vm-verify boots the sealed image once and checks all of that
vm-boot boots a throwaway copy with a key made for that boot and
runs a command in it
On this machine: install 114 s, seal 27 s, a 4.2 GB image, SSH about 5 s
after power-on, 17 of 17 verify checks, and 7 of them failing on an
image sealed without these fixes.
This commit is contained in:
1 parent
8b17699997
commit
4e7b18eb7d
4 files changed
+355
No files matched your search
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
# Boots a sealed Omarchy image (vm-seal) as a throwaway machine.
|
||||
#
|
||||
# vm-boot <sealed_dir> boot, print how to log in, run until Ctrl-C
|
||||
# vm-boot <sealed_dir> <command...> boot, run the command over SSH, power off;
|
||||
# exits with the command's status
|
||||
#
|
||||
# Nothing is written to sealed_dir: the machine runs on a copy-on-write overlay
|
||||
# that is deleted on exit. Each boot gets a new SSH key and a new machine ID;
|
||||
# the image itself holds no key and its SSH takes no password.
|
||||
#
|
||||
# Needs qemu-system-x86_64, qemu-img, ssh and a usable /dev/kvm.
|
||||
# Env: SMP (4), MEM (4G), SSH_PORT (random), VM_UUID (random), APPEND (more
|
||||
# kernel arguments), QEMU_EXTRA (more qemu arguments, split on spaces),
|
||||
# VM_STATE_DIR (/var/tmp; holds the overlay, so it needs room to grow).
|
||||
set -euo pipefail
|
||||
[[ $# -ge 1 ]] || { sed -n '2,16p' "$0" >&2; exit 2; }
|
||||
base=$(realpath "$1"); shift
|
||||
for f in base.qcow2 vmlinuz initrd cmdline; do
|
||||
[[ -s $base/$f ]] || { echo "vm-boot: $base/$f is missing" >&2; exit 1; }
|
||||
done
|
||||
[[ -r /dev/kvm && -w /dev/kvm ]] || { echo "vm-boot: /dev/kvm is not usable" >&2; exit 1; }
|
||||
|
||||
state=$(mktemp -d "${VM_STATE_DIR:-/var/tmp}/vm.XXXXXX")
|
||||
cleanup() {
|
||||
local status=$? pid
|
||||
if [[ -f $state/qemu.pid ]]; then
|
||||
pid=$(cat "$state/qemu.pid")
|
||||
kill "$pid" 2>/dev/null || true
|
||||
for _ in $(seq 1 50); do kill -0 "$pid" 2>/dev/null || break; sleep 0.1; done
|
||||
fi
|
||||
rm -rf "$state"
|
||||
exit "$status"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
trap 'exit 130' INT TERM
|
||||
port=${SSH_PORT:-$(( 20000 + RANDOM % 10000 ))}
|
||||
uuid=${VM_UUID:-$(cat /proc/sys/kernel/random/uuid)}
|
||||
|
||||
# A key made for this boot only, handed in through the firmware tables as a
|
||||
# systemd credential that writes authorized_keys.
|
||||
ssh-keygen -q -t ed25519 -N '' -C vm-boot -f "$state/id_ed25519"
|
||||
keys=$(printf 'd /home/omarchy/.ssh 0700 omarchy omarchy -\nf+ /home/omarchy/.ssh/authorized_keys 0600 omarchy omarchy - %s\n' \
|
||||
"$(cat "$state/id_ed25519.pub")" | base64 -w0)
|
||||
ssh_opts=(-i "$state/id_ed25519" -p "$port" -o BatchMode=yes -o IdentitiesOnly=yes
|
||||
-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR)
|
||||
|
||||
qemu-img create -qf qcow2 -b "$base/base.qcow2" -F qcow2 "$state/run.qcow2"
|
||||
t0=$(date +%s%N)
|
||||
# shellcheck disable=SC2086
|
||||
qemu-system-x86_64 -cpu host -enable-kvm -machine q35,accel=kvm -smp "${SMP:-4}" -m "${MEM:-4G}" \
|
||||
-kernel "$base/vmlinuz" -initrd "$base/initrd" -append "$(cat "$base/cmdline")${APPEND:+ $APPEND}" \
|
||||
-uuid "$uuid" \
|
||||
-drive "file=$state/run.qcow2,format=qcow2,if=none,id=d0" -device virtio-blk-pci,drive=d0 \
|
||||
-smbios "type=11,value=io.systemd.credential.binary:tmpfiles.extra=$keys" \
|
||||
-device virtio-vga -device virtio-rng-pci -display none \
|
||||
-netdev "user,id=n0,hostfwd=tcp:127.0.0.1:$port-:22" -device virtio-net-pci,netdev=n0 \
|
||||
-qmp "unix:$state/qmp.sock,server,nowait" -pidfile "$state/qemu.pid" -daemonize ${QEMU_EXTRA:-}
|
||||
|
||||
# </dev/null: the probe must not eat a script meant for the command below.
|
||||
until ssh "${ssh_opts[@]}" -o ConnectTimeout=1 omarchy@127.0.0.1 true </dev/null 2>/dev/null; do
|
||||
kill -0 "$(cat "$state/qemu.pid")" 2>/dev/null || { echo "vm-boot: qemu exited before ssh came up" >&2; exit 1; }
|
||||
(( ($(date +%s%N) - t0) / 1000000 < 300000 )) || { echo "vm-boot: no ssh after 300s" >&2; exit 1; }
|
||||
sleep 0.2
|
||||
done
|
||||
echo "vm-boot: ssh up after $(( ($(date +%s%N) - t0) / 1000000 )) ms, machine ID ${uuid//-/}" >&2
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
# Stdin passes through, so `vm-boot dir bash -s <script` works.
|
||||
ssh "${ssh_opts[@]}" omarchy@127.0.0.1 "$@"
|
||||
else
|
||||
echo "ssh ${ssh_opts[*]} omarchy@127.0.0.1"
|
||||
echo "Desktop and sudo password: omarchy. QMP socket: $state/qmp.sock. Ctrl-C powers it off."
|
||||
while kill -0 "$(cat "$state/qemu.pid")" 2>/dev/null; do sleep 1; done
|
||||
fi
|
||||
Reference in new issue
Block a user