From 01c7cb5e6594db18c978bc060dc681279de3eff1 Mon Sep 17 00:00:00 2001 From: Thales Maciel Date: Sat, 21 Mar 2026 17:22:57 -0300 Subject: [PATCH] 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 ./.... --- .gitignore | 1 + AGENTS.md | 38 +++---- Makefile | 55 +++++----- README.md | 102 ++++++++++-------- cmd/runtimebundle/main.go | 16 ++- packages.apt => config/packages.apt | 0 packages.void => config/packages.void | 0 .../runtime-bundle.toml | 2 +- .../reference/firecracker-api.yaml | 0 examples/void-exp.config.toml | 12 +-- internal/cli/cli_test.go | 2 +- internal/daemon/daemon_test.go | 10 +- internal/paths/paths.go | 18 +++- internal/paths/paths_test.go | 22 +++- scripts/bench-create.sh | 8 +- customize.sh => scripts/customize.sh | 19 ++-- interactive.sh => scripts/interactive.sh | 19 ++-- packages.sh => scripts/lib/packages.sh | 5 +- .../make-rootfs-void.sh | 37 ++++--- make-rootfs.sh => scripts/make-rootfs.sh | 30 +++--- .../make-void-kernel.sh | 19 ++-- .../register-void-image.sh | 17 +-- verify.sh => scripts/verify.sh | 50 ++++++--- 23 files changed, 296 insertions(+), 186 deletions(-) rename packages.apt => config/packages.apt (100%) rename packages.void => config/packages.void (100%) rename runtime-bundle.toml => config/runtime-bundle.toml (92%) rename firecracker-api.yaml => docs/reference/firecracker-api.yaml (100%) rename customize.sh => scripts/customize.sh (96%) rename interactive.sh => scripts/interactive.sh (93%) rename packages.sh => scripts/lib/packages.sh (92%) rename make-rootfs-void.sh => scripts/make-rootfs-void.sh (93%) rename make-rootfs.sh => scripts/make-rootfs.sh (57%) rename make-void-kernel.sh => scripts/make-void-kernel.sh (95%) rename register-void-image.sh => scripts/register-void-image.sh (82%) rename verify.sh => scripts/verify.sh (85%) diff --git a/.gitignore b/.gitignore index 1a13dc5..4aad341 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ state/ +/build/ /runtime/ /dist/ /banger diff --git a/AGENTS.md b/AGENTS.md index 2f547b3..5cfea46 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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. diff --git a/Makefile b/Makefile index 36ee25c..50a17fa 100644 --- a/Makefile +++ b/Makefile @@ -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)" diff --git a/README.md b/README.md index 18c59d1..b6b9235 100644 --- a/README.md +++ b/README.md @@ -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 = "" ``` -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 ` 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) diff --git a/cmd/runtimebundle/main.go b/cmd/runtimebundle/main.go index ec72b79..28da9ea 100644 --- a/cmd/runtimebundle/main.go +++ b/cmd/runtimebundle/main.go @@ -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 } diff --git a/packages.apt b/config/packages.apt similarity index 100% rename from packages.apt rename to config/packages.apt diff --git a/packages.void b/config/packages.void similarity index 100% rename from packages.void rename to config/packages.void diff --git a/runtime-bundle.toml b/config/runtime-bundle.toml similarity index 92% rename from runtime-bundle.toml rename to config/runtime-bundle.toml index 7867a9d..460cb53 100644 --- a/runtime-bundle.toml +++ b/config/runtime-bundle.toml @@ -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 = "" diff --git a/firecracker-api.yaml b/docs/reference/firecracker-api.yaml similarity index 100% rename from firecracker-api.yaml rename to docs/reference/firecracker-api.yaml diff --git a/examples/void-exp.config.toml b/examples/void-exp.config.toml index a3a1b89..192f433 100644 --- a/examples/void-exp.config.toml +++ b/examples/void-exp.config.toml @@ -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" diff --git a/internal/cli/cli_test.go b/internal/cli/cli_test.go index 49c166a..b0b0f63 100644 --- a/internal/cli/cli_test.go +++ b/internal/cli/cli_test.go @@ -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() diff --git a/internal/daemon/daemon_test.go b/internal/daemon/daemon_test.go index cf5ef8a..82ffa7f 100644 --- a/internal/daemon/daemon_test.go +++ b/internal/daemon/daemon_test.go @@ -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, diff --git a/internal/paths/paths.go b/internal/paths/paths.go index 0663730..8608a19 100644 --- a/internal/paths/paths.go +++ b/internal/paths/paths.go @@ -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 { diff --git a/internal/paths/paths_test.go b/internal/paths/paths_test.go index 50cdcde..68771a9 100644 --- a/internal/paths/paths_test.go +++ b/internal/paths/paths_test.go @@ -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{ diff --git a/scripts/bench-create.sh b/scripts/bench-create.sh index 59bd5e4..ff30290 100644 --- a/scripts/bench-create.sh +++ b/scripts/bench-create.sh @@ -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" diff --git a/customize.sh b/scripts/customize.sh similarity index 96% rename from customize.sh rename to scripts/customize.sh index 1576382..52b90d6 100755 --- a/customize.sh +++ b/scripts/customize.sh @@ -7,7 +7,7 @@ log() { usage() { cat <<'EOF' -Usage: ./customize.sh [--out ] [--size ] [--kernel ] [--initrd ] [--docker] [--modules ] +Usage: ./scripts/customize.sh [--out ] [--size ] [--kernel ] [--initrd ] [--docker] [--modules ] 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 diff --git a/interactive.sh b/scripts/interactive.sh similarity index 93% rename from interactive.sh rename to scripts/interactive.sh index b89114b..bda0798 100755 --- a/interactive.sh +++ b/scripts/interactive.sh @@ -7,7 +7,7 @@ log() { usage() { cat <<'EOF' -Usage: ./interactive.sh [--out ] [--size ] +Usage: ./scripts/interactive.sh [--out ] [--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 diff --git a/packages.sh b/scripts/lib/packages.sh similarity index 92% rename from packages.sh rename to scripts/lib/packages.sh index 25af4c7..3a87295 100644 --- a/packages.sh +++ b/scripts/lib/packages.sh @@ -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" diff --git a/make-rootfs-void.sh b/scripts/make-rootfs-void.sh similarity index 93% rename from make-rootfs-void.sh rename to scripts/make-rootfs-void.sh index 1cf5c89..918be10 100755 --- a/make-rootfs-void.sh +++ b/scripts/make-rootfs-void.sh @@ -7,21 +7,21 @@ log() { usage() { cat <<'EOF' -Usage: ./make-rootfs-void.sh [--out ] [--size ] [--mirror ] [--arch ] [--packages ] +Usage: ./scripts/make-rootfs-void.sh [--out ] [--size ] [--mirror ] [--arch ] [--packages ] 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")" diff --git a/make-rootfs.sh b/scripts/make-rootfs.sh similarity index 57% rename from make-rootfs.sh rename to scripts/make-rootfs.sh index dd83d55..4fd20b6 100755 --- a/make-rootfs.sh +++ b/scripts/make-rootfs.sh @@ -7,19 +7,25 @@ log() { usage() { cat <<'EOF' -Usage: ./make-rootfs.sh [--size ] [--base-rootfs ] +Usage: ./scripts/make-rootfs.sh [--size ] [--base-rootfs ] -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 diff --git a/make-void-kernel.sh b/scripts/make-void-kernel.sh similarity index 95% rename from make-void-kernel.sh rename to scripts/make-void-kernel.sh index fb67ba4..13f92f8 100755 --- a/make-void-kernel.sh +++ b/scripts/make-void-kernel.sh @@ -7,13 +7,14 @@ log() { usage() { cat <<'EOF' -Usage: ./make-void-kernel.sh [--out-dir ] [--mirror ] [--arch ] [--kernel-package ] [--print-register-flags] +Usage: ./scripts/make-void-kernel.sh [--out-dir ] [--mirror ] [--arch ] [--kernel-package ] [--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" diff --git a/register-void-image.sh b/scripts/register-void-image.sh similarity index 82% rename from register-void-image.sh rename to scripts/register-void-image.sh index 1d3a343..bc4ccfc 100755 --- a/register-void-image.sh +++ b/scripts/register-void-image.sh @@ -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" diff --git a/verify.sh b/scripts/verify.sh similarity index 85% rename from verify.sh rename to scripts/verify.sh index 53478e1..3b963f7 100755 --- a/verify.sh +++ b/scripts/verify.sh @@ -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 ] +Usage: ./scripts/verify.sh [--nat] [--image ] 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