banger hasn't shipped a public release — every "legacy", "pre-opt-in",
"previously", "migration note", "no longer" reference in the tree is
pinning against a state no real user's install has ever been in.
That scaffolding has weight: it's a coordinate system future readers
have to decode, and it keeps dead code alive.
Removed (code):
- internal/daemon/ssh_client_config.go
- vmSSHConfigIncludeBegin / vmSSHConfigIncludeEnd constants and
every `removeManagedBlock(existing, vm...)` call they enabled
(legacy inline `Host *.vm` block scrub)
- cleanupLegacySSHConfigDir (+ its caller in syncVMSSHClientConfig)
— wiped a pre-opt-in sibling file under $ConfigDir/ssh
- sameDirOrParent + resolvePathForComparison — only ever used
by cleanupLegacySSHConfigDir
- the "also check legacy marker" fallback in
UserSSHIncludeInstalled / UninstallUserSSHInclude
- internal/store/migrations.go
- migrateDropDeadImageColumns (migration 2) + its slice entry
- dropColumnIfExists (orphaned after the above)
- addColumnIfMissing + the whole "columns added across the pre-
versioning lifetime" block at the end of migrateBaseline —
subsumed into the baseline CREATE TABLE
- `packages_path TEXT` column on the images table (the
throwaway migration 2 dropped it, but there was never any
reader)
- internal/daemon/vm.go
- vmDNSRecordName local wrapper — was justified as "avoid
pulling vmdns into every file"; three of four callers already
imported vmdns directly, so inline the one stray call
- internal/cli/cli_test.go
- TestLegacyRemovedCommandIsRejected (`tui` subcommand never
shipped)
Removed / simplified (tests):
- ssh_client_config_test.go: dropped TestSameDirOrParentHandlesSymlinks,
TestSyncVMSSHClientConfigPreservesUserKeyInLegacyDir,
TestSyncVMSSHClientConfigNarrowsCleanupToLegacyFile,
TestSyncVMSSHClientConfigLeavesUnexpectedLegacyContents,
TestInstallUserSSHIncludeMigratesLegacyInlineBlock, plus the
"legacy posture" regression strings in the remaining happy-path
test; TestUninstallUserSSHIncludeRemovesBothMarkerBlocks collapsed
to a single-block test
- migrations_test.go: dropped TestMigrateDropDeadImageColumns_AcrossInstallPaths,
TestDropColumnIfExistsIsIdempotent; TestOpenReadOnlyDoesNotRunMigrations
simplified to test against the baseline marker
Removed (docs):
- README.md "**Migration note.**" blockquote about the SSH-key path move
- docs/advanced.md parenthetical "(the old behaviour)"
Reworded (comments):
- Dropped "Previously this file also contained LogLevel DEBUG3..."
history from vm_disk.go's sshdGuestConfig doc
- Dropped "Call sites that previously read vm.Runtime.{PID,...}"
from vm_handles.go; now documents the current contract
- Dropped "Pre-v0.1 the defaults are" scaffolding in doctor_test.go
- Dropped "no longer does its own git inspection" phrasing in vm_run.go
- Dropped the "(also cleans up legacy inline block from pre-opt-in
builds)" aside on the `ssh-config` CLI docstring
- Renamed test var `legacyKey` → `existingKey` in vm_test.go; its
purpose was "pre-existing authorized_keys line," not banger-legacy
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3.1 KiB
Advanced flows
banger vm run covers the common sandbox case. This doc is for the
rest: scripting, arbitrary images, custom rootfs stacks, long-lived
guest processes.
vm create — the low-level primitive
Use when you want to provision without starting, or when you need to script VM creation piecewise.
banger vm create --image debian-bookworm --name testbox --no-start
banger vm start testbox
banger vm ssh testbox
banger vm stop testbox
banger vm delete testbox
Sweep every non-running VM (stopped, created, error) with:
banger vm prune # interactive confirmation
banger vm prune -f # skip the prompt
vm create is synchronous by default, but on a TTY it shows live
progress until the VM is fully ready.
image pull <oci-ref> — arbitrary container images
For images outside banger's catalog, pull from any OCI registry:
banger image pull docker.io/library/alpine:3.20 --kernel-ref generic-6.12
Layers are flattened, ownership is fixed (setuid binaries, root-owned
config preserved), banger's guest agents are injected, and a first-boot
systemd service installs openssh-server via the guest's package
manager so the VM is reachable on first boot.
See docs/oci-import.md for supported distros,
caveats, and the internal/imagepull design.
image register — existing host-side stack
If you already have an ext4 rootfs, a kernel, optional initrd, and optional modules as files on disk:
banger image register --name base \
--rootfs /abs/path/rootfs.ext4 \
--kernel-ref generic-6.12
You can mix --kernel-ref (a cataloged kernel) with --rootfs from
disk, or pass --kernel /abs/path/vmlinux for a one-off kernel.
For reproducible custom images, write a Dockerfile and publish it to
an image catalog. See docs/image-catalog.md.
Workspace primitive
vm run ./repo (see README) handles the common case. For a manual
flow against an already-running VM, vm workspace prepare
materialises a local git checkout into the guest:
banger vm workspace prepare <vm> ./other-repo --guest-path /root/repo
Default guest path is /root/repo; default mode is a shallow
metadata copy plus a tracked-files overlay. Untracked files are
skipped by default — pass --include-untracked to ship untracked
non-ignored files too. Pass --dry-run to list the exact file set
without touching the guest. For repositories with submodules, pass
--mode full_copy.
Inspecting boot failures
When a VM's create flow errors ("ssh did not come up within 90s" or similar), the VM is kept alive for inspection:
banger vm logs <name>— the firecracker serial console output, the best window into a stuck boot (systemd unit failures, kernel panics, missing modules).banger vm ports <name>— what's listening in the guest. Works as long as banger's vsock agent has come up, even if SSH is wedged.banger vm show <name>— daemon-side state (IP, PID, overlay paths).
--rm on vm run intentionally does NOT fire when the initial ssh
wait times out, so the VM stays around for post-mortem.