OXYGENHUB
# 2d025bbf9842 oxygenflow / crates / flow-core / src / api.rs
4.8 KiB · Rust · last changed Register runners with a token; describe them in claims 1 month ago source blame history raw
e0918b88 Andy McCall 1
//! The runner API between OxygenHub and `flow runner` (docs/m0.md §5).
2
//! Both sides use these types, so they cannot drift.
3
4
use crate::pipeline::{Job, Sandbox};
5
use crate::receipt::Receipt;
6
use serde::{Deserialize, Serialize};
7
8
/// `POST /api/v1/flow/claim`.
9
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
10
pub struct ClaimRequest {
11
    /// The runner's name, shown on job pages.
12
    pub runner: String,
13
    /// Tiers this runner can run (`microvm`, `syscall`).
14
    pub runtimes: Vec<String>,
bb643c25 Andy McCall ↶ 15
    /// Memory the runner has free for another job, in MiB: the hub hands
16
    /// out only a job whose sandbox fits. Absent: no limit.
17
    #[serde(default, skip_serializing_if = "Option::is_none")]
18
    pub free_memory_mib: Option<u32>,
19
    /// vCPUs the runner has free for another job. Absent: no limit.
20
    #[serde(default, skip_serializing_if = "Option::is_none")]
21
    pub free_cpus: Option<u32>,
f98a8f78 Andy McCall ↶ 22
    /// What the runner is, for the hub's Runners page.
23
    #[serde(default, skip_serializing_if = "Option::is_none")]
24
    pub info: Option<RunnerInfo>,
25
}
26
27
/// A runner's description: shown on the hub's Runners page, and what
28
/// scheduling by label and architecture will match.
29
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
30
pub struct RunnerInfo {
31
    /// `x86_64`, `aarch64`, `riscv64`, …
32
    pub arch: String,
33
    pub os: String,
34
    /// The `flow` version.
35
    pub version: String,
36
    /// From flow.toml `[runner] labels`.
37
    #[serde(default)]
38
    pub labels: Vec<String>,
39
    /// Jobs at once, and the memory (MiB) and vCPUs they share.
40
    pub max_jobs: u32,
41
    #[serde(default)]
42
    pub memory_mib: Option<u32>,
43
    #[serde(default)]
44
    pub cpus: Option<u32>,
45
}
46
47
impl RunnerInfo {
48
    /// This machine and build, with the given labels and capacity.
49
    pub fn here(labels: Vec<String>, max_jobs: u32, memory_mib: Option<u32>, cpus: Option<u32>) -> RunnerInfo {
50
        RunnerInfo {
51
            arch: std::env::consts::ARCH.into(),
52
            os: std::env::consts::OS.into(),
53
            version: env!("CARGO_PKG_VERSION").into(),
54
            labels,
55
            max_jobs,
56
            memory_mib,
57
            cpus,
58
        }
59
    }
60
}
61
62
/// `POST /api/v1/flow/runners/register`: exchange a one-time registration
63
/// token from the hub for a runner credential, binding the runner's
64
/// signing identity to it.
65
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
66
pub struct Register {
67
    pub token: String,
68
    pub name: String,
69
    /// The runner's Oxygen identity, hex of its encoding: its key signs
70
    /// every receipt, and the hub accepts no other for this runner.
71
    pub identity: String,
72
    pub info: RunnerInfo,
73
}
74
75
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
76
pub struct Registered {
77
    pub id: i64,
78
    pub name: String,
79
    /// The runner's bearer token from now on; shown once.
80
    pub credential: String,
e0918b88 Andy McCall 81
}
82
83
/// A claimed job: everything the runner needs, nothing more.
84
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
85
pub struct Claim {
86
    pub job_id: i64,
87
    pub run_id: i64,
88
    /// `owner/name`.
89
    pub repo: String,
90
    /// Where to fetch the repository from (`oxy` wire protocol).
91
    pub clone_url: String,
92
    /// Read access to this repository only, until the job finishes.
93
    pub token: String,
94
    /// The state to build, as full change hashes.
95
    pub heads: Vec<String>,
96
    /// Hex BLAKE3 of the canonical pipeline.
97
    pub pipeline_hash: String,
98
    pub job: Job,
99
    pub sandbox: Sandbox,
100
    /// The hub's limit for this job.
101
    pub timeout_s: u64,
102
}
103
104
/// One line of output (docs/m0.md §2).
105
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
106
pub struct Record {
107
    /// Milliseconds since the job started.
108
    pub t: u64,
109
    /// `out`, `err`, `console` (the VM outside the job) or `flow` (the runner).
110
    pub stream: String,
111
    pub text: String,
112
}
113
114
/// `POST /api/v1/flow/jobs/{id}/log`.
115
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
116
pub struct LogBatch {
117
    pub records: Vec<Record>,
118
}
119
120
/// `POST /api/v1/flow/jobs/{id}/finish`.
121
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
122
pub struct Finish {
123
    /// The job's exit code; absent when the runner could not run it.
124
    pub exit_code: Option<i32>,
125
    pub duration_ms: u64,
126
    pub receipt: Option<Receipt>,
47c1d64d Andy McCall ↶ 127
    /// The receipt bound to the job's state and signed by the runner
128
    /// (Oxygen spec §14.6), hex of the signed receipt's bytes.
129
    #[serde(default, skip_serializing_if = "Option::is_none")]
130
    pub signed_receipt: Option<String>,
e0918b88 Andy McCall 131
    /// Why the runner could not run the job (rootfs missing, VM failed).
132
    pub error: Option<String>,
133
}
134
135
/// Longest text of one record the hub keeps; longer lines are cut.
136
pub const MAX_RECORD_TEXT: usize = 16 * 1024;
137
/// Most records the hub keeps per job; later ones are dropped with a note.
138
pub const MAX_RECORDS: usize = 50_000;