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

mikronova/draupnir

.nornir/oci-network-mode.md

OCI network mode — the airgap --network none wire (Skidbladnir's #1 blocker)

Why. Skidbladnir's airgap container route needs a container that reaches no network — podman run --network none. jera's ContainerSpec already renders that choice (net: NetMode, network_arg() → --network none), but draupnir owns the ONE OCI engine and its create body carried port_bindings + binds and no network_mode — so jera could express the airgap but it never reached the live podman create. This threads the net mode onto the create body, additively, so NetMode::None actually cuts the container off from egress at the real run.

The knob (a net field on BootSpec, NetMode::Default = unchanged)

Every draupnir::BootSpec is built through a constructor + builders — no consumer (nornir/korp/knut/tunnr/jera/Skidbladnir) constructs it by raw struct literal (audited: the only raw BootSpec {…} literals in the constellation are each repo's own local BootSpec type). So a new field is safe as long as the four constructors default it. net defaults to NetMode::Default, which renders no --network flag and leaves the create body byte-for-byte identical to a spec that never named a net mode.

pub enum NetMode { Default, None, Host, Bridge }   // Default = no --network flag
impl NetMode {
    pub fn oci_value(self) -> Option<&'static str>;    // None | "none" | "host" | "bridge"
    pub fn is_default(self) -> bool;                    // parity guard
    pub fn from_oci_value(v: Option<&str>) -> Self;     // the cross-repo wire (jera passes this)
}
pub struct BootSpec { /* …, */ pub net: NetMode }
impl BootSpec { pub fn with_net(self, net: NetMode) -> Self; }   // builder

NetMode mirrors jera's ContainerSpec::NetMode field-for-field. jera passes its rendered value across the repo boundary as the OCI string ("none"/"host"/ "bridge") via NetMode::from_oci_value(jera_spec.net.oci_value()) — no cross-repo variant coupling. net is container-only: validate() rejects a non-default net on KVM/Redfish (parity with the cmd/ports container-only guards).

The wire (rides the existing bind delegate chain)

The create body already had a *_with_binds delegate chain; net rides it with one more *_and_net layer, so the bind-free / net-free entries stay byte-identical.

net-free (unchanged) net-aware (new) note
Engine::create_body_with_binds Engine::create_body_with_binds_and_net pure body builder; None net ⇒ identical body (HostConfig.network_mode stays None)
Engine::create_and_start_with_binds Engine::create_and_start_with_binds_and_net create+start with HostConfig.network_mode
— Boot::boot / boot_with_binds read spec.net both boot paths thread spec.net.oci_value() onto the create body

Because both boot paths read spec.net, every downstream entry — Boot::boot, boot_with_binds, run_to_completion, run_to_completion_with_binds — honours the net mode automatically. A consumer just sets spec.net.

 jera ContainerSpec { net: NetMode::None }        draupnir (ONE OCI engine, bollard)
 ┌──────────────────────────────────────┐          ┌───────────────────────────────────┐
 │ to_draupnir():                        │          │ boot / boot_with_binds read spec.net│
 │   d.net = NetMode::from_oci_value(    │ ───────▶ │   → create_and_start_with_binds_and │
 │     self.net.oci_value())  // "none"  │          │     _net(…, Some("none"))           │
 │ run_to_completion_with_binds(&d, …)   │          │   → HostConfig.network_mode="none"  │
 └──────────────────────────────────────┘          │   → podman create --network none    │
   (was: expressed but dropped at the run)          └───────────────────────────────────┘

The jera handoff (one line)

jera's ContainerSpec::to_draupnir() builds the draupnir::BootSpec that BOTH its boot leg (DraupnirContainerBootRunner) and its run-to-completion leg (run_to_completion_with_binds) consume. One added line carries the net mode through both:

// in jera ContainerSpec::to_draupnir()
d.net = draupnir::NetMode::from_oci_value(self.net.oci_value());

After that line, NetMode::None reaches the live podman run, and Skidbladnir can un-gate its airgap container route (drop the --network none fallback to a direct podman subprocess).

Status