Manage image artifacts and show VM create progress

Stop relying on ad hoc rootfs handling by adding image promotion, managed work-seed fingerprint metadata, and lazy self-healing for older managed images after the first create.

Rebuild guest images with baked SSH access, a guest NIC bootstrap, and default opencode services, and add the staged Void kernel/initramfs/modules workflow so void-exp uses a matching Void boot stack.

Replace the opaque blocking vm.create RPC with a begin/status flow that prints live stages in the CLI while still waiting for vsock health and opencode on guest port 4096.

Validate with GOCACHE=/tmp/banger-gocache go test ./... and live void-exp create/delete smoke runs.
This commit is contained in:
Thales Maciel 2026-03-21 14:48:01 -03:00
parent 9f09b0d25c
commit 30f0c0b54a
No known key found for this signature in database
GPG key ID: 33112E6833C34679
37 changed files with 2334 additions and 99 deletions

View file

@ -18,8 +18,10 @@ Defaults:
--arch x86_64
--packages ./packages.void
This path is experimental and local-only. It reuses the current runtime bundle
kernel/initrd/modules and does not change the default Debian image flow.
This path is experimental and local-only. If ./runtime/void-kernel exists it
uses the staged Void kernel modules from that directory; otherwise it falls back
to the current runtime bundle modules. It does not change the default Debian
image flow.
EOF
}
@ -85,6 +87,14 @@ bundle_path() {
printf '%s\n' "$fallback"
}
find_latest_module_dir() {
local root="$1"
if [[ ! -d "$root" ]]; then
return 1
fi
find "$root" -mindepth 1 -maxdepth 1 -type d | sort | tail -n 1
}
find_static_binary() {
local name="$1"
find "$STATIC_DIR" -type f \( -name "$name" -o -name "$name.static" \) -perm -u+x | sort | head -n 1
@ -94,6 +104,15 @@ find_static_keys_dir() {
find "$STATIC_DIR" -type d -path '*/var/db/xbps/keys' | sort | head -n 1
}
install_root_authorized_key() {
local public_key
public_key="$(ssh-keygen -y -f "$SSH_KEY")"
sudo mkdir -p "$ROOT_MOUNT/root/.ssh"
printf '%s\n' "$public_key" | sudo tee "$ROOT_MOUNT/root/.ssh/authorized_keys" >/dev/null
sudo chmod 700 "$ROOT_MOUNT/root/.ssh"
sudo chmod 600 "$ROOT_MOUNT/root/.ssh/authorized_keys"
}
ensure_sshd_include() {
local cfg="$ROOT_MOUNT/etc/ssh/sshd_config"
local tmp_cfg="$TMP_DIR/sshd_config"
@ -137,6 +156,34 @@ EOF
sudo ln -snf /etc/sv/banger-vsock-agent "$ROOT_MOUNT/etc/runit/runsvdir/default/banger-vsock-agent"
}
install_opencode_service() {
local service_dir="$ROOT_MOUNT/etc/sv/banger-opencode"
local run_path="$service_dir/run"
local finish_path="$service_dir/finish"
sudo mkdir -p "$service_dir"
cat <<'EOF' | sudo tee "$run_path" >/dev/null
#!/bin/sh
set -e
export HOME=/root
cd /root
exec /usr/local/bin/opencode serve --hostname 0.0.0.0 --port 4096
EOF
cat <<'EOF' | sudo tee "$finish_path" >/dev/null
#!/bin/sh
exit 0
EOF
sudo chmod 0755 "$run_path" "$finish_path"
sudo mkdir -p "$ROOT_MOUNT/etc/runit/runsvdir/default"
sudo ln -snf /etc/sv/banger-opencode "$ROOT_MOUNT/etc/runit/runsvdir/default/banger-opencode"
}
install_guest_network_bootstrap() {
sudo mkdir -p "$ROOT_MOUNT/usr/local/libexec" "$ROOT_MOUNT/etc/runit/core-services"
sudo install -m 0755 "$GUESTNET_BOOTSTRAP_SCRIPT" "$ROOT_MOUNT/usr/local/libexec/banger-network-bootstrap"
sudo install -m 0644 "$GUESTNET_VOID_CORE_SERVICE" "$ROOT_MOUNT/etc/runit/core-services/20-banger-network.sh"
}
configure_docker_bootstrap() {
local modules_conf="$ROOT_MOUNT/etc/modules-load.d/docker-netfilter.conf"
local sysctl_conf="$ROOT_MOUNT/etc/sysctl.d/99-docker.conf"
@ -346,6 +393,7 @@ if [[ ! -d "$RUNTIME_DIR" ]]; then
fi
BUNDLE_METADATA="$RUNTIME_DIR/bundle.json"
SSH_KEY="$(bundle_path ssh_key_path "$RUNTIME_DIR/id_ed25519")"
OUT_ROOTFS="$RUNTIME_DIR/rootfs-void.ext4"
SIZE_SPEC="2G"
MIRROR="https://repo-default.voidlinux.org"
@ -353,11 +401,17 @@ ARCH="x86_64"
MISE_VERSION="v2025.12.0"
MISE_INSTALL_PATH="/usr/local/bin/mise"
OPENCODE_TOOL="github:anomalyco/opencode"
GUESTNET_BOOTSTRAP_SCRIPT="$SCRIPT_DIR/internal/guestnet/assets/bootstrap.sh"
GUESTNET_VOID_CORE_SERVICE="$SCRIPT_DIR/internal/guestnet/assets/void-core-service.sh"
MODULES_DIR="$(bundle_path default_modules_dir "$RUNTIME_DIR/wtf/root/lib/modules/6.8.0-94-generic")"
VOID_KERNEL_MODULES_DIR="$(find_latest_module_dir "$RUNTIME_DIR/void-kernel/lib/modules" || true)"
VSOCK_AGENT="$(bundle_path vsock_agent_path "$RUNTIME_DIR/banger-vsock-agent")"
if [[ "$VSOCK_AGENT" == "$RUNTIME_DIR/banger-vsock-agent" && ! -x "$VSOCK_AGENT" ]]; then
VSOCK_AGENT="$(bundle_path vsock_ping_helper_path "$RUNTIME_DIR/banger-vsock-pingd")"
fi
if [[ -n "$VOID_KERNEL_MODULES_DIR" ]]; then
MODULES_DIR="$VOID_KERNEL_MODULES_DIR"
fi
while [[ $# -gt 0 ]]; do
case "$1" in
@ -417,6 +471,14 @@ if [[ ! -x "$VSOCK_AGENT" ]]; then
log "run 'make build' or refresh the runtime bundle"
exit 1
fi
if [[ ! -f "$GUESTNET_BOOTSTRAP_SCRIPT" ]]; then
log "guest network bootstrap script not found: $GUESTNET_BOOTSTRAP_SCRIPT"
exit 1
fi
if [[ ! -f "$GUESTNET_VOID_CORE_SERVICE" ]]; then
log "guest network core-service shim not found: $GUESTNET_VOID_CORE_SERVICE"
exit 1
fi
if [[ -e "$OUT_ROOTFS" ]]; then
log "output rootfs already exists: $OUT_ROOTFS"
exit 1
@ -426,6 +488,7 @@ require_command curl
require_command tar
require_command sudo
require_command mkfs.ext4
require_command ssh-keygen
require_command mount
require_command umount
require_command install
@ -498,7 +561,11 @@ if [[ -n "$XBPS_QUERY" && -x "$XBPS_QUERY" ]]; then
sudo env XBPS_ARCH="$ARCH" "$XBPS_QUERY" -r "$ROOT_MOUNT" -l | awk '/^ii/ {print " " $2}' || true
fi
log "copying bundled kernel modules into the guest"
if [[ -n "$VOID_KERNEL_MODULES_DIR" ]]; then
log "copying staged Void kernel modules into the guest"
else
log "copying bundled kernel modules into the guest"
fi
sudo mkdir -p "$ROOT_MOUNT/lib/modules"
sudo cp -a "$MODULES_DIR" "$ROOT_MOUNT/lib/modules/"
@ -507,6 +574,7 @@ sudo mkdir -p "$ROOT_MOUNT/usr/local/bin"
sudo install -m 0755 "$VSOCK_AGENT" "$ROOT_MOUNT/usr/local/bin/banger-vsock-agent"
log "preparing SSH and runit services"
install_guest_network_bootstrap
ensure_sshd_include
enable_sshd_service
install_vsock_service
@ -516,7 +584,8 @@ normalize_root_shell
configure_root_bash_prompt
log "installing mise and opencode"
install_mise_and_opencode
sudo mkdir -p "$ROOT_MOUNT/root/.ssh"
install_opencode_service
install_root_authorized_key
sudo touch "$ROOT_MOUNT/etc/fstab" "$ROOT_MOUNT/etc/hostname"
sudo chroot "$ROOT_MOUNT" /usr/bin/ssh-keygen -A