Reorganize the source checkout layout

Separate tracked source from generated artifacts so the repo root stops accumulating helper scripts, manifests, and local runtime outputs.

Move manual shell entrypoints under scripts/, manifests under config/, and the Firecracker API reference under docs/reference/. Make build and runtimebundle now target build/bin, build/runtime, and build/dist as the canonical source-checkout paths.

Update runtime discovery, helper scripts, tests, and docs to follow the new layout while keeping legacy source-checkout runtime fallbacks for existing local bundles during migration.

Validated with bash -n on the moved scripts, make build, and GOCACHE=/tmp/banger-gocache go test ./....
This commit is contained in:
Thales Maciel 2026-03-21 17:22:57 -03:00
parent 2362d0ae39
commit 01c7cb5e65
No known key found for this signature in database
GPG key ID: 33112E6833C34679
23 changed files with 296 additions and 186 deletions

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
state/
/build/
/runtime/
/dist/
/banger

View file

@ -4,28 +4,28 @@
- `cmd/banger` and `cmd/bangerd` are the primary user-facing entrypoints.
- `internal/` contains the daemon, CLI, RPC, storage, Firecracker, and system integration code.
- The VM lifecycle is now organized around daemon capabilities plus a structured guest-config builder. New host-integrated VM features should plug into that Go path instead of adding more one-off branches through `internal/daemon/vm.go`.
- `customize.sh`, `make-rootfs.sh`, and `interactive.sh` remain as manual rootfs/customization helpers; normal VM lifecycle, NAT, `.vm` DNS, and daemon-driven image builds are handled by the Go control plane.
- Source checkouts use a generated `./runtime/` bundle for Firecracker, kernels, modules, rootfs images, and helper copies. Bundle defaults come from `./runtime/bundle.json` when present. Those runtime artifacts are not meant to be tracked directly in Git.
- `scripts/customize.sh`, `scripts/make-rootfs.sh`, and `scripts/interactive.sh` remain as manual rootfs/customization helpers; normal VM lifecycle, NAT, `.vm` DNS, and daemon-driven image builds are handled by the Go control plane.
- Source checkouts use a generated `./build/runtime/` bundle for Firecracker, kernels, modules, rootfs images, and helper copies. Bundle defaults come from `./build/runtime/bundle.json` when present. Those runtime artifacts are not meant to be tracked directly in Git.
- The daemon keeps state under XDG directories rather than the old repo-local `state/` layout.
## Build, Test, and Development Commands
- `make build` builds `./banger`, `./bangerd`, and the bundled `./runtime/banger-vsock-agent` guest helper.
- `make build` builds `./build/bin/banger`, `./build/bin/bangerd`, and the bundled `./build/runtime/banger-vsock-agent` guest helper.
- `make bench-create` benchmarks `vm create` and first-SSH readiness on the current host.
- `make runtime-bundle` bootstraps `./runtime/` from the archive referenced by `RUNTIME_MANIFEST`; the checked-in `runtime-bundle.toml` is only a template.
- `make void-kernel` downloads and stages a Void `linux6.12` kernel under `./runtime/void-kernel`, including extracted `vmlinux`, raw `vmlinuz`, a matching generated `initramfs`, config, and matching modules.
- `make rootfs-void` builds an experimental local-only `x86_64-glibc` Void rootfs plus work-seed under `./runtime/`; it prefers staged `./runtime/void-kernel` modules when present, but does not replace the default Debian path or teach `banger image build` about Void.
- `make runtime-bundle` bootstraps `./build/runtime/` from the archive referenced by `RUNTIME_MANIFEST`; the checked-in `config/runtime-bundle.toml` is only a template.
- `make void-kernel` downloads and stages a Void `linux6.12` kernel under `./build/runtime/void-kernel`, including extracted `vmlinux`, raw `vmlinuz`, a matching generated `initramfs`, config, and matching modules.
- `make rootfs-void` builds an experimental local-only `x86_64-glibc` Void rootfs plus work-seed under `./build/runtime/`; it prefers staged `./build/runtime/void-kernel` modules when present, but does not replace the default Debian path or teach `banger image build` about Void.
- `make verify-void` registers `void-exp` and runs the normal smoke test against that image.
- `banger` validates required host tools per command and reports actionable missing-tool errors; do not assume one workstation's package set.
- `./banger vm create --name testbox` creates and starts a VM.
- `./banger vm create` now blocks until the guest reaches the daemon's default readiness checks and shows live progress stages on TTY stderr while it waits.
- `./banger vm ssh testbox` connects to a running guest using the runtime bundle SSH key and reminds the user if the VM is still running when the session exits.
- `./banger vm stop testbox` stops a VM while preserving its disks.
- `./banger vm stop vm-a vm-b vm-c` and `./banger vm set --nat web-1 web-2` are supported; multi-VM lifecycle and `set` actions fan out concurrently through the CLI.
- `./banger doctor` reports runtime bundle, host tool, feature, and image-build readiness from the same Go checks used by the daemon.
- `./banger image register --name local --rootfs /abs/path/rootfs.ext4` creates or updates an unmanaged image record without changing the default image config; use it for experimental guest iteration paths such as Void.
- `./build/bin/banger vm create --name testbox` creates and starts a VM.
- `./build/bin/banger vm create` now blocks until the guest reaches the daemon's default readiness checks and shows live progress stages on TTY stderr while it waits.
- `./build/bin/banger vm ssh testbox` connects to a running guest using the runtime bundle SSH key and reminds the user if the VM is still running when the session exits.
- `./build/bin/banger vm stop testbox` stops a VM while preserving its disks.
- `./build/bin/banger vm stop vm-a vm-b vm-c` and `./build/bin/banger vm set --nat web-1 web-2` are supported; multi-VM lifecycle and `set` actions fan out concurrently through the CLI.
- `./build/bin/banger doctor` reports runtime bundle, host tool, feature, and image-build readiness from the same Go checks used by the daemon.
- `./build/bin/banger image register --name local --rootfs /abs/path/rootfs.ext4` creates or updates an unmanaged image record without changing the default image config; use it for experimental guest iteration paths such as Void.
- `bangerd` now also serves a localhost web UI on `http://127.0.0.1:7777` by default unless `web_listen_addr = ""` disables it; the UI uses server-rendered templates, polls async VM/image operations, and keeps image path selection on the host via a server-side file picker.
- `make test` runs `go test ./...`.
- `./verify.sh` runs the smoke test for the Go VM workflow.
- `./scripts/verify.sh` runs the smoke test for the Go VM workflow.
## Coding Style & Naming Conventions
- Go code should stay small, direct, and standard-library-first unless there is a clear reason otherwise.
@ -35,15 +35,15 @@
## Testing Guidelines
- Primary automated coverage is `go test ./...`.
- Manual verification for VM lifecycle changes: `./banger vm create`, confirm SSH access, then stop/delete the VM.
- For host-integration changes, run `./banger doctor` as a quick readiness check before the live VM smoke.
- Manual verification for VM lifecycle changes: `./build/bin/banger vm create`, confirm SSH access, then stop/delete the VM.
- For host-integration changes, run `./build/bin/banger doctor` as a quick readiness check before the live VM smoke.
- The web UI follows the same sudo model as the CLI path: bangerd stays unprivileged and privileged writes only work when `sudo -v` is already warm or sudo is passwordless.
- Rebuilt images now include `mise`, `opencode`, a host-reachable default `opencode` server service on guest TCP port `4096`, `tmux-resurrect`/`tmux-continuum` defaults for `root`, and the `banger-vsock-agent` service used by the SSH reminder and guest health-check path; if you change guest provisioning, document whether users need to rebuild `./runtime/rootfs-docker.ext4` or another base image to pick it up.
- The experimental Void rootfs path now includes the repo's basic dev baseline plus Docker and Compose, alongside boot, SSH, a guest network bootstrap sourced from the kernel `ip=` cmdline, the vsock HTTP health agent, pinned `mise` plus `opencode` for `root`, the default host-reachable `opencode` server service on guest TCP port `4096`, a `bash` root shell while leaving `/bin/sh` alone, and the `/root` work-seed. When `./runtime/void-kernel/` exists, the Void image registration path expects a complete staged Void kernel, initramfs, and modules tree and points `void-exp` at it. Keep further baked-in tooling deliberate and user-driven.
- Rebuilt images now include `mise`, `opencode`, a host-reachable default `opencode` server service on guest TCP port `4096`, `tmux-resurrect`/`tmux-continuum` defaults for `root`, and the `banger-vsock-agent` service used by the SSH reminder and guest health-check path; if you change guest provisioning, document whether users need to rebuild `./build/runtime/rootfs-docker.ext4` or another base image to pick it up.
- The experimental Void rootfs path now includes the repo's basic dev baseline plus Docker and Compose, alongside boot, SSH, a guest network bootstrap sourced from the kernel `ip=` cmdline, the vsock HTTP health agent, pinned `mise` plus `opencode` for `root`, the default host-reachable `opencode` server service on guest TCP port `4096`, a `bash` root shell while leaving `/bin/sh` alone, and the `/root` work-seed. When `./build/runtime/void-kernel/` exists, the Void image registration path expects a complete staged Void kernel, initramfs, and modules tree and points `void-exp` at it. Keep further baked-in tooling deliberate and user-driven.
- Rebuilt images also emit a `work-seed.ext4` sidecar used to speed up future VM creates. Older managed images may take one slower create to refresh seeded SSH access before they rejoin the fast path. If you touch `/root` provisioning, verify both the rootfs and the work-seed output.
- The daemon may keep idle TAP devices in a pool for faster creates. Smoke tests should treat `tap-pool-*` devices as reusable capacity, not cleanup leaks.
- If you add a new operational workflow, document how to exercise it in `README.md`.
- For NAT changes, verify both guest outbound access and host rule cleanup, for example with `./verify.sh --nat`.
- For NAT changes, verify both guest outbound access and host rule cleanup, for example with `./scripts/verify.sh --nat`.
## Commit & Pull Request Guidelines
- Git history uses short, imperative subjects.

View file

@ -8,10 +8,14 @@ BINDIR ?= $(PREFIX)/bin
LIBDIR ?= $(PREFIX)/lib
RUNTIMEDIR ?= $(LIBDIR)/banger
DESTDIR ?=
RUNTIME_MANIFEST ?= runtime-bundle.toml
RUNTIME_SOURCE_DIR ?= runtime
RUNTIME_ARCHIVE ?= dist/banger-runtime.tar.gz
BINARIES := banger bangerd
BUILD_DIR ?= build
BUILD_BIN_DIR ?= $(BUILD_DIR)/bin
RUNTIME_MANIFEST ?= config/runtime-bundle.toml
RUNTIME_SOURCE_DIR ?= $(BUILD_DIR)/runtime
RUNTIME_ARCHIVE ?= $(BUILD_DIR)/dist/banger-runtime.tar.gz
BANGER_BIN ?= $(BUILD_BIN_DIR)/banger
BANGERD_BIN ?= $(BUILD_BIN_DIR)/bangerd
BINARIES := $(BANGER_BIN) $(BANGERD_BIN)
RUNTIME_HELPERS := $(RUNTIME_SOURCE_DIR)/banger-vsock-agent
GO_SOURCES := $(shell find cmd internal -type f -name '*.go' | sort)
RUNTIME_EXECUTABLES := firecracker customize.sh packages.sh namegen banger-vsock-agent
@ -29,8 +33,8 @@ VOID_VM_NAME ?= void-dev
help:
@printf '%s\n' \
'Targets:' \
' make build Build ./banger and ./bangerd' \
' make runtime-bundle Fetch and unpack ./runtime from the archive referenced by $(RUNTIME_MANIFEST)' \
' make build Build ./build/bin/banger and ./build/bin/bangerd' \
' make runtime-bundle Fetch and unpack ./build/runtime from the archive referenced by $(RUNTIME_MANIFEST)' \
' make runtime-package Package $(RUNTIME_SOURCE_DIR) into $(RUNTIME_ARCHIVE) and print its SHA256' \
' make bench-create Benchmark vm create and SSH readiness with scripts/bench-create.sh' \
' make install Build and install binaries plus the runtime bundle into $(DESTDIR)$(BINDIR) and $(DESTDIR)$(RUNTIMEDIR)' \
@ -38,20 +42,22 @@ help:
' make fmt Format Go sources under cmd/ and internal/' \
' make tidy Run go mod tidy' \
' make clean Remove built Go binaries' \
' make rootfs Rebuild the source-checkout default Debian rootfs image in ./runtime' \
' make void-kernel Download and stage a Void kernel, initramfs, and modules under ./runtime/void-kernel' \
' make rootfs-void Build an experimental Void Linux rootfs and work-seed in ./runtime' \
' make rootfs Rebuild the source-checkout default Debian rootfs image in ./build/runtime' \
' make void-kernel Download and stage a Void kernel, initramfs, and modules under ./build/runtime/void-kernel' \
' make rootfs-void Build an experimental Void Linux rootfs and work-seed in ./build/runtime' \
' make void-register Register or update the experimental Void image as $(VOID_IMAGE_NAME)' \
' make void-vm Register the experimental Void image and create a VM named $(VOID_VM_NAME)' \
' make verify-void Register the experimental Void image and run verify.sh against it'
' make verify-void Register the experimental Void image and run scripts/verify.sh against it'
build: $(BINARIES) $(RUNTIME_HELPERS)
banger: $(GO_SOURCES) go.mod go.sum
$(GO) build -o ./banger ./cmd/banger
$(BANGER_BIN): $(GO_SOURCES) go.mod go.sum
mkdir -p "$(BUILD_BIN_DIR)"
$(GO) build -o "$(BANGER_BIN)" ./cmd/banger
bangerd: $(GO_SOURCES) go.mod go.sum
$(GO) build -o ./bangerd ./cmd/bangerd
$(BANGERD_BIN): $(GO_SOURCES) go.mod go.sum
mkdir -p "$(BUILD_BIN_DIR)"
$(GO) build -o "$(BANGERD_BIN)" ./cmd/bangerd
$(RUNTIME_SOURCE_DIR)/banger-vsock-agent: $(GO_SOURCES) go.mod go.sum
mkdir -p "$(RUNTIME_SOURCE_DIR)"
@ -67,7 +73,8 @@ tidy:
$(GO) mod tidy
clean:
rm -f ./banger ./bangerd
rm -rf "$(BUILD_BIN_DIR)"
rm -f "$(RUNTIME_SOURCE_DIR)/banger-vsock-agent"
runtime-bundle:
$(GO) run ./cmd/runtimebundle fetch --manifest "$(RUNTIME_MANIFEST)" --out "$(RUNTIME_SOURCE_DIR)"
@ -76,7 +83,7 @@ runtime-package:
$(GO) run ./cmd/runtimebundle package --manifest "$(RUNTIME_MANIFEST)" --runtime-dir "$(RUNTIME_SOURCE_DIR)" --out "$(RUNTIME_ARCHIVE)"
bench-create: build
bash ./scripts/bench-create.sh $(ARGS)
BANGER_BIN="$(abspath $(BANGER_BIN))" bash ./scripts/bench-create.sh $(ARGS)
check-runtime:
@test -d "$(RUNTIME_SOURCE_DIR)" || { echo "missing runtime bundle directory: $(RUNTIME_SOURCE_DIR); run 'make runtime-bundle'" >&2; exit 1; }
@ -89,8 +96,8 @@ install: build check-runtime
mkdir -p "$(DESTDIR)$(RUNTIMEDIR)"
mkdir -p "$(DESTDIR)$(RUNTIMEDIR)/wtf/root/boot"
mkdir -p "$(DESTDIR)$(RUNTIMEDIR)/wtf/root/lib/modules"
$(INSTALL) -m 0755 ./banger "$(DESTDIR)$(BINDIR)/banger"
$(INSTALL) -m 0755 ./bangerd "$(DESTDIR)$(BINDIR)/bangerd"
$(INSTALL) -m 0755 "$(BANGER_BIN)" "$(DESTDIR)$(BINDIR)/banger"
$(INSTALL) -m 0755 "$(BANGERD_BIN)" "$(DESTDIR)$(BINDIR)/bangerd"
@for path in $(RUNTIME_EXECUTABLES); do \
$(INSTALL) -m 0755 "$(RUNTIME_SOURCE_DIR)/$$path" "$(DESTDIR)$(RUNTIMEDIR)/$$path"; \
done
@ -106,19 +113,19 @@ install: build check-runtime
cp -a "$(RUNTIME_SOURCE_DIR)/$(RUNTIME_MODULES_DIR)" "$(DESTDIR)$(RUNTIMEDIR)/wtf/root/lib/modules/"
rootfs:
BANGER_RUNTIME_DIR="$(abspath $(RUNTIME_SOURCE_DIR))" ./make-rootfs.sh
BANGER_RUNTIME_DIR="$(abspath $(RUNTIME_SOURCE_DIR))" ./scripts/make-rootfs.sh
void-kernel:
BANGER_RUNTIME_DIR="$(abspath $(RUNTIME_SOURCE_DIR))" ./make-void-kernel.sh
BANGER_RUNTIME_DIR="$(abspath $(RUNTIME_SOURCE_DIR))" ./scripts/make-void-kernel.sh
rootfs-void:
BANGER_RUNTIME_DIR="$(abspath $(RUNTIME_SOURCE_DIR))" ./make-rootfs-void.sh
BANGER_RUNTIME_DIR="$(abspath $(RUNTIME_SOURCE_DIR))" ./scripts/make-rootfs-void.sh
void-register: build
BANGER_RUNTIME_DIR="$(abspath $(RUNTIME_SOURCE_DIR))" VOID_IMAGE_NAME="$(VOID_IMAGE_NAME)" BANGER_BIN="$(abspath ./banger)" ./register-void-image.sh
BANGER_RUNTIME_DIR="$(abspath $(RUNTIME_SOURCE_DIR))" VOID_IMAGE_NAME="$(VOID_IMAGE_NAME)" BANGER_BIN="$(abspath $(BANGER_BIN))" ./scripts/register-void-image.sh
void-vm: void-register
./banger vm create --image "$(VOID_IMAGE_NAME)" --name "$(VOID_VM_NAME)"
"$(abspath $(BANGER_BIN))" vm create --image "$(VOID_IMAGE_NAME)" --name "$(VOID_VM_NAME)"
verify-void: void-register
./verify.sh --image "$(VOID_IMAGE_NAME)"
BANGER_BIN="$(abspath $(BANGER_BIN))" ./scripts/verify.sh --image "$(VOID_IMAGE_NAME)"

102
README.md
View file

@ -17,7 +17,7 @@ assuming one workstation layout.
## Runtime Bundle
Runtime artifacts are no longer tracked directly in Git. Source checkouts use a
generated `./runtime/` bundle, while installed binaries use
generated `./build/runtime/` bundle, while installed binaries use
`$(prefix)/lib/banger`.
The bundle contains:
@ -34,30 +34,30 @@ The bundle contains:
- the helper scripts used by manual customization and installs
Bootstrap a source checkout from a local or published runtime archive. The
checked-in [`runtime-bundle.toml`](/home/thales/projects/personal/banger/runtime-bundle.toml)
checked-in [`config/runtime-bundle.toml`](/home/thales/projects/personal/banger/config/runtime-bundle.toml)
is a template and intentionally ships with empty `url` and `sha256`.
If you need to create a local archive first, do that from a checkout or machine
that already has a populated `./runtime/` tree:
that already has a populated `./build/runtime/` tree:
```bash
make runtime-package
cp dist/banger-runtime.tar.gz /path/to/fresh-checkout/dist/
cp build/dist/banger-runtime.tar.gz /path/to/fresh-checkout/build/dist/
```
In the fresh checkout:
```bash
cp runtime-bundle.toml runtime-bundle.local.toml
cp config/runtime-bundle.toml config/runtime-bundle.local.toml
```
Edit `runtime-bundle.local.toml` to point at the staged archive and checksum:
Edit `config/runtime-bundle.local.toml` to point at the staged archive and checksum:
```toml
url = "./dist/banger-runtime.tar.gz"
url = "./build/dist/banger-runtime.tar.gz"
sha256 = "<sha256 printed by make runtime-package>"
```
Then bootstrap `./runtime/` with the local manifest copy:
Then bootstrap `./build/runtime/` with the local manifest copy:
```bash
make runtime-bundle RUNTIME_MANIFEST=runtime-bundle.local.toml
make runtime-bundle RUNTIME_MANIFEST=config/runtime-bundle.local.toml
```
`url` may be a relative path, absolute path, `file:///...` URL, or HTTP(S)
@ -68,8 +68,19 @@ URL. `make install` will not fetch artifacts for you.
make build
```
Run `make build` after `./runtime/` has been bootstrapped. It also rebuilds the
bundled `banger-vsock-agent` guest helper in `./runtime/`.
Run `make build` after `./build/runtime/` has been bootstrapped. It writes
`./build/bin/banger`, `./build/bin/bangerd`, and refreshes the bundled
`banger-vsock-agent` guest helper in `./build/runtime/`.
Older ignored root artifacts such as `./runtime/`, `./banger`, and `./bangerd`
are no longer the canonical source-checkout layout. Leave them alone if you
still need them, or remove them manually after migrating to `build/`.
If you have confirmed your current images and runtime settings no longer point
at the old checkout-local paths, a one-time cleanup looks like:
```bash
rm -rf ./runtime ./banger ./bangerd
```
Install into `~/.local/bin` by default, with the runtime bundle under
`~/.local/lib/banger`:
@ -178,8 +189,9 @@ State lives under XDG directories:
- runtime socket: `$XDG_RUNTIME_DIR/banger/bangerd.sock`
Installed binaries resolve their runtime bundle from `../lib/banger` relative to
the executable. Source-checkout binaries resolve it from `./runtime` next to the
repo-built `./banger`. You can override either with `runtime_dir` in
the executable. Source-checkout binaries resolve it from `./build/runtime` next
to `./build/bin/banger`, and still fall back to a legacy `./runtime` checkout
bundle if that exists. You can override either with `runtime_dir` in
`~/.config/banger/config.toml` or `BANGER_RUNTIME_DIR`.
Useful config keys:
@ -323,32 +335,32 @@ shell helpers treated as manual workflows rather than architecture drivers.
- Stopping a VM preserves its overlay and work disk.
## Rebuilding The Repo Default Rootfs
`packages.apt` controls the base apt packages baked into rebuilt images,
`config/packages.apt` controls the base apt packages baked into rebuilt images,
including guest tools such as `ss` used by `banger vm ports`.
To rebuild the source-checkout default image in `./runtime/rootfs-docker.ext4`:
To rebuild the source-checkout default image in `./build/runtime/rootfs-docker.ext4`:
```bash
make rootfs
```
That rebuild also regenerates `./runtime/rootfs-docker.work-seed.ext4`, which
That rebuild also regenerates `./build/runtime/rootfs-docker.work-seed.ext4`, which
the daemon uses to speed up future `vm create` calls, and bakes in the default
host-reachable `opencode` server service.
If your runtime bundle does not include `./runtime/rootfs.ext4`, pass an
If your runtime bundle does not include `./build/runtime/rootfs.ext4`, pass an
explicit base image instead:
```bash
./make-rootfs.sh --base-rootfs /path/to/base-rootfs.ext4
./scripts/make-rootfs.sh --base-rootfs /path/to/base-rootfs.ext4
```
If the package manifest changed and you want a fresh source-checkout image:
```bash
rm -f ./runtime/rootfs-docker.ext4 ./runtime/rootfs-docker.ext4.packages.sha256
rm -f ./build/runtime/rootfs-docker.ext4 ./build/runtime/rootfs-docker.ext4.packages.sha256
make rootfs
```
`make rootfs` expects a bootstrapped runtime bundle. If `./runtime/rootfs.ext4`
is not available, pass an explicit `--base-rootfs` to `./make-rootfs.sh`.
`make rootfs` expects a bootstrapped runtime bundle. If `./build/runtime/rootfs.ext4`
is not available, pass an explicit `--base-rootfs` to `./scripts/make-rootfs.sh`.
Existing VMs keep using their current image and disks; rebuilds only affect VMs
created from the rebuilt image afterward. Restarting an existing VM is not
enough to pick up guest provisioning changes such as the default `opencode`
@ -363,13 +375,13 @@ make rootfs-void
```
That writes:
- `./runtime/void-kernel/` when `make void-kernel` is used
- `./runtime/rootfs-void.ext4`
- `./runtime/rootfs-void.work-seed.ext4`
- `./build/runtime/void-kernel/` when `make void-kernel` is used
- `./build/runtime/rootfs-void.ext4`
- `./build/runtime/rootfs-void.work-seed.ext4`
This path is intentionally local-only and does not change the default Debian
image flow. `make void-kernel` stages an actual Void `linux6.12` kernel package
under `./runtime/void-kernel/`, including the raw `vmlinuz`, extracted
under `./build/runtime/void-kernel/`, including the raw `vmlinuz`, extracted
Firecracker `vmlinux`, a matching `initramfs`, the matching config, and the
matching modules tree. The initramfs is generated locally with `dracut`
against the downloaded Void sysroot so the kernel, initrd, and modules stay
@ -395,11 +407,11 @@ The builder fetches official static XBPS tools and packages from the Void
mirror during the build. The kernel fetcher and rootfs builder currently
support only `x86_64`.
The package set comes from [`packages.void`](/home/thales/projects/personal/banger/packages.void).
The package set comes from [`config/packages.void`](/home/thales/projects/personal/banger/config/packages.void).
You can override the mirror, size, output path, or kernel package directly:
```bash
./make-void-kernel.sh --kernel-package linux6.12
./make-rootfs-void.sh --mirror https://repo-default.voidlinux.org --size 2G
./scripts/make-void-kernel.sh --kernel-package linux6.12
./scripts/make-rootfs-void.sh --mirror https://repo-default.voidlinux.org --size 2G
```
The fastest local iteration loop does not require changing your default image
@ -408,8 +420,8 @@ config at all:
make void-kernel
make rootfs-void
make void-register
./banger vm create --image void-exp --name void-dev
./banger vm ssh void-dev
./build/bin/banger vm create --image void-exp --name void-dev
./build/bin/banger vm ssh void-dev
```
Rebuild the staged Void kernel or Void rootfs, then recreate existing
@ -425,7 +437,7 @@ make verify-void
`make void-register` uses the unmanaged image registration path to create or
update a `void-exp` image record in place, so repeated rebuilds do not require
editing `~/.config/banger/config.toml`. It expects a complete staged Void
kernel set under `./runtime/void-kernel/` and points the experimental image at
kernel set under `./build/runtime/void-kernel/` and points the experimental image at
the staged Void `vmlinux`, `initramfs`, and matching modules tree.
There is also a one-step helper target:
@ -453,12 +465,12 @@ and package manifest:
```bash
banger image register \
--name void-exp \
--rootfs ./runtime/rootfs-void.ext4 \
--work-seed ./runtime/rootfs-void.work-seed.ext4 \
--kernel ./runtime/void-kernel/boot/vmlinux-6.12.77_1 \
--initrd ./runtime/void-kernel/boot/initramfs-6.12.77_1.img \
--modules ./runtime/void-kernel/lib/modules/6.12.77_1 \
--packages ./packages.void
--rootfs ./build/runtime/rootfs-void.ext4 \
--work-seed ./build/runtime/rootfs-void.work-seed.ext4 \
--kernel ./build/runtime/void-kernel/boot/vmlinux-6.12.77_1 \
--initrd ./build/runtime/void-kernel/boot/initramfs-6.12.77_1.img \
--modules ./build/runtime/void-kernel/lib/modules/6.12.77_1 \
--packages ./config/packages.void
```
If an unmanaged image with the same name already exists, `image register`
@ -466,17 +478,17 @@ updates it in place so future `vm create --image <name>` calls pick up the new
artifacts immediately.
## Maintaining The Runtime Bundle
The checked-in [`runtime-bundle.toml`](/home/thales/projects/personal/banger/runtime-bundle.toml)
The checked-in [`config/runtime-bundle.toml`](/home/thales/projects/personal/banger/config/runtime-bundle.toml)
is a template. Keep `bundle_metadata` accurate there, but use a separate local
manifest copy when you need concrete `url` and `sha256` values for bootstrap
testing or publication.
Package a local `./runtime/` tree into an archive:
Package a local `./build/runtime/` tree into an archive:
```bash
make runtime-package
```
That writes `dist/banger-runtime.tar.gz` and prints its SHA256 so you can update
That writes `build/dist/banger-runtime.tar.gz` and prints its SHA256 so you can update
a local manifest copy before testing bootstrap changes or publishing the
archive elsewhere.
@ -499,10 +511,10 @@ The benchmark prints JSON with:
## Remaining Shell Helpers
The runtime VM lifecycle is managed through `banger`. The remaining shell scripts are not the primary user interface:
- `customize.sh`: manual reference flow for rootfs customization; `banger image build` is now Go-native, but the script still reads
- `scripts/customize.sh`: manual reference flow for rootfs customization; `banger image build` is now Go-native, but the script still reads
assets from `BANGER_RUNTIME_DIR` and stores transient state under
`BANGER_STATE_DIR`/XDG state
- `make-rootfs.sh`: convenience wrapper for rebuilding `./runtime/rootfs-docker.ext4`
- `interactive.sh`: manual one-off rootfs customization over SSH
- `packages.sh`: shell helper library
- `verify.sh`: smoke test for the Go workflow (`./verify.sh --nat` adds NAT coverage)
- `scripts/make-rootfs.sh`: convenience wrapper for rebuilding `./build/runtime/rootfs-docker.ext4`
- `scripts/interactive.sh`: manual one-off rootfs customization over SSH
- `scripts/lib/packages.sh`: shell helper library
- `scripts/verify.sh`: smoke test for the Go workflow (`./scripts/verify.sh --nat` adds NAT coverage)

View file

@ -9,6 +9,12 @@ import (
"banger/internal/runtimebundle"
)
const (
defaultManifestPath = "config/runtime-bundle.toml"
defaultRuntimeDir = "build/runtime"
defaultArchivePath = "build/dist/banger-runtime.tar.gz"
)
func main() {
if len(os.Args) < 2 {
usage()
@ -34,8 +40,8 @@ func main() {
func fetch(args []string) error {
fs := flag.NewFlagSet("fetch", flag.ContinueOnError)
fs.SetOutput(os.Stderr)
manifestPath := fs.String("manifest", "runtime-bundle.toml", "path to the runtime bundle manifest")
outDir := fs.String("out", "runtime", "destination runtime directory")
manifestPath := fs.String("manifest", defaultManifestPath, "path to the runtime bundle manifest")
outDir := fs.String("out", defaultRuntimeDir, "destination runtime directory")
if err := fs.Parse(args); err != nil {
return err
}
@ -49,9 +55,9 @@ func fetch(args []string) error {
func pkg(args []string) error {
fs := flag.NewFlagSet("package", flag.ContinueOnError)
fs.SetOutput(os.Stderr)
manifestPath := fs.String("manifest", "runtime-bundle.toml", "path to the runtime bundle manifest")
runtimeDir := fs.String("runtime-dir", "runtime", "runtime directory to package")
outArchive := fs.String("out", "dist/banger-runtime.tar.gz", "output archive path")
manifestPath := fs.String("manifest", defaultManifestPath, "path to the runtime bundle manifest")
runtimeDir := fs.String("runtime-dir", defaultRuntimeDir, "runtime directory to package")
outArchive := fs.String("out", defaultArchivePath, "output archive path")
if err := fs.Parse(args); err != nil {
return err
}

View file

@ -1,6 +1,6 @@
# Template manifest for local or published runtime bundle archives.
# Keep this checked-in file empty by default; use a local manifest copy with
# concrete `url` and `sha256` values when bootstrapping `./runtime/`.
# concrete `url` and `sha256` values when bootstrapping `./build/runtime/`.
version = "v0"
url = ""
sha256 = ""

View file

@ -5,10 +5,10 @@
# to the Void image yet; banger image build still assumes the Debian flow.
# If you run `make void-kernel`, also merge the commented kernel/initrd/modules lines.
runtime_dir = "/abs/path/to/banger/runtime"
runtime_dir = "/abs/path/to/banger/build/runtime"
default_image_name = "void-exp"
default_rootfs = "/abs/path/to/banger/runtime/rootfs-void.ext4"
default_work_seed = "/abs/path/to/banger/runtime/rootfs-void.work-seed.ext4"
# default_kernel = "/abs/path/to/banger/runtime/void-kernel/boot/vmlinux-6.12.77_1"
# default_initrd = "/abs/path/to/banger/runtime/void-kernel/boot/initramfs-6.12.77_1.img"
# default_modules_dir = "/abs/path/to/banger/runtime/void-kernel/lib/modules/6.12.77_1"
default_rootfs = "/abs/path/to/banger/build/runtime/rootfs-void.ext4"
default_work_seed = "/abs/path/to/banger/build/runtime/rootfs-void.work-seed.ext4"
# default_kernel = "/abs/path/to/banger/build/runtime/void-kernel/boot/vmlinux-6.12.77_1"
# default_initrd = "/abs/path/to/banger/build/runtime/void-kernel/boot/initramfs-6.12.77_1.img"
# default_modules_dir = "/abs/path/to/banger/build/runtime/void-kernel/lib/modules/6.12.77_1"

View file

@ -427,7 +427,7 @@ func TestAbsolutizeImageRegisterPaths(t *testing.T) {
KernelPath: filepath.Join(".", "runtime", "vmlinux"),
InitrdPath: filepath.Join(".", "runtime", "initrd.img"),
ModulesDir: filepath.Join(".", "runtime", "modules"),
PackagesPath: filepath.Join(".", "packages.void"),
PackagesPath: filepath.Join(".", "config", "packages.void"),
}
wd, err := os.Getwd()

View file

@ -111,11 +111,11 @@ func TestEnsureDefaultImageReconcilesStaleUnmanagedDefaultInPlace(t *testing.T)
ID: "default-id",
Name: "default",
Managed: false,
RootfsPath: "/home/thales/projects/personal/banger/rootfs-docker.ext4",
KernelPath: "/home/thales/projects/personal/banger/wtf/root/boot/vmlinux-6.8.0-94-generic",
InitrdPath: "/home/thales/projects/personal/banger/wtf/root/boot/initrd.img-6.8.0-94-generic",
ModulesDir: "/home/thales/projects/personal/banger/wtf/root/lib/modules/6.8.0-94-generic",
PackagesPath: "/home/thales/projects/personal/banger/packages.apt",
RootfsPath: "/home/thales/projects/personal/banger/build/runtime/rootfs-docker.ext4",
KernelPath: "/home/thales/projects/personal/banger/build/runtime/wtf/root/boot/vmlinux-6.8.0-94-generic",
InitrdPath: "/home/thales/projects/personal/banger/build/runtime/wtf/root/boot/initrd.img-6.8.0-94-generic",
ModulesDir: "/home/thales/projects/personal/banger/build/runtime/wtf/root/lib/modules/6.8.0-94-generic",
PackagesPath: "/home/thales/projects/personal/banger/build/runtime/packages.apt",
Docker: true,
CreatedAt: now,
UpdatedAt: now,

View file

@ -86,14 +86,24 @@ func ResolveRuntimeDir(configuredRuntimeDir, deprecatedRepoRoot string) string {
}
exeDir := filepath.Dir(exe)
if filepath.Base(exeDir) == "bin" {
if filepath.Base(filepath.Dir(exeDir)) == "build" {
buildRuntimeDir := filepath.Clean(filepath.Join(exeDir, "..", "runtime"))
if HasRuntimeBundle(buildRuntimeDir) {
return buildRuntimeDir
}
}
installRuntimeDir := filepath.Clean(filepath.Join(exeDir, "..", "lib", "banger"))
if HasRuntimeBundle(installRuntimeDir) {
return installRuntimeDir
}
}
sourceRuntimeDir := filepath.Join(exeDir, "runtime")
if HasRuntimeBundle(sourceRuntimeDir) {
return sourceRuntimeDir
for _, sourceRuntimeDir := range []string{
filepath.Join(exeDir, "build", "runtime"),
filepath.Join(exeDir, "runtime"),
} {
if HasRuntimeBundle(sourceRuntimeDir) {
return sourceRuntimeDir
}
}
return ""
}
@ -141,7 +151,7 @@ func BangerdPath() (string, error) {
return candidate, nil
}
}
return "", errors.New("bangerd binary not found next to banger; build ./cmd/bangerd")
return "", errors.New("bangerd binary not found next to banger; run `make build`")
}
func RuntimeBundleHint() string {

View file

@ -35,9 +35,9 @@ func TestResolveRuntimeDirUsesInstalledLayout(t *testing.T) {
}
}
func TestResolveRuntimeDirUsesSourceCheckoutRuntimeSubdir(t *testing.T) {
func TestResolveRuntimeDirUsesBuildRuntimeForSourceCheckoutBinary(t *testing.T) {
root := t.TempDir()
runtimeDir := filepath.Join(root, "runtime")
runtimeDir := filepath.Join(root, "build", "runtime")
createRuntimeBundle(t, runtimeDir)
origExecutablePath := executablePath
@ -53,6 +53,24 @@ func TestResolveRuntimeDirUsesSourceCheckoutRuntimeSubdir(t *testing.T) {
}
}
func TestResolveRuntimeDirUsesBuildRuntimeForBuildBinExecutable(t *testing.T) {
root := t.TempDir()
runtimeDir := filepath.Join(root, "build", "runtime")
createRuntimeBundle(t, runtimeDir)
origExecutablePath := executablePath
executablePath = func() (string, error) {
return filepath.Join(root, "build", "bin", "banger"), nil
}
t.Cleanup(func() {
executablePath = origExecutablePath
})
if got := ResolveRuntimeDir("", ""); got != runtimeDir {
t.Fatalf("ResolveRuntimeDir() = %q, want %q", got, runtimeDir)
}
}
func createRuntimeBundle(t *testing.T, runtimeDir string) {
t.Helper()
metadata := runtimebundle.BundleMetadata{

View file

@ -52,7 +52,13 @@ fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
BANGER_BIN="${BANGER_BIN:-$REPO_ROOT/banger}"
if [[ -z "${BANGER_BIN:-}" ]]; then
if [[ -x "$REPO_ROOT/build/bin/banger" ]]; then
BANGER_BIN="$REPO_ROOT/build/bin/banger"
else
BANGER_BIN="$REPO_ROOT/banger"
fi
fi
if [[ ! -x "$BANGER_BIN" ]]; then
log "banger binary not found: $BANGER_BIN"
log "run 'make build' or set BANGER_BIN"

View file

@ -7,7 +7,7 @@ log() {
usage() {
cat <<'EOF'
Usage: ./customize.sh <base-rootfs> [--out <path>] [--size <size>] [--kernel <path>] [--initrd <path>] [--docker] [--modules <dir>]
Usage: ./scripts/customize.sh <base-rootfs> [--out <path>] [--size <size>] [--kernel <path>] [--initrd <path>] [--docker] [--modules <dir>]
Creates a copy of rootfs.ext4, optionally resizes it, boots a VM using the
copy as a writable rootfs, then applies base configuration and packages.
@ -30,9 +30,10 @@ parse_size() {
}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEFAULT_RUNTIME_DIR="$SCRIPT_DIR"
if [[ -d "$SCRIPT_DIR/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$SCRIPT_DIR/runtime"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
DEFAULT_RUNTIME_DIR="$REPO_ROOT/build/runtime"
if [[ ! -d "$DEFAULT_RUNTIME_DIR" && -d "$REPO_ROOT/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$REPO_ROOT/runtime"
fi
RUNTIME_DIR="${BANGER_RUNTIME_DIR:-$DEFAULT_RUNTIME_DIR}"
if [[ ! -d "$RUNTIME_DIR" ]]; then
@ -40,7 +41,7 @@ if [[ ! -d "$RUNTIME_DIR" ]]; then
log "run 'make runtime-bundle' or set BANGER_RUNTIME_DIR"
exit 1
fi
source "$RUNTIME_DIR/packages.sh"
source "$SCRIPT_DIR/lib/packages.sh"
STATE="${BANGER_STATE_DIR:-${XDG_STATE_HOME:-$HOME/.local/state}/banger/image-build}"
VM_ROOT="$STATE/vms"
mkdir -p "$VM_ROOT"
@ -83,8 +84,12 @@ resolve_banger_bin() {
printf '%s\n' "$BANGER_BIN"
return
fi
if [[ -x "$SCRIPT_DIR/banger" ]]; then
printf '%s\n' "$SCRIPT_DIR/banger"
if [[ -x "$REPO_ROOT/build/bin/banger" ]]; then
printf '%s\n' "$REPO_ROOT/build/bin/banger"
return
fi
if [[ -x "$REPO_ROOT/banger" ]]; then
printf '%s\n' "$REPO_ROOT/banger"
return
fi
if command -v banger >/dev/null 2>&1; then

View file

@ -7,7 +7,7 @@ log() {
usage() {
cat <<'EOF'
Usage: ./interactive.sh <base-rootfs> [--out <path>] [--size <size>]
Usage: ./scripts/interactive.sh <base-rootfs> [--out <path>] [--size <size>]
Creates a writable copy of the base rootfs and boots a VM so you can
customize it manually over SSH. No automatic package/config changes
@ -30,10 +30,11 @@ parse_size() {
return 1
}
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEFAULT_RUNTIME_DIR="$DIR"
if [[ -d "$DIR/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$DIR/runtime"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
DEFAULT_RUNTIME_DIR="$REPO_ROOT/build/runtime"
if [[ ! -d "$DEFAULT_RUNTIME_DIR" && -d "$REPO_ROOT/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$REPO_ROOT/runtime"
fi
RUNTIME_DIR="${BANGER_RUNTIME_DIR:-$DEFAULT_RUNTIME_DIR}"
if [[ ! -d "$RUNTIME_DIR" ]]; then
@ -77,8 +78,12 @@ resolve_banger_bin() {
printf '%s\n' "$BANGER_BIN"
return
fi
if [[ -x "$DIR/banger" ]]; then
printf '%s\n' "$DIR/banger"
if [[ -x "$REPO_ROOT/build/bin/banger" ]]; then
printf '%s\n' "$REPO_ROOT/build/bin/banger"
return
fi
if [[ -x "$REPO_ROOT/banger" ]]; then
printf '%s\n' "$REPO_ROOT/banger"
return
fi
if command -v banger >/dev/null 2>&1; then

View file

@ -1,7 +1,8 @@
#!/usr/bin/env bash
BANGER_PACKAGES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BANGER_APT_PACKAGES_FILE="${BANGER_APT_PACKAGES_FILE:-$BANGER_PACKAGES_DIR/packages.apt}"
readonly BANGER_PACKAGES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly BANGER_REPO_ROOT="$(cd "$BANGER_PACKAGES_DIR/../.." && pwd)"
BANGER_APT_PACKAGES_FILE="${BANGER_APT_PACKAGES_FILE:-$BANGER_REPO_ROOT/config/packages.apt}"
banger_packages_file() {
printf '%s' "$BANGER_APT_PACKAGES_FILE"

View file

@ -7,21 +7,21 @@ log() {
usage() {
cat <<'EOF'
Usage: ./make-rootfs-void.sh [--out <path>] [--size <size>] [--mirror <url>] [--arch <arch>] [--packages <path>]
Usage: ./scripts/make-rootfs-void.sh [--out <path>] [--size <size>] [--mirror <url>] [--arch <arch>] [--packages <path>]
Build an experimental Void Linux rootfs image plus a matching /root work-seed.
Defaults:
--out ./runtime/rootfs-void.ext4
--out ./build/runtime/rootfs-void.ext4
--size 2G
--mirror https://repo-default.voidlinux.org
--arch x86_64
--packages ./packages.void
--packages ./config/packages.void
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.
This path is experimental and local-only. If ./build/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
}
@ -53,8 +53,12 @@ resolve_banger_bin() {
printf '%s\n' "$BANGER_BIN"
return
fi
if [[ -x "$SCRIPT_DIR/banger" ]]; then
printf '%s\n' "$SCRIPT_DIR/banger"
if [[ -x "$REPO_ROOT/build/bin/banger" ]]; then
printf '%s\n' "$REPO_ROOT/build/bin/banger"
return
fi
if [[ -x "$REPO_ROOT/banger" ]]; then
printf '%s\n' "$REPO_ROOT/banger"
return
fi
if command -v banger >/dev/null 2>&1; then
@ -377,13 +381,14 @@ cleanup() {
}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PACKAGES_FILE="$SCRIPT_DIR/packages.void"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
PACKAGES_FILE="$REPO_ROOT/config/packages.void"
export BANGER_APT_PACKAGES_FILE="$PACKAGES_FILE"
source "$SCRIPT_DIR/packages.sh"
source "$SCRIPT_DIR/lib/packages.sh"
DEFAULT_RUNTIME_DIR="$SCRIPT_DIR"
if [[ -d "$SCRIPT_DIR/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$SCRIPT_DIR/runtime"
DEFAULT_RUNTIME_DIR="$REPO_ROOT/build/runtime"
if [[ ! -d "$DEFAULT_RUNTIME_DIR" && -d "$REPO_ROOT/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$REPO_ROOT/runtime"
fi
RUNTIME_DIR="${BANGER_RUNTIME_DIR:-$DEFAULT_RUNTIME_DIR}"
if [[ ! -d "$RUNTIME_DIR" ]]; then
@ -401,8 +406,8 @@ 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"
GUESTNET_BOOTSTRAP_SCRIPT="$REPO_ROOT/internal/guestnet/assets/bootstrap.sh"
GUESTNET_VOID_CORE_SERVICE="$REPO_ROOT/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")"

View file

@ -7,19 +7,25 @@ log() {
usage() {
cat <<'EOF'
Usage: ./make-rootfs.sh [--size <size>] [--base-rootfs <path>]
Usage: ./scripts/make-rootfs.sh [--size <size>] [--base-rootfs <path>]
Builds rootfs-docker.ext4 using customize.sh. If --base-rootfs is omitted,
the first existing file is used:
./rootfs.ext4
Builds build/runtime/rootfs-docker.ext4 using scripts/customize.sh. If
--base-rootfs is omitted, the first existing file is used:
./build/runtime/rootfs.ext4
./runtime/rootfs.ext4 (legacy fallback)
./ubuntu-noble-rootfs/rootfs.ext4
./ubuntu-lts/rootfs.ext4
EOF
}
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$DIR/packages.sh"
RUNTIME_DIR="${BANGER_RUNTIME_DIR:-$DIR/runtime}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
source "$SCRIPT_DIR/lib/packages.sh"
DEFAULT_RUNTIME_DIR="$REPO_ROOT/build/runtime"
if [[ ! -d "$DEFAULT_RUNTIME_DIR" && -d "$REPO_ROOT/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$REPO_ROOT/runtime"
fi
RUNTIME_DIR="${BANGER_RUNTIME_DIR:-$DEFAULT_RUNTIME_DIR}"
if [[ ! -d "$RUNTIME_DIR" ]]; then
log "runtime bundle not found: $RUNTIME_DIR"
log "run 'make runtime-bundle' or set BANGER_RUNTIME_DIR"
@ -63,10 +69,10 @@ fi
if [[ -z "$BASE_ROOTFS" ]]; then
if [[ -f "$RUNTIME_DIR/rootfs.ext4" ]]; then
BASE_ROOTFS="$RUNTIME_DIR/rootfs.ext4"
elif [[ -f "$DIR/ubuntu-noble-rootfs/rootfs.ext4" ]]; then
BASE_ROOTFS="$DIR/ubuntu-noble-rootfs/rootfs.ext4"
elif [[ -f "$DIR/ubuntu-lts/rootfs.ext4" ]]; then
BASE_ROOTFS="$DIR/ubuntu-lts/rootfs.ext4"
elif [[ -f "$REPO_ROOT/ubuntu-noble-rootfs/rootfs.ext4" ]]; then
BASE_ROOTFS="$REPO_ROOT/ubuntu-noble-rootfs/rootfs.ext4"
elif [[ -f "$REPO_ROOT/ubuntu-lts/rootfs.ext4" ]]; then
BASE_ROOTFS="$REPO_ROOT/ubuntu-lts/rootfs.ext4"
else
log "no base rootfs found; run 'make runtime-bundle' or pass --base-rootfs"
exit 1
@ -76,7 +82,7 @@ fi
mkdir -p "$RUNTIME_DIR"
log "building $OUT_ROOTFS from $BASE_ROOTFS"
exec env BANGER_RUNTIME_DIR="$RUNTIME_DIR" "$DIR/customize.sh" "$BASE_ROOTFS" \
exec env BANGER_RUNTIME_DIR="$RUNTIME_DIR" "$SCRIPT_DIR/customize.sh" "$BASE_ROOTFS" \
--out "$OUT_ROOTFS" \
--size "$SIZE_SPEC" \
--docker

View file

@ -7,13 +7,14 @@ log() {
usage() {
cat <<'EOF'
Usage: ./make-void-kernel.sh [--out-dir <path>] [--mirror <url>] [--arch <arch>] [--kernel-package <name>] [--print-register-flags]
Usage: ./scripts/make-void-kernel.sh [--out-dir <path>] [--mirror <url>] [--arch <arch>] [--kernel-package <name>] [--print-register-flags]
Download and stage a Void Linux kernel under ./runtime/void-kernel for the
Download and stage a Void Linux kernel under ./build/runtime/void-kernel for
the
experimental Void guest flow.
Defaults:
--out-dir ./runtime/void-kernel
--out-dir ./build/runtime/void-kernel
--mirror https://repo-default.voidlinux.org
--arch x86_64
--kernel-package linux6.12
@ -223,9 +224,10 @@ cleanup() {
}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEFAULT_RUNTIME_DIR="$SCRIPT_DIR"
if [[ -d "$SCRIPT_DIR/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$SCRIPT_DIR/runtime"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
DEFAULT_RUNTIME_DIR="$REPO_ROOT/build/runtime"
if [[ ! -d "$DEFAULT_RUNTIME_DIR" && -d "$REPO_ROOT/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$REPO_ROOT/runtime"
fi
RUNTIME_DIR="${BANGER_RUNTIME_DIR:-$DEFAULT_RUNTIME_DIR}"
OUT_DIR="$RUNTIME_DIR/void-kernel"
@ -282,10 +284,7 @@ if [[ "$ARCH" != "x86_64" ]]; then
log "this experimental downloader currently supports only x86_64"
exit 1
fi
if [[ ! -d "$RUNTIME_DIR" ]]; then
log "runtime bundle not found: $RUNTIME_DIR"
exit 1
fi
mkdir -p "$RUNTIME_DIR"
if [[ -e "$OUT_DIR" ]]; then
log "output directory already exists: $OUT_DIR"
log "remove it first if you want to re-stage a different Void kernel"

View file

@ -27,8 +27,12 @@ resolve_banger_bin() {
printf '%s\n' "$BANGER_BIN"
return
fi
if [[ -x "$SCRIPT_DIR/banger" ]]; then
printf '%s\n' "$SCRIPT_DIR/banger"
if [[ -x "$REPO_ROOT/build/bin/banger" ]]; then
printf '%s\n' "$REPO_ROOT/build/bin/banger"
return
fi
if [[ -x "$REPO_ROOT/banger" ]]; then
printf '%s\n' "$REPO_ROOT/banger"
return
fi
if command -v banger >/dev/null 2>&1; then
@ -40,9 +44,10 @@ resolve_banger_bin() {
}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEFAULT_RUNTIME_DIR="$SCRIPT_DIR"
if [[ -d "$SCRIPT_DIR/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$SCRIPT_DIR/runtime"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
DEFAULT_RUNTIME_DIR="$REPO_ROOT/build/runtime"
if [[ ! -d "$DEFAULT_RUNTIME_DIR" && -d "$REPO_ROOT/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$REPO_ROOT/runtime"
fi
RUNTIME_DIR="${BANGER_RUNTIME_DIR:-$DEFAULT_RUNTIME_DIR}"
@ -50,7 +55,7 @@ IMAGE_NAME="${VOID_IMAGE_NAME:-void-exp}"
BANGER_BIN="$(resolve_banger_bin)"
ROOTFS="$RUNTIME_DIR/rootfs-void.ext4"
WORK_SEED="$RUNTIME_DIR/rootfs-void.work-seed.ext4"
PACKAGES="$SCRIPT_DIR/packages.void"
PACKAGES="$REPO_ROOT/config/packages.void"
if [[ ! -f "$ROOTFS" ]]; then
log "missing Void rootfs: $ROOTFS"

View file

@ -5,10 +5,11 @@ log() {
printf '[verify] %s\n' "$*"
}
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEFAULT_RUNTIME_DIR="$DIR"
if [[ -d "$DIR/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$DIR/runtime"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
DEFAULT_RUNTIME_DIR="$REPO_ROOT/build/runtime"
if [[ ! -d "$DEFAULT_RUNTIME_DIR" && -d "$REPO_ROOT/runtime" ]]; then
DEFAULT_RUNTIME_DIR="$REPO_ROOT/runtime"
fi
RUNTIME_DIR="${BANGER_RUNTIME_DIR:-$DEFAULT_RUNTIME_DIR}"
SSH_KEY="$RUNTIME_DIR/id_ed25519"
@ -35,6 +36,29 @@ SSH_COMMON_ARGS=(
)
OPENCODE_PORT=4096
resolve_banger_bin() {
if [[ -n "${BANGER_BIN:-}" ]]; then
printf '%s\n' "$BANGER_BIN"
return
fi
if [[ -x "$REPO_ROOT/build/bin/banger" ]]; then
printf '%s\n' "$REPO_ROOT/build/bin/banger"
return
fi
if [[ -x "$REPO_ROOT/banger" ]]; then
printf '%s\n' "$REPO_ROOT/banger"
return
fi
if command -v banger >/dev/null 2>&1; then
command -v banger
return
fi
log "banger binary not found; run 'make build' or set BANGER_BIN"
exit 1
}
BANGER_BIN="$(resolve_banger_bin)"
firecracker_running() {
local pid="$1"
local api_sock="$2"
@ -85,7 +109,7 @@ wait_for_tcp() {
}
refresh_vm_metadata() {
if ! VM_JSON="$(./banger vm show "$VM_NAME" 2>/dev/null)"; then
if ! VM_JSON="$("$BANGER_BIN" vm show "$VM_NAME" 2>/dev/null)"; then
return 1
fi
TAP="$(printf '%s\n' "$VM_JSON" | jq -r '.runtime.tap_device // empty')"
@ -125,13 +149,13 @@ wait_for_vm_ready() {
dump_diagnostics() {
log "diagnostics for $VM_NAME"
./banger vm show "$VM_NAME" || true
"$BANGER_BIN" vm show "$VM_NAME" || true
if [[ "${PID:-0}" -gt 0 ]]; then
log "process state for pid $PID"
ps -fp "$PID" || true
fi
log "recent firecracker log"
./banger vm logs "$VM_NAME" 2>/dev/null | tail -n 200 || true
"$BANGER_BIN" vm logs "$VM_NAME" 2>/dev/null | tail -n 200 || true
if [[ -f "$DAEMON_LOG" ]]; then
log "recent daemon log"
tail -n 200 "$DAEMON_LOG" || true
@ -153,7 +177,7 @@ dump_diagnostics() {
usage() {
cat <<'EOF'
Usage: ./verify.sh [--nat] [--image <name>]
Usage: ./scripts/verify.sh [--nat] [--image <name>]
Run a basic smoke test for the Go VM workflow.
Use --nat to additionally verify outbound NAT and host rule cleanup.
@ -198,20 +222,20 @@ LAST_ERROR=""
delete_vm() {
if [[ -n "${VM_NAME:-}" ]]; then
./banger vm delete "$VM_NAME"
"$BANGER_BIN" vm delete "$VM_NAME"
fi
}
cleanup() {
if [[ -n "${VM_NAME:-}" ]]; then
./banger vm delete "$VM_NAME" >/dev/null 2>&1 || true
"$BANGER_BIN" vm delete "$VM_NAME" >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT
log "starting VM"
CREATE_ARGS=(./banger vm create --name "$VM_NAME")
CREATE_ARGS=("$BANGER_BIN" vm create --name "$VM_NAME")
if [[ -n "$IMAGE_NAME" ]]; then
CREATE_ARGS+=(--image "$IMAGE_NAME")
fi
@ -267,7 +291,7 @@ if ! wait_for_tcp "$GUEST_IP" "$OPENCODE_PORT" "$BOOT_DEADLINE"; then
fi
log "asserting opencode port is reported by banger vm ports"
if ! ./banger vm ports "$VM_NAME" | grep -F ":${OPENCODE_PORT}" >/dev/null 2>&1; then
if ! "$BANGER_BIN" vm ports "$VM_NAME" | grep -F ":${OPENCODE_PORT}" >/dev/null 2>&1; then
log "banger vm ports did not report ${OPENCODE_PORT}"
dump_diagnostics
exit 1
@ -286,7 +310,7 @@ if ! delete_vm; then
fi
log "asserting cleanup success"
if ./banger vm show "$VM_NAME" >/dev/null 2>&1; then
if "$BANGER_BIN" vm show "$VM_NAME" >/dev/null 2>&1; then
log "vm still exists after delete: $VM_NAME"
exit 1
fi