OXYGENHUB

A runner offers only the tiers it can run c5b702e59c1f

The MicroVM tier is offered only when /dev/kvm opens for reading and
writing and flow.toml pins Firecracker; the runner names its tiers when
it starts, and with none refuses to start, saying why, instead of
claiming jobs it would fail (spec §11.1). refs #36
Author
Andy McCall @andymccall <[email protected]>
When
· 2026-10-04 23:57 UTC
Signature
✔ signed by Andy McCall
Hash
c5b702e59c1f884f01afc1c62f02ae023e83b8b27a39b092d52ca5977d212ec4
Depends on
3007d8f011fa 47c1d64dec8a bb643c252515 c3db750ed96e e0918b887850 f53e6d47b56a
Depended on by
77c8c24066ef e6949d87205b b11e30f5031d ea56c56eaf90
In bookmarks
main newer-pipeline push-uses-login
In tags
v0.2.0 v0.3.0 v0.3.1 v0.4.0 v0.5.0 v0.5.1 v0.5.2 v0.5.3
Edits
7 atoms, 0 tree operations, 2 files

Browse the tree at this change

modified CHANGELOG.md +2 −0
…
3 unchanged lines
4 4
5 5
## Unreleased
6 6
7 +
- **A runner offers only the tiers it can run (#36).** It checks that `/dev/kvm` opens before offering the MicroVM tier, says which tiers it serves when it starts, and refuses to start with none, naming why, rather than claiming jobs it would fail.
8 +
7 9
- **A runner tries a fetch again after a network hiccup (oxygenhub#111).** Fetching or cloning the job's repository or a subrepo is retried on DNS, connection, timeout and 502/503/504 errors, waiting 2, 4, 8, 16 and 30 seconds; any other error still ends the job at once.
8 10
9 11
- **Architecture awareness (#36, spec §11.2).** `flow rootfs import` records an image's architecture from its shell's ELF header and refuses an image for another architecture; a claim reports each image's architecture, and a sandbox may say `arch "riscv64"`.
…
18 unchanged lines
modified crates/flow/src/runner.rs +20 −2
…
248 unchanged lines
249 249
    }
250 250
}
251 251
252 +
/// The isolation tiers this machine can honour now (spec §11.1): the
253 +
/// MicroVM tier only when `/dev/kvm` opens for reading and writing and
254 +
/// flow.toml pins Firecracker. `Err` says why there are none.
255 +
pub fn tiers(home: &Home) -> std::result::Result<Vec<String>, String> {
256 +
    let kvm = std::fs::OpenOptions::new().read(true).write(true).open("/dev/kvm");
257 +
    match (kvm, home.config.microvm.is_some()) {
258 +
        (Ok(_), true) => Ok(vec!["microvm".into()]),
259 +
        (Ok(_), false) => Err("flow.toml has no [microvm] section, so no tier can run".into()),
260 +
        (Err(e), _) => Err(format!(
261 +
            "/dev/kvm cannot be opened ({e}): the MicroVM tier needs hardware virtualisation and this user in the kvm group, and no other tier is in this build"
262 +
        )),
263 +
    }
264 +
}
265 +
252 266
pub fn serve(home: &Home) -> Result<()> {
253 267
    let cfg = home.config.runner.clone().context("flow.toml has no [runner] section")?;
268 +
    // A runner offers only what it can run: a machine without KVM claims
269 +
    // nothing rather than taking MicroVM jobs and failing them (#36).
270 +
    let runtimes = tiers(home).map_err(|why| anyhow::anyhow!("flow runner: {why}"))?;
254 271
    let hub = Hub::new(&cfg)?;
255 272
    let name = cfg.name.clone().unwrap_or_else(|| "flow".into());
256 273
    let budget = Budget::of(&cfg);
257 274
    let key = home.runner_key(&name)?;
258 275
    eprintln!(
259 -
        "flow runner {name}: polling {} (up to {} jobs at once), signing receipts as {}",
276 +
        "flow runner {name}: polling {} (up to {} jobs at once, tiers {}), signing receipts as {}",
260 277
        cfg.hub,
261 278
        budget.max_jobs,
279 +
        runtimes.join(", "),
262 280
        key.identity.hash().to_hex()
263 281
    );
264 282
    let used = std::sync::Mutex::new(Used::default());
…
21 unchanged lines
286 304
            };
287 305
            let req = ClaimRequest {
288 306
                runner: name.clone(),
289 -
                runtimes: vec!["microvm".into()],
307 +
                runtimes: runtimes.clone(),
290 308
                free_memory_mib,
291 309
                free_cpus,
292 310
                info: Some(RunnerInfo {
…
498 unchanged lines