1use crate::connector::JobError;
5use crate::image::manifest::ImageId;
6use crate::util::chrono::duration as human_duration;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use uuid::Uuid;
10
11pub mod websocket {
12 pub static TREADMILL_WEBSOCKET_PROTOCOL: &str = "treadmillv1";
13 pub static TREADMILL_WEBSOCKET_CONFIG: &str = "tml-socket-config";
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct SocketConfig {
20 pub keepalive: KeepaliveConfig,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct KeepaliveConfig {
26 #[serde(with = "human_duration")]
28 pub ping_interval: chrono::TimeDelta,
29 #[serde(with = "human_duration")]
31 pub keepalive: chrono::TimeDelta,
32}
33
34#[derive(Serialize, Deserialize, Clone)]
37pub struct ParameterValue {
38 pub value: String,
39 pub secret: bool,
40}
41
42impl std::fmt::Debug for ParameterValue {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
46 let mut debug_struct = f.debug_struct("ParameterValue");
47 debug_struct.field("secret", &self.secret);
48
49 debug_struct.field("value", if self.secret { &"***" } else { &self.value });
61
62 debug_struct.finish()
63 }
64}
65
66#[derive(Serialize, Deserialize, Debug, Clone)]
67#[serde(rename_all = "snake_case")]
68pub struct RendezvousServerSpec {
69 pub client_id: Uuid,
70 pub server_base_url: String,
71 pub auth_token: String,
72}
73#[derive(Serialize, Deserialize, Debug, Clone)]
74#[serde(tag = "type")]
75#[serde(rename_all = "snake_case")]
76pub enum ImageSpecification {
77 ResumeJob { job_id: Uuid },
79
80 Image { image_id: ImageId },
89}
90#[derive(Serialize, Deserialize, Debug, Clone)]
91#[serde(rename_all = "snake_case")]
92pub struct RestartPolicy {
93 pub remaining_restart_count: usize,
94}
95#[derive(Serialize, Deserialize, Debug, Clone)]
96#[serde(rename_all = "snake_case")]
97pub struct StartJobMessage {
98 pub job_id: Uuid,
106
107 pub image_spec: ImageSpecification,
108
109 pub ssh_keys: Vec<String>,
114
115 pub restart_policy: RestartPolicy,
116
117 pub ssh_rendezvous_servers: Vec<RendezvousServerSpec>,
123
124 pub parameters: HashMap<String, ParameterValue>,
127}
128
129#[derive(Serialize, Deserialize, Debug, Clone)]
132#[serde(rename_all = "snake_case")]
133pub struct StopJobMessage {
134 pub job_id: Uuid,
136}
137
138#[derive(Serialize, Deserialize, Debug, Clone)]
141#[serde(rename_all = "snake_case")]
142pub enum JobInitializingStage {
143 Starting,
145
146 FetchingImage,
148
149 Allocating,
152
153 Provisioning,
156
157 Booting,
160}
161#[derive(Serialize, Deserialize, Debug, Clone)]
178#[serde(tag = "state")]
179#[serde(rename_all = "snake_case")]
180pub enum RunningJobState {
181 Initializing { stage: JobInitializingStage },
182 Ready,
183 Terminating,
185 Terminated,
186}
187#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
188#[serde(rename_all = "snake_case")]
189pub enum JobUserExitStatus {
190 Success,
191 Error,
192 Unknown,
193}
194#[derive(Serialize, Deserialize, Debug, Clone)]
195#[serde(tag = "type")]
196#[serde(rename_all = "snake_case")]
197pub enum SupervisorJobEvent {
198 StateTransition {
199 new_state: RunningJobState,
200 status_message: Option<String>,
201 },
202 DeclareExitStatus {
203 user_exit_status: JobUserExitStatus,
204 host_output: Option<String>,
205 },
206 Error {
208 error: JobError,
209 },
210 ConsoleLog {
211 console_bytes: Vec<u8>,
212 },
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
216#[serde(tag = "type")]
217#[serde(rename_all = "snake_case")]
218pub enum ReportedSupervisorStatus {
219 OngoingJob {
220 job_id: Uuid,
221 job_state: RunningJobState,
222 },
223 Idle,
224}
225#[derive(Debug, Clone, Serialize, Deserialize)]
226#[serde(tag = "type")]
227#[serde(rename_all = "snake_case")]
228pub enum SupervisorEvent {
229 JobEvent {
230 job_id: Uuid,
231 event: SupervisorJobEvent,
232 },
233}
234
235#[derive(Serialize, Deserialize, Debug, Clone)]
238#[serde(rename_all = "snake_case")]
239pub struct Request<T> {
240 pub request_id: Uuid,
241 pub message: T,
242}
243#[derive(Serialize, Deserialize, Debug, Clone)]
244#[serde(rename_all = "snake_case")]
245pub struct Response<T> {
246 pub response_to_request_id: Uuid,
247 pub message: T,
248}
249#[derive(Serialize, Deserialize, Debug, Clone)]
250#[serde(rename_all = "snake_case")]
251#[serde(tag = "type", content = "message")]
252pub enum Message {
253 StartJob(StartJobMessage),
254
255 StopJob(StopJobMessage),
256
257 StatusRequest(Request<()>),
258 StatusResponse(Response<ReportedSupervisorStatus>),
259
260 SupervisorEvent(SupervisorEvent),
261}
262impl Message {
263 pub fn request_id(&self) -> Option<Uuid> {
264 match self {
265 Message::StatusRequest(r) => Some(r.request_id),
266 Message::StartJob(_)
267 | Message::StopJob(_)
268 | Message::StatusResponse(_)
269 | Message::SupervisorEvent(_) => None,
270 }
271 }
272 pub fn to_response_message(self) -> Result<Response<ResponseMessage>, Message> {
273 match self {
274 Message::StatusResponse(Response {
275 response_to_request_id,
276 message,
277 }) => Ok(Response {
278 response_to_request_id,
279 message: ResponseMessage::StatusResponse(message),
280 }),
281 x => Err(x),
282 }
283 }
284}
285#[derive(Debug)]
286#[non_exhaustive]
287pub enum ResponseMessage {
288 StatusResponse(ReportedSupervisorStatus),
289}