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

mikronova/draupnir

.nornir/design.md

draupnir — design

Draupnir is the low-level boot / provisioning library of the nordisk constellation. It fires up a runtime instance from one [BootSpec] across three backends and drives its power lifecycle. Named for Draupnir, Odin's gold ring that drips eight identical copies of itself every ninth night — here a light nod: booting a fleet of identical machines from one ISO is the natural extension, not the core. The core is one library, three boot backends.

Charter

Ownership — one home per capability (the no-duplication rule)

Draupnir is the shared low-level boot lib. Two high-level consumers depend on it directly; neither re-implements boot code. Draupnir knows nothing about jobs or services — it only fires up and controls instances.

Component Layer Owns Depends on
Draupnir low-level boot lib the Boot/Lifecycle/VirtualMedia traits, BootSpec/Machine types, spec validation + fleet fan-out, the NoCloud cloud-init seed builder (seed — see nocloud-seed.md), and the three backend adapters (kvm/container/redfish) tunnr (KVM); an OCI runtime crate; a Redfish client crate; fatfs (seed image)
tunnr KVM boot backend the QEMU + OVMF (UEFI) + KVM boot primitive (BootSpec/boot_test/BootHandle) — (Draupnir's KVM backend drives it)
jera (edda job handler) thin job policy job semantics only — a job is process | VM | container; the durable job ledger Draupnir (directly, for VM/container job instances)
Skidbladnir high-level service/airgap layer service/systemd lifecycle, airgap pack/move/unfold, orchestration Draupnir (directly, for service instances)

Call direction — two independent consumers, one shared engine:

  jera ─────────┐
                ├──▶ Draupnir ──▶ tunnr            (KVM VM)
  Skidbladnir ──┘             ├─▶ OCI runtime      (container / redis service)
                              └─▶ Redfish BMC      (bare-metal virtual-media)

No-duplication rule. Instance booting lives in exactly one place: Draupnir. jera does not shell out to QEMU; Skidbladnir does not carry its own KVM/container drivers; neither reimplements the other's boot path. tunnr is the sole KVM boot primitive, reached only through Draupnir's KVM backend.

This revises the earlier "Skidbladnir is the KVM/container mechanism master" decision. Skidbladnir now delegates instance-firing to Draupnir and becomes a consumer of it (service/systemd, airgap, orchestration stay in Skidbladnir). jera likewise depends on Draupnir directly rather than re-rolling VM/container boot.

Types & traits (the real core)

Dependencies (reuse, don't reinvent — Brokkr's minimal-dependency law)

Draupnir's own code is the thin Boot glue; each backend delegates to an existing crate. Chosen (and why):

The network-touching backends (OCI, Redfish) sit behind OFF-by-default features so the default build stays pure-std and offline-green; only their justified crates are pulled when a consumer enables them.

Extraction plan — moving instance-firing out of Skidbladnir (staged)

Instance-firing code currently lives in Skidbladnir/src/machine.rs (behind its machine / kvm / container features): the MachineController trait with kvm::KvmController (qemu/KVM + cloud-init NoCloud seed) and container::ContainerController (podman/docker), plus MachineSpec / Handle / ImageCache. That is exactly Draupnir's remit. Do not rip it now — the scaffold is created first; the move is staged:

  1. Land Draupnir (this repo) as the Boot/Lifecycle seam + backend adapters. (done — this scaffold.)
  2. Wire the KVM backend to tunnr_vm::boot_test under backend-tunnr (signature already mapped in src/kvm.rs); port Skidbladnir's cloud-init NoCloud seed authoring into draupnir. (done — now the owned, pure src/seed.rs builder behind the seed feature; the KVM adapter attaches it. Follow-up: dedup Skidbladnir's machine.rs copy onto it — see step 5 / nocloud-seed.md.)
  3. Wire the container backend to bollard under backend-oci; fold in ContainerController's start/stop/exec/wait_ready readiness model.
  4. Add the Redfish backend (backend-redfish) — net-new capability, no Skidbladnir source to move.
  5. Repoint Skidbladnir (and jera) at Draupnir: delete machine.rs's duplicate drivers, keep only the high-level service/airgap logic that calls Draupnir. Skidbladnir's ImageCache either moves to Draupnir or is replaced by the znippy-backed image store.
  6. Repoint jera's vm/container seams at Draupnir instead of its own tunnr-vm path dep, so jera keeps only job policy.

Steps 5–6 are the actual code removal and happen only after Draupnir's backends are real (green under their features) — never a half-landed swap.

Why a separate repo

Booting/provisioning is a distinct, versionable capability with two independent consumers (jera, Skidbladnir). Its own leaf workspace lets both depend on one lean crate without dragging each other's dep trees, and lets the boot engine evolve on its own cadence — every backend a unit-testable Rust seam, not an opaque script.

Docs

This .nornir/ is the source of the repo's docs (crisp holger-pattern): design.md (this file) · guide.md (usage) · for-idiots.md (the beginner walk-through).