Gunnar

nordisk/edda

crates/jera/README.md

# jera

**The shared infra runtime** — the non-UI job/infra engine lifted out of
[nornir](https://git.gunnar.rs/nordisk/nornir) so both **nornir** and **korp** depend
on one lean crate instead of pulling each other's dependency trees (no dep-hell).

jera is runtime only. The job-list *UI* stays in `facett-jobview`; jera is the
engine underneath it.

## What's in it

- **`jera::jobs`** — the durable **job ledger / engine**. One redb list
  (`jobs.redb`) of every long-running operation (`running → done|failed` + timing),
  orthogonal to whatever result the op produced. Fat-client (writes the local
  `jobs.redb`) or thin-client (submits each record over a `JobSink`), an exclusive
  serial-scheduler gate, and opportunistic retention. Public API: `JobStore`,
  `JobHandle`, `JobSink`, `JobRecord`, `JobSelector`, the `kind` / `status` modules.

- **`jera::container`** — a **no-shell container runtime** over the podman/Docker
  **REST API** ([bollard]). Bring a `ContainerSpec` up as a detached container,
  stream its logs, and tear it down (`BollardBootRunner` / `BollardEngine`), or run
  one to completion **as a tracked job** (`run_container`). There is **no
  `std::process::Command`** and no CLI shell-out anywhere on this path — the
  constellation's zero-shell charter. (Feature `bollard`, on by default.)

- **`jera::vm`** — a **no-shell KVM/VM boot** seam. Map a self-contained `BootSpec`
  onto the hypervisor boot primitive and drive it as a job. `StubVmBootRunner` is
  the honest not-wired default; `TunnrVmBootRunner` (feature `vm-tunnr`) drives
  tunnr's real `tunnr_vm::boot_test` KVM primitive.

- **`jera::boot`** — the engine-agnostic boot lifecycle (`BootStatus`, `BootProc`,
  `BootRunner`) shared by the container / VM / exe runners, and the job-bound
  **`BootJobs`** manager: the reusable "start X as a tracked job" engine, with the
  bidirectional lifecycle wired (kill the job → kill the boot; the boot dies → the
  job terminates).

## Start a container as a job

```rust
use jera::jobs::JobSink;
use jera::boot::{BootJobs, BootTarget};
use jera::container::ContainerSpec;

let mut jobs = BootJobs::new(JobSink::noop(), "my-workspace");
let id = jobs.boot(BootTarget::Container(ContainerSpec {
    image: "docker.io/library/nginx:alpine".into(),
    ports: vec![8080],
    ..Default::default()
}));
jobs.poll();          // drives the lifecycle both ways
jobs.kill(&id);       // stop + remove over the REST API
```

Or run one to completion and capture its outcome (feature `bollard`):

```rust
let outcome = jera::container::run_container(
    JobSink::noop(),
    &ContainerSpec::image("docker.io/library/alpine:3"),
    "alpine", "my-workspace",
)?;
assert_eq!(outcome.exit_code, Some(0));
```

A `ContainerSpec` also carries **airgap isolation** and **bind mounts** — additive
knobs (default = unchanged, existing specs byte-identical):

```rust
use jera::container::{ContainerSpec, NetMode, BindMount};

let spec = ContainerSpec {
    net: NetMode::None,                              // --network none: no egress (airgap)
    mounts: vec![BindMount::ro("/etc/certs", "/certs")], // -v /etc/certs:/certs:ro
    ..ContainerSpec::image("packer:1")
};
assert_eq!(spec.network_arg().as_deref(), Some("--network none"));
assert_eq!(spec.bind_strings(), vec!["/etc/certs:/certs:ro".to_string()]);
```

Mounts are threaded into draupnir's mount-aware run (`run_to_completion_with_binds`);
`net` is the rendered contract routers gate on (the OCI engine hook is a draupnir
follow-up). See [`.nornir/container-spec.md`](.nornir/container-spec.md).

## Features

| feature     | default | what it adds |
|-------------|---------|--------------|
| `bollard`   | ✅      | the real podman/Docker REST engine + `run_container` |
| `vm-tunnr`  | —       | the real KVM backend over `tunnr_vm::boot_test` (dep pending the tunnr repo) |

A lean consumer sets `default-features = false` (nornir does, then forwards its own
`test-boot-container-bollard` feature to `jera/bollard`).

## Status

Extracted from nornir; consumed by nornir (via the `nornir-jobs` shim + the
`test-boot` runtime) and destined for korp. This standalone sibling directory will
move into a shared repo later.

[bollard]: https://docs.rs/bollard

## License

MIT OR Apache-2.0.