1use serde::{Deserialize, Serialize};
2
3use crate::Manifest;
4
5pub const DEFAULT_WADM_TOPIC_PREFIX: &str = "wadm.api";
7pub const WADM_STATUS_API_PREFIX: &str = "wadm.status";
8
9#[derive(Debug, Serialize, Deserialize)]
11pub struct GetModelRequest {
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub version: Option<String>,
14}
15
16#[derive(Debug, Serialize, Deserialize)]
18pub struct GetModelResponse {
19 pub result: GetResult,
20 #[serde(default)]
21 pub message: String,
22 #[serde(skip_serializing_if = "Option::is_none")]
23 pub manifest: Option<Manifest>,
24}
25
26#[derive(Debug, Serialize, Deserialize)]
27pub struct ListModelsResponse {
28 pub result: GetResult,
29 #[serde(default)]
30 pub message: String,
31 pub models: Vec<ModelSummary>,
32}
33
34#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
36#[serde(rename_all = "lowercase")]
37pub enum GetResult {
38 Error,
39 Success,
40 NotFound,
41}
42
43#[derive(Debug, Serialize, Deserialize)]
45pub struct PutModelResponse {
46 pub result: PutResult,
47 #[serde(default)]
48 pub total_versions: usize,
49 #[serde(default)]
50 pub current_version: String,
51 #[serde(default)]
52 pub message: String,
53 #[serde(default)]
54 pub name: String,
55}
56
57#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
59#[serde(rename_all = "lowercase")]
60pub enum PutResult {
61 Error,
62 Created,
63 NewVersion,
64}
65
66#[derive(Debug, Serialize, Deserialize, Clone)]
68pub struct ModelSummary {
69 pub name: String,
70 pub version: String,
71 pub description: Option<String>,
72 pub deployed_version: Option<String>,
73 #[serde(default)]
74 pub detailed_status: Status,
75 #[deprecated(since = "0.14.0", note = "Use detailed_status instead")]
76 pub status: StatusType,
77 #[deprecated(since = "0.14.0", note = "Use detailed_status instead")]
78 pub status_message: Option<String>,
79}
80
81#[derive(Debug, Serialize, Deserialize)]
83pub struct VersionResponse {
84 pub result: GetResult,
85 #[serde(default)]
86 pub message: String,
87 pub versions: Vec<VersionInfo>,
88}
89
90#[derive(Debug, Serialize, Deserialize, Clone)]
92pub struct VersionInfo {
93 pub version: String,
94 pub deployed: bool,
95}
96
97#[derive(Debug, Serialize, Deserialize)]
99pub struct DeleteModelRequest {
100 #[serde(default)]
101 pub version: Option<String>,
102}
103
104#[derive(Debug, Serialize, Deserialize)]
106pub struct DeleteModelResponse {
107 pub result: DeleteResult,
108 #[serde(default)]
109 pub message: String,
110 #[serde(default)]
111 pub undeploy: bool,
112}
113
114#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
116#[serde(rename_all = "lowercase")]
117pub enum DeleteResult {
118 Deleted,
119 Error,
120 Noop,
121}
122
123#[derive(Debug, Serialize, Deserialize)]
128pub struct DeployModelRequest {
129 pub version: Option<String>,
130}
131
132#[derive(Debug, Serialize, Deserialize)]
134pub struct DeployModelResponse {
135 pub result: DeployResult,
136 #[serde(default)]
137 pub message: String,
138 #[serde(default)]
139 pub name: String,
140 #[serde(default)]
141 pub version: Option<String>,
142}
143
144#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
146#[serde(rename_all = "lowercase")]
147pub enum DeployResult {
148 Error,
149 Acknowledged,
150 NotFound,
151}
152
153#[derive(Debug, Serialize, Deserialize)]
157pub struct UndeployModelRequest {}
158
159#[derive(Debug, Serialize, Deserialize)]
161pub struct StatusResponse {
162 pub result: StatusResult,
163 #[serde(default)]
164 pub message: String,
165 #[serde(skip_serializing_if = "Option::is_none")]
166 pub status: Option<Status>,
167}
168
169#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
171#[serde(rename_all = "lowercase")]
172pub enum StatusResult {
173 Error,
174 Ok,
175 NotFound,
176}
177
178#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
180pub struct Status {
181 #[serde(rename = "status")]
182 pub info: StatusInfo,
183 #[serde(skip_serializing_if = "Vec::is_empty", default)]
184 pub scalers: Vec<ScalerStatus>,
185 #[serde(default)]
186 #[deprecated(since = "0.14.0")]
187 pub version: String,
188 #[serde(default)]
189 #[deprecated(since = "0.14.0")]
190 pub components: Vec<ComponentStatus>,
191}
192
193impl Status {
194 pub fn new(info: StatusInfo, scalers: Vec<ScalerStatus>) -> Self {
195 #[allow(deprecated)]
196 Status {
197 info,
198 scalers,
199 version: String::with_capacity(0),
200 components: Vec::with_capacity(0),
201 }
202 }
203}
204
205#[derive(Debug, Serialize, Deserialize, Default, Clone, Eq, PartialEq)]
207pub struct ComponentStatus {
208 pub name: String,
209 #[serde(rename = "type")]
210 pub component_type: String,
211 #[serde(rename = "status")]
212 pub info: StatusInfo,
213 #[serde(skip_serializing_if = "Vec::is_empty", default)]
214 pub traits: Vec<TraitStatus>,
215}
216
217#[derive(Debug, Serialize, Deserialize, Default, Clone, Eq, PartialEq)]
219pub struct TraitStatus {
220 #[serde(rename = "type")]
221 pub trait_type: String,
222 #[serde(rename = "status")]
223 pub info: StatusInfo,
224}
225
226#[derive(Debug, Serialize, Deserialize, Default, Clone, Eq, PartialEq)]
228pub struct ScalerStatus {
229 #[serde(default)]
231 pub id: String,
232 #[serde(default)]
234 pub kind: String,
235 #[serde(default)]
237 pub name: String,
238 #[serde(rename = "status")]
239 pub info: StatusInfo,
240}
241
242#[derive(Debug, Serialize, Deserialize, Default, Clone, Eq, PartialEq)]
244pub struct StatusInfo {
245 #[serde(rename = "type")]
246 pub status_type: StatusType,
247 #[serde(skip_serializing_if = "String::is_empty", default)]
248 pub message: String,
249}
250
251impl StatusInfo {
252 pub fn undeployed(message: &str) -> Self {
253 StatusInfo {
254 status_type: StatusType::Undeployed,
255 message: message.to_owned(),
256 }
257 }
258
259 pub fn deployed(message: &str) -> Self {
260 StatusInfo {
261 status_type: StatusType::Deployed,
262 message: message.to_owned(),
263 }
264 }
265
266 pub fn failed(message: &str) -> Self {
267 StatusInfo {
268 status_type: StatusType::Failed,
269 message: message.to_owned(),
270 }
271 }
272
273 pub fn reconciling(message: &str) -> Self {
274 StatusInfo {
275 status_type: StatusType::Reconciling,
276 message: message.to_owned(),
277 }
278 }
279
280 pub fn waiting(message: &str) -> Self {
281 StatusInfo {
282 status_type: StatusType::Waiting,
283 message: message.to_owned(),
284 }
285 }
286
287 pub fn unhealthy(message: &str) -> Self {
288 StatusInfo {
289 status_type: StatusType::Unhealthy,
290 message: message.to_owned(),
291 }
292 }
293}
294
295#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Copy, Default)]
297#[serde(rename_all = "lowercase")]
298pub enum StatusType {
299 Waiting,
300 #[default]
301 Undeployed,
302 #[serde(alias = "compensating")]
303 Reconciling,
304 #[serde(alias = "ready")]
305 Deployed,
306 Failed,
307 Unhealthy,
308}
309
310impl std::ops::Add for StatusType {
312 type Output = Self;
313
314 fn add(self, rhs: Self) -> Self::Output {
315 if self == rhs {
317 return self;
318 }
319
320 match (self, rhs) {
324 (Self::Failed, _) => Self::Failed,
326 (_, Self::Failed) => Self::Failed,
327 (Self::Undeployed, _) => Self::Undeployed,
329 (_, Self::Undeployed) => Self::Undeployed,
330 (Self::Waiting, _) => Self::Waiting,
332 (_, Self::Waiting) => Self::Waiting,
333 (Self::Reconciling, _) => Self::Reconciling,
334 (_, Self::Reconciling) => Self::Reconciling,
335 (Self::Unhealthy, _) => Self::Unhealthy,
336 (_, Self::Unhealthy) => Self::Unhealthy,
337 (Self::Deployed, Self::Deployed) => Self::Deployed,
339 }
340 }
341}
342
343impl std::iter::Sum for StatusType {
344 fn sum<I: Iterator<Item = Self>>(mut iter: I) -> Self {
345 let first = iter.next().unwrap_or_default();
347 iter.fold(first, |a, b| a + b)
348 }
349}
350
351#[cfg(test)]
352mod test {
353 use super::*;
354
355 #[test]
356 fn test_status_aggregate() {
357 assert!(matches!(
358 [StatusType::Deployed, StatusType::Deployed]
359 .into_iter()
360 .sum(),
361 StatusType::Deployed
362 ));
363
364 assert!(matches!(
365 [StatusType::Undeployed, StatusType::Undeployed]
366 .into_iter()
367 .sum(),
368 StatusType::Undeployed
369 ));
370
371 assert!(matches!(
372 [StatusType::Undeployed, StatusType::Failed]
373 .into_iter()
374 .sum(),
375 StatusType::Failed
376 ));
377
378 assert!(matches!(
379 [StatusType::Reconciling, StatusType::Undeployed]
380 .into_iter()
381 .sum(),
382 StatusType::Undeployed
383 ));
384
385 assert!(matches!(
386 [StatusType::Deployed, StatusType::Undeployed]
387 .into_iter()
388 .sum(),
389 StatusType::Undeployed
390 ));
391
392 assert!(matches!(
393 [
394 StatusType::Deployed,
395 StatusType::Reconciling,
396 StatusType::Undeployed,
397 StatusType::Failed
398 ]
399 .into_iter()
400 .sum(),
401 StatusType::Failed
402 ));
403
404 assert!(matches!(
405 [StatusType::Deployed, StatusType::Unhealthy]
406 .into_iter()
407 .sum(),
408 StatusType::Unhealthy
409 ));
410
411 assert!(matches!(
412 [StatusType::Reconciling, StatusType::Unhealthy]
413 .into_iter()
414 .sum(),
415 StatusType::Reconciling
416 ));
417
418 let empty: Vec<StatusType> = Vec::new();
419 assert!(matches!(empty.into_iter().sum(), StatusType::Undeployed));
420 }
421}