OXYGENHUB
# 8aa45fa6ece5 oxygenflow / README.md
5.5 KiB · Markdown · last changed A Windows runner updates itself 10 days ago renderedsource blame history raw
a083cc80 Andy McCall ↶ 1
# OxygenFlow
2
3
Hermetic pipelines for Oxygen repositories:
4
5
- a typed pipeline in `.flow/pipeline.kdl`
6
- jobs run in isolation tiers, Firecracker microVMs by default
7
- the host writes the receipts
8
- results go to OxygenHub as checks and appear on its Flow tab
9
10
The specification is [docs/spec.md]docs/spec.md. What works today is
11
[docs/m0.md]docs/m0.md.
12
13
## A pipeline
14
15
```kdl
16
schema-version 1
17
18
sandbox "alpine" {
19
    runtime "microvm"
20
    rootfs "cas://blob/…"      // printed by `flow rootfs import`
21
    memory-limit "256MiB"
22
    network "isolated"
23
}
24
25
job "build" {
26
    sandbox "alpine"
27
    exec "make"
28
}
29
30
job "test" {
31
    sandbox "alpine"
32
    depends-on "build"
33
    exec "sh" "-eu" "test.sh"   // argv, run as written: no shell unless you name one
34
}
35
```
36
37
Each job boots its own microVM:
38
39
- it has no network device
40
- the rootfs is read-only
41
- the workspace is the state being built, read-write at `/src`
42
- the job runs as a user that is not root
43
44
This repository's own pipeline is [.flow/pipeline.kdl].flow/pipeline.kdl.
45
fc10d9e8 Andy McCall ↶ 46
## Deploying the runner on Earth
47
48
`make deploy-runner` builds `flow` and the static `flow-init`, installs them
49
under `/home/claude/flow` (keeping the previous files as `.prev`), re-pins
50
`flow-init` in `flow.toml` and restarts the `flow-runner` service.
51
73141320 Andy McCall ↶ 52
## A Windows runner
53
54
A Windows machine runs WASM jobs (the other tiers are Linux's). Each
55
release carries `flow-windows-x86_64.exe` (from the `dist` job):
56
57
    flow.exe --home C:\flow runner register https://oxygenhub.io --token flowreg_… --name win-1 --label windows
58
    flow.exe --home C:\flow runner
59
60
The token comes from the hub (Admin › Runners, or `POST /api/v1/user/runner-token`
61
for a runner of your own repositories). A pipeline sends it work with a
62
`runtime "wasm"` sandbox and `runs-on "windows"`. To keep it running, a
63
Task Scheduler task at start-up with that command (restarting on failure)
494a1b9a Andy McCall ↶ 64
does; set it to restart on failure, as a runner that leaves for a new build
65
exits 75 (`flow runner update`, spec §11.5.3). What a Windows runner does
66
not do yet: report load and kernel, or drain when Windows stops it
67
(oxygenflow#83).
73141320 Andy McCall ↶ 68
a083cc80 Andy McCall ↶ 69
## Commands
70
71
    flow check                 # validate .flow/pipeline.kdl, print jobs and the pipeline hash
72
    flow run [JOB…]            # run the pipeline on this directory, locally, in microVMs
73
    flow rootfs import T.tgz --sha256 HEX   # make a rootfs image; prints the `rootfs` line to pin
a72abeee Andy McCall ↶ 74
                  [--env NAME=value …]      #   with the image's own environment (a Dockerfile's ENV)
a083cc80 Andy McCall ↶ 75
    flow rootfs list
76
    flow hash FILE             # BLAKE3, for pinning in flow.toml
77
    flow runner                # claim and run jobs for the hub in flow.toml
73141320 Andy McCall ↶ 78
    flow runner update --from FILE [--dry-run]   # install a new flow build in place of this one (spec §11.5.3)
a083cc80 Andy McCall ↶ 79
80
## A Flow home
81
82
`$FLOW_HOME` (default `~/.local/share/flow`) holds:
83
84
- `flow.toml`
85
- the pinned Firecracker binary, guest kernel and `flow-init`
86
- rootfs images under `cas/`
87
- scratch space
88
89
Every pinned file is checked against its BLAKE3 before use.
90
91
```toml
92
[microvm]
93
firecracker = { path = "bin/firecracker", blake3 = "…" }
94
kernel = { path = "kernel/vmlinux", blake3 = "…" }
95
init = { path = "bin/flow-init", blake3 = "…" }
96
97
[runner]                     # only for `flow runner`
98
hub = "https://hub.example:7343"
99
token = "…"                  # listed in the hub's [flow] runner_tokens
100
ca = "/path/to/hub-ca.pem"   # when the hub's certificate is self-signed
101
name = "runner-1"
bb643c25 Andy McCall ↶ 102
max_jobs = 3                 # jobs at once (default 1)
103
memory_mib = 24576           # what they may use together; a lone job may use it all
104
cpus = 8
a083cc80 Andy McCall ↶ 105
```
106
107
Setting one up needs Linux x86-64 with KVM and e2fsprogs 1.43 or later:
108
109
1. Build `flow` with `cargo build --release -p flow`. Build the guest init
110
   as a static binary:
111
   `RUSTFLAGS="-C target-feature=+crt-static" cargo build --release -p flow-init --target x86_64-unknown-linux-gnu`.
112
2. Download Firecracker v1.17.0 from its GitHub release, and check the
113
   published SHA-256. Download the guest kernel
114
   `firecracker-ci/v1.15/x86_64/vmlinux-6.1.155` from Firecracker's CI
115
   bucket.
116
3. Run `flow rootfs import alpine-minirootfs-3.24.2-x86_64.tar.gz --sha256 …`.
117
4. Write `flow.toml`, pinning each file by its `flow hash`.
118
119
On OxygenHub, `hub.toml` lists the runner token and the repositories whose
120
pushes run pipelines:
121
122
```toml
123
[flow]
124
runner_tokens = ["…"]
125
repos = ["owner/*"]
126
```
127
128
## Tests
129
da5118d2 Andy McCall ↶ 130
**Changelog:** a commit that changes code adds a line under `## Unreleased` in CHANGELOG.md (Added, Changed, Fixed or Security, with the issue number); versions change only at release. `scripts/changelog-check.sh [PATH...]` checks it for the paths a commit takes (the working copy's changes without any) and runs in the gate; `NO_CHANGELOG=1` for code changes users won't notice.
131
132
a083cc80 Andy McCall ↶ 133
`cargo test --workspace` runs every test that needs no VM. The microVM
134
conformance test also runs when `FLOW_TEST_HOME` names a Flow home and
135
`FLOW_TEST_ROOTFS` is the hash of an Alpine rootfs in it. The test checks
136
literal argv, network isolation, the read-only rootfs, and that dependents
137
are skipped after a failure.
fe128fa6 Andy McCall ↶ 138
139
## oxygen as a pinned subrepo
140
141
`flow` builds against `deps/oxygen`, a subrepo (`oxy submodule`) pinned to an exact state, so builds are reproducible and OxygenFlow can build this repository without network. `make pins` moves it to oxygen's `main` on Earth (push oxygen first); the next commit records the new pin. Format only this workspace, `cargo fmt -p flow -p flow-core -p flow-init`: `--all` also reaches `deps/`. After a fresh clone, `oxy submodule update --init` fetches it.