mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 20:27:15 +01:00
The Arch cloud image leaves sshd enabled but never started -- no start line, no failure line, dependencies satisfied. Four hypotheses (NTP, cloud-init clean, a socket-disable, a blocking start) were each disproven by measurement, so rather than keep paying a ~10 min rebuild per guess this adds the transport the tool should arguably have used all along. For the case vmbox exists for, serial beats ssh on the merits: it keeps printing straight through the poweroff that kills an ssh connection, and it works when sshd does not. `vm run` now picks ssh when it answers and the serial console otherwise, and recovers the guest exit code either way. Guests get a second serial port (ttyS1) on a unix socket with a root autologin, kept separate from ttyS0 so driving a shell never interleaves with the append-only log the verdict is read from. serial_exec.py waits for an explicit per-command end marker rather than a fixed sleep. That is not a detail: an earlier probe used a 4s window, the next command was typed while the previous one still ran, and the tty echoed that input -- which reads exactly like output in a transcript and produced a confident but wrong conclusion. It also strips ANSI CSI and systemd's OSC 3008 shell-integration blocks, verified against a real captured boot log. Also: a vmbox-sshd-kick unit that forces sshd up after multi-user.target as belt and braces, and the smoke-test sandbox renamed to a name that actually passes validate_vm_name -- "__smoke" was rejected, so the gate silently never ran. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdyMBGCrGVGDWtJ9xe48f3
50 lines
2.0 KiB
Bash
50 lines
2.0 KiB
Bash
#!/bin/bash
|
|
# ============================================================================
|
|
# vmbox: post-seal verification.
|
|
#
|
|
# Split out of base.sh to stay under the 250-line cap.
|
|
# ============================================================================
|
|
|
|
# shellcheck source=common.sh
|
|
source "$(dirname "${BASH_SOURCE[0]}")/common.sh"
|
|
|
|
# Boot a real overlay off the freshly sealed base and require that ssh answers.
|
|
#
|
|
# This is the gate that matters. Every check inside the build VM only proves
|
|
# state at seal time; the failures that actually shipped all lived in the gap
|
|
# between "correct in the build VM" and "works on a fresh overlay boot". This
|
|
# catches missing host keys, a no-op systemctl enable, a clobbered NIC and
|
|
# whatever the next cause turns out to be, WITHOUT needing to know which.
|
|
base_smoke_test() {
|
|
log "Smoke-testing the sealed image (boots a throwaway sandbox)"
|
|
source "$VMBOX_LIB_DIR/overlay.sh"
|
|
source "$VMBOX_LIB_DIR/launch.sh"
|
|
source "$VMBOX_LIB_DIR/ssh.sh"
|
|
|
|
local smoke="vmbox-smoke"
|
|
vm_exists "$smoke" && overlay_rm "$smoke" >/dev/null 2>&1
|
|
overlay_new "$smoke" >/dev/null
|
|
|
|
local failed=0
|
|
launch_vm "$smoke" >/dev/null
|
|
if vm_wait_ssh "$smoke" 180 && vm_ssh_exec "$smoke" true 2>/dev/null; then
|
|
ok "smoke test passed: a fresh sandbox boots and accepts ssh"
|
|
else
|
|
failed=1
|
|
warn "SMOKE TEST FAILED -- the sealed image boots but is unreachable."
|
|
warn "Serial log: $(vm_serial "$smoke" 0)"
|
|
warn "Debug it with the serial console (root autologin is enabled there)."
|
|
fi
|
|
|
|
# On failure KEEP the sandbox: deleting it would destroy the serial log
|
|
# this very message points at, which is the only evidence available when
|
|
# ssh is the thing that is broken.
|
|
if (( failed == 0 )); then
|
|
overlay_rm "$smoke" >/dev/null 2>&1 || true
|
|
else
|
|
warn "keeping sandbox 'vmbox-smoke' so its logs survive; remove it with: vm rm vmbox-smoke"
|
|
die "refusing to ship an unreachable base image"
|
|
fi
|
|
}
|
|
|