1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# Draupnir — the low-level BOOT / PROVISIONING library of the nordisk
# constellation. One crate, three boot backends: KVM (drives tunnr), OCI
# containers, and Redfish bare-metal virtual-media boot.
#
# Standalone workspace whose root IS the `draupnir` crate (the tunnr /
# Skidbladnir house pattern): this pins it as its own workspace root so a
# parent directory's workspace cannot accidentally absorb it, and so the two
# high-level consumers (jera, Skidbladnir) can path/version-dep it as a leaf
# without dragging a wider tree.
[]
= "2"
[]
= "draupnir"
= "0.1.9"
= "2021"
= "1.85"
= "Draupnir — the nordisk boot/provisioning library: fire up a runtime from one BootSpec across three backends (KVM via tunnr · OCI container · Redfish bare-metal virtual-media) and drive its power lifecycle. Odin's ring that drips eight identical copies → boot a fleet of identical machines from one ISO."
= "MIT OR Apache-2.0"
= "https://codeberg.org/nordisk/draupnir"
= ["boot", "provisioning", "redfish", "kvm", "container"]
= ["virtualization", "os"]
[]
= "draupnir"
= "src/lib.rs"
[]
# Lean by design: the default build is PURE std — the trait surface, the
# BootSpec/Machine types, validation and the fleet fan-out all compile with no
# dependency at all. Each live backend sits behind a feature so a lean consumer
# pulls only what it drives.
= []
# The REAL KVM backend over tunnr's `tunnr_vm::boot_test(BootSpec) -> BootHandle`
# primitive. The `kvm` module + its `Boot`/`Lifecycle` seam always compile (an
# honest, un-feature-gated stub); this feature adds the live tunnr wire. tunnr-vm
# is not yet on crates.io, so a PATH dep is the correct interim (exactly how
# `jera` wires it) — switch to a version once tunnr publishes. Pulls `seed` so the
# KVM adapter can author the cloud-init NoCloud seed *image* it attaches to a VM.
= ["dep:tunnr-vm", "seed"]
# The **NoCloud cloud-init seed** builder ([`seed`]) — draupnir owns it (ported
# from Skidbladnir). The file-set render + the plain **seed directory** output are
# pure std (always compiled, no dep); THIS feature adds the pure-Rust `fatfs`
# **vfat seed image** authoring (volume label `cidata`, no `genisoimage`/`mkisofs`
# subprocess). Split out from `backend-tunnr` so a consumer can author a seed
# image without dragging the KVM boot path.
= ["dep:fatfs"]
# Route this crate's `functional_status` emit markers into real nornir test-matrix
# rows (the constellation-wide introspection-coverage gate). OFF by default so the
# lean core pulls no nornir dep — then `functional_status` is a compiled-out no-op.
= ["dep:nornir-testmatrix", "nornir-testmatrix/testmatrix"]
# The REAL OCI container backend over the podman/Docker REST API (`bollard`) — the
# same zero-shell container engine `jera` drives, reused rather than re-rolled. A
# dedicated tokio runtime drives the async API from the synchronous `Boot`/
# `Lifecycle` seam. OFF by default so a plain `cargo build` stays pure-std.
#
# Also carries the image ARCHIVE path (`export_image`/`import_image`): `bytes` for
# bollard's streaming load body, and `serde_json` — already in this manifest for
# Redfish — to read the `manifest.json` at the root of a docker-archive, which is
# how an exported tar names the tags and config digest it actually contains.
= ["dep:bollard", "dep:tokio", "dep:futures", "dep:tar", "dep:bytes", "dep:serde_json"]
# The DAEMON-LESS OCI runtime backend over **youki-core** (`libcontainer`): a
# pure-Rust runc alternative that runs containers directly on Linux namespaces +
# cgroups-v2, NO daemon, NO CLI (the in-appliance engine korp-server links). OFF by
# default so a plain `cargo build` stays pure-std and the `bollard` socket path is
# the default container engine. Pulls `tar` (shared with `backend-oci`) for the
# layer→rootfs unpack. Alias-worthy as `oci-native`.
= ["dep:libcontainer", "dep:rustix", "dep:flate2", "dep:tar"]
# The REAL bare-metal Redfish backend: a pure-Rust `ureq` (rustls, no
# openssl/native-tls) client over the handful of DMTF Redfish endpoints we drive
# (VirtualMedia insert/eject, the ComputerSystem `Boot` override, and
# ComputerSystem.Reset). OFF by default so a plain `cargo build` stays pure-std
# and offline-green; the request shaping is pure + fixture-tested with no BMC.
= ["dep:ureq", "dep:serde_json"]
# The Redfish **SERVER** — draupnir's own BMC, fronting KVM ([`redfish_server`]).
#
# The other end of `backend-redfish`: a pure-Rust Redfish service that answers the
# six endpoints draupnir's client drives and translates them onto the vocabulary
# that already exists — `InsertMedia` → [`BootSpec::medium`], the `Boot` override →
# [`BootOrder`], `ComputerSystem.Reset` → the [`Boot`]/[`Lifecycle`] seam. That
# turns any Linux box with `/dev/kvm` into a Redfish-controllable machine, which is
# squarely this crate's charter, and it gives the `iso-redfish-sim` matrix form a
# BMC to burn against on a box that has none.
#
# OFF by default and NOT implied by `backend-redfish`: a client-only build must not
# grow a listening socket. Pulls `rustls` (pure Rust, `ring` — the same 0.23 line
# `ureq` already resolves to, so no second TLS stack enters the graph) and `rcgen`
# for the server's TLS identity, because draupnir's own client PINS the BMC
# certificate and a pinned client needs a real cert to pin. `rcgen` — not
# korp-installer's RSA/`x509-cert` `SigningIdentity`, which mints an *Authenticode
# code-signing* identity — is the constellation's TLS-identity crate: it is exactly
# what Skidbladnir's `src/pki.rs` uses (`rcgen 0.13`, `default-features = false`,
# `["pem","ring"]`, proven to load into a real `rustls::ServerConfig`). That code
# cannot simply be called from here: Skidbladnir path-deps *this* crate
# (`Skidbladnir/Cargo.toml:87`), so a dep back onto its `pki` module would be a
# cycle. Same crate, same features, same pattern — one cert story, not two.
= ["dep:rustls", "dep:rcgen", "dep:serde_json"]
[]
# ── threading (always): the ONE sanctioned home for concurrency ──
# ROOT-LAW #0 ("rayon-free" / core-saturation): every thread in the constellation
# originates in gatling, never a bare `std::thread::spawn`. The parallel fleet
# fan-out (`boot_fleet_and_await_parallel`) routes each member's blocking boot
# through `gatling::gatling_forkjoin::gatling_for_each` (one worker per member).
# Published as `rotaryengine`; the library identity stays `gatling`. Path dep
# (offline workspace, all repos are siblings under git/); already in the tree
# transitively via tunnr-vm, so a direct dep adds no new leaf.
= { = "../znippy-zoomies/gatling", = "0.1.9", = "rotaryengine" }
# ── real KVM backend (feature `backend-tunnr`) ──
# The path resolves to the sibling tunnr workspace root whose root crate is
# `tunnr-vm` (lib `tunnr_vm`); OFF by default so a plain `cargo build` has no
# dep and the KVM `boot()` is a compiled-out honest stub.
= { = "../tunnr", = "0.1", = true }
# Pure-Rust FAT12/16 authoring for the cloud-init NoCloud seed image (volume label
# `cidata`) the KVM guest's cloud-init reads at first boot — the same `fatfs` crate
# Skidbladnir uses, so there is no `genisoimage`/`mkisofs` subprocess (zero-shell).
# Rides the `seed` feature (which `backend-tunnr` pulls).
= { = "0.3", = true }
# ── the nornir test-matrix emit sink (feature `testmatrix`) ──
# Lean serde-only crate: turns `functional_status` markers into real matrix rows.
# PATH added 2026-08-01 for `tests/silenced_tests_guard.rs`, which needs the
# `gatedtests` module — that module exists only in edda's unpublished 0.2.8, and
# cargo demands ONE canonical source path for a package across [dependencies] and
# [dev-dependencies]. `version` is kept so `cargo publish` still resolves it from
# the registry for external consumers; locally the sibling path wins (the same
# path+version shape the `gatling` dep above uses).
= { = "../edda/crates/nornir-testmatrix", = "0.2", = false, = true }
# ── real OCI container backend (feature `backend-oci`) ──
# bollard is the async podman/Docker REST client; pinned to the same 0.20 line
# jera uses so there is one container engine across the constellation. tokio drives
# its async API from draupnir's synchronous seam; futures for the pull/log streams.
= { = "0.20", = true }
= { = "1", = ["rt-multi-thread"], = true }
= { = "0.3", = true }
# Pure-Rust tar for the OCI image-build context (tar the build dir → `build_image`)
# and the `create`+`cp` artifact extract (unpack `download_from_container`'s tar) —
# so Skidbladnir's `pack.rs` `podman build` + `podman cp` twin routes through the
# ONE OCI engine. Rides `backend-oci`; the lean default pulls nothing.
= { = "0.4", = true }
# `bytes::Bytes` is the chunk type bollard's STREAMING import (`import_image_stream`)
# demands (`Stream<Item = Result<Bytes, E>>`); the non-streaming `import_image` wants
# the whole archive as one `Bytes`, which for a 1.4 GB Spark image is exactly the
# gigabyte-in-RAM we refuse. Not a new crate in the build graph — bollard already
# pulls `bytes` (1.12.1 in `Cargo.lock`); naming it here only makes the type
# constructible. Pinned to bollard's own 1.x line so the types unify.
= { = "1", = true }
# ── the DAEMON-LESS OCI runtime backend (feature `backend-youki`, aka oci-native) ──
# youki-core (`libcontainer`) is the pure-Rust LOW-LEVEL OCI runtime — a runc
# alternative that runs a container DIRECTLY over Linux namespaces + cgroups-v2 with
# NO daemon and NO CLI. This is the in-appliance container engine korp-server (static
# PID-1) links, per Gemini's revised design: mount cgroups, set up namespaces, unpack
# an OCI image's layers into a bundle rootfs, generate `config.json`, and drive the
# create/start/kill/delete lifecycle — all in-process. Zero-shell: single-line rootless
# uid/gid maps are written straight to `/proc/self/uid_map` (no `newuidmap` exec), and
# any boot-path shell-out into a `scratch` bundle is an instant ENOENT.
# - `v2` → cgroups-v2 (Unified) only; no cgroup-v1.
# - `systemd` → the pure-Rust **native-dbus** systemd cgroup manager. libcontainer
# FORCES the systemd cgroup path whenever a user namespace is present (rootless),
# so this is required for a rootless run: it creates a transient scope under the
# caller's delegated `user@UID.service` slice over the session bus — still zero
# external process (a hand-rolled dbus client, not the `systemctl`/`busctl` CLI).
= { = "0.6", = false, = ["v2", "systemd"], = true }
# geteuid/getegid for the single-line rootless id-map (map container-root → the
# caller's own uid, so youki writes uid_map directly and never execs `newuidmap`).
= { = "1", = false, = ["process"], = true }
# gzip decode for the OCI-image layer tarballs when unpacking them into a bundle rootfs.
= { = "1", = true }
# ── real Redfish backend (feature `backend-redfish`) ──
# Pure-Rust HTTP: ureq over rustls (ring) — NO openssl/native-tls (pure-Rust
# charter). `disable_verification` handles the self-signed certs BMCs ship with.
# serde_json shapes the Redfish action bodies.
= { = "3", = false, = ["rustls", "json", "gzip"], = true }
= { = "1", = true }
# ── the Redfish SERVER (feature `redfish-server`) ──
# TLS for draupnir's own BMC. rustls 0.23 over **ring** — the exact provider `ureq`
# already resolves to in this tree (`Cargo.lock`: rustls 0.23.42 → ring 0.17.14), so
# the server side adds no second crypto backend and client + server share one stack.
# `std` for the blocking `StreamOwned` seam the accept loop reads/writes through.
= { = "0.23", = false, = ["ring", "std", "tls12", "logging"], = true }
# The server's TLS identity — a genuine self-signed X.509 with SANs, minted per run
# and held **in memory only** (never written to disk, so no `.key`/`.pem`/`.der` can
# be committed). Same crate, same feature set and same call shape as Skidbladnir's
# `pki::issue_leaf` (`Skidbladnir/Cargo.toml:116`); see the `redfish-server` feature
# note for why the code is mirrored in crate choice rather than imported.
= { = "0.13", = false, = ["pem", "ring"], = true }
# ── dev-only: the fleet-boot bench (does NOT affect the lib's runtime deps) ──
# criterion drives the LIGHT serial-vs-parallel fleet-boot arm (`benches/fleet_boot.rs`);
# it is a dev-dependency only, so a consumer's `cargo build` still pulls the pure-std
# lib with no criterion in its tree. The Loki bencher runs the authoritative HEAVY pass.
[]
= { = "0.5", = false }
# The SILENCED-TEST guard (`tests/silenced_tests_guard.rs`): edda's
# `nornir_testmatrix::gatedtests::audit_repo`, which fails this repo's own
# `cargo test` the moment a `tests/*.rs` goes dark behind an off-by-default
# feature. Deliberately NO `version` — crates.io's newest nornir-testmatrix
# (0.2.7) has no `gatedtests` module, so a version requirement would be a claim
# the registry cannot honour. A path-only dev-dep is stripped by `cargo publish`,
# so no consumer ever sees this edge.
= { = "../edda/crates/nornir-testmatrix", = false }
= { = "0.3.23", = ["env-filter"] }
# `tests/redfish_server_conformance.rs` re-hashes every vendored DMTF fixture against
# the digests recorded in `tests/fixtures/dmtf/PROVENANCE.md` before it reads them.
# Without that, a fixture quietly edited to make a conformance assertion pass would
# be indistinguishable from conformance — the anchor has to be tamper-evident or it
# is not an anchor. Pure-Rust `sha2` (no `cc`, no openssl); dev-only, so no consumer
# sees it.
= "0.10"
# The conformance suite's HTTP transport. Deliberately a THIRD-PARTY client rather
# than anything draupnir wrote: if the server emits malformed HTTP, an independent
# implementation is what notices. Same crate/features the `backend-redfish` optional
# dep resolves to, so no second HTTP stack enters the graph.
= { = "3", = false, = ["rustls", "json", "gzip"] }
= "1"
# The fleet-boot bench: serial `boot_fleet_and_await` vs the concurrent
# `boot_fleet_and_await_parallel` over a fake fast backend with a small per-member
# status latency (models a BMC/QEMU/container readback round-trip). `harness = false`
# → criterion owns `main`.
[[]]
= "fleet_boot"
= false