Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

mikronova/draupnir

.nornir/build-thing-launch-design.md

build-thing launch axis + the machine spine — design

Class: design · Home: draupnir, because draupnir is the hub the whole machine spine hangs from. The how-to is in build-thing-launch-guide.md. This doc is the map for the deep-wiring that connects a built artifact to a running, asserted machine, all Rust, no shell.


1. The thesis: two axes, not one list

A build-thing produces an artifact and then (optionally) launches it. Those are two different things, and conflating them is what made exe / container / kvm / iso read as one list when it is really a matrix:

BUILD (what comes out) LAUNCH (how you run it) verdict channel
exe — cargo build run — spawn the binary exit code + stdout
container — ContainerBuild (bollard) deploy — podman run (bollard) + logs pane container stdout stream
vm — VmBuild (kernel+rootfs) boot console — tunnr_vm::boot_test + serial pane contract markers in serial
iso — bootloader-in-disk (new) boot console · or → USB → bare metal same serial contract

kvm is not an artifact — it is a launch target. An artifact declares which targets it supports; the UI renders the launch control that fits. This is the whole correction: build-thing already has ArtifactKind ∈ {Exe,Lib,Wasm,Container,Vm,Service} (edda nornir-build-thing/src/variant.rs); what it lacks is a first-class launch axis beside the build one, and a kind-aware rendering of it.

2. The machine spine — who owns what

The launch axis only works because there is exactly one machine spine underneath, and every layer has a single job:

No cycle: draupnir → tunnr-vm (feature backend-tunnr) is one-directional; the tunnr → draupnir edge lives only in leaf crates (tunnr-demo, payloads/*), never in tunnr-vm. Clean DAG, verified against the Cargo.tomls.

3. The keystone change — draupnir grows a fat-dist boot model

Today draupnir::ImageSource (src/lib.rs:124) can express direct-kernel (KernelRootfs) and kernel+disk (Disk) — but validate() requires a kernel on both (src/lib.rs:622-624), so it cannot express the kernel-less, bootloader-in-disk boot that a fat distro (and Skidbladnir's airgap install) needs. That single gap is why jera_vm_routable() is always false.

The five focused edits (all in draupnir; zero in tunnr — the engine already does it):

  1. src/lib.rs:124 — add ImageSource::BootloaderDisk { disk: String } (self-booting disk, no -kernel).
  2. src/lib.rs:154 — suits(): BootloaderDisk suits Backend::Kvm.
  3. src/lib.rs:622 — validate(): require only the disk path, not a kernel.
  4. src/lib.rs:~463 — a bootloader_disk constructor peer.
  5. src/kvm.rs:74 — to_tunnr_spec: map BootloaderDisk to an empty-kernel tunnr_vm::BootSpec (tunnr firmware-boots the disk). And, while here, fix the seed drift (kvm.rs:104): use tunnr's native BootSpec::with_seed instead of hand-rolling the seed -drive into extra_qemu_args, so the seed argv is authored in one place.

This unlocks both downstream moves at once: the fat-dist launch, and Skidbladnir routing onto draupnir.

4. The launch axis — declared in the model, rendered elsewhere

The wiring adds an explicit launch action, distinct from build, to the build-thing data model (edda/crates/nornir-build-thing/src/surface.rs, state_json) — kind-aware:

This is a declaration of what launch a cell supports, carried in state_json for a consumer (dwarves, or a future UI) to render. Two deliberate scope lines:

No shell — when the executor is built, container work is the bollard Rust API and VM work is boot_test; neither lives in this model phase.

5. Caching & sealing

6. The shell island — ported to Rust

tunnr's outer Buildroot orchestration was variants/buildroot/build.sh + board/tunnr/post-build.sh (shell). Both are now deleted and ported to pure Rust:

BuildShVmBuilder calls the Rust path; the defconfigs point at the compiled hook. No shell remains in the Buildroot path — the last island is drained.

7. What the wiring touches (the deep pass)

Repo Change Gate
draupnir ImageSource::BootloaderDisk + validate + to_tunnr_spec + seed-drift fix cargo test --features backend-tunnr,seed
Skidbladnir route machine::kvm through draupnir::kvm; enable draupnir/backend-tunnr; delete own launcher cargo build --features kvm,matrix
tunnr tunnr-demo adopts draupnir fleet fan-out for the two-node OS-less boot cargo build -p tunnr-demo
dwarves run_vm real spec via jera→draupnir; new vm-boot feature enabling jera/vm-tunnr; VmBoot step carries a real spec cargo build + cargo build --features vm-boot
edda launch axis declared in build-thing surface (kind-aware) + LaunchOutput logs seam cargo build -p nornir-build-thing
nornir out of scope — huge; viz rendering + logs are a separate framework —

Every row is compile-gated; nothing is reported wired that does not build.