use serde::{Deserialize, Serialize};
use crate::Manifest;
pub const DEFAULT_WADM_TOPIC_PREFIX: &str = "wadm.api";
pub const WADM_STATUS_API_PREFIX: &str = "wadm.status";
#[derive(Debug, Serialize, Deserialize)]
pub struct GetModelRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct GetModelResponse {
pub result: GetResult,
#[serde(default)]
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub manifest: Option<Manifest>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ListModelsResponse {
pub result: GetResult,
#[serde(default)]
pub message: String,
pub models: Vec<ModelSummary>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum GetResult {
Error,
Success,
NotFound,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct PutModelResponse {
pub result: PutResult,
#[serde(default)]
pub total_versions: usize,
#[serde(default)]
pub current_version: String,
#[serde(default)]
pub message: String,
#[serde(default)]
pub name: String,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum PutResult {
Error,
Created,
NewVersion,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ModelSummary {
pub name: String,
pub version: String,
pub description: Option<String>,
pub deployed_version: Option<String>,
#[serde(default)]
pub detailed_status: Status,
#[deprecated(since = "0.14.0", note = "Use detailed_status instead")]
pub status: StatusType,
#[deprecated(since = "0.14.0", note = "Use detailed_status instead")]
pub status_message: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct VersionResponse {
pub result: GetResult,
#[serde(default)]
pub message: String,
pub versions: Vec<VersionInfo>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct VersionInfo {
pub version: String,
pub deployed: bool,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DeleteModelRequest {
#[serde(default)]
pub version: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DeleteModelResponse {
pub result: DeleteResult,
#[serde(default)]
pub message: String,
#[serde(default)]
pub undeploy: bool,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum DeleteResult {
Deleted,
Error,
Noop,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DeployModelRequest {
pub version: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DeployModelResponse {
pub result: DeployResult,
#[serde(default)]
pub message: String,
#[serde(default)]
pub name: String,
#[serde(default)]
pub version: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum DeployResult {
Error,
Acknowledged,
NotFound,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct UndeployModelRequest {}
#[derive(Debug, Serialize, Deserialize)]
pub struct StatusResponse {
pub result: StatusResult,
#[serde(default)]
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<Status>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum StatusResult {
Error,
Ok,
NotFound,
}
#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
pub struct Status {
#[serde(rename = "status")]
pub info: StatusInfo,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub scalers: Vec<ScalerStatus>,
#[serde(default)]
#[deprecated(since = "0.14.0")]
pub version: String,
#[serde(default)]
#[deprecated(since = "0.14.0")]
pub components: Vec<ComponentStatus>,
}
impl Status {
pub fn new(info: StatusInfo, scalers: Vec<ScalerStatus>) -> Self {
#[allow(deprecated)]
Status {
info,
scalers,
version: String::with_capacity(0),
components: Vec::with_capacity(0),
}
}
}
#[derive(Debug, Serialize, Deserialize, Default, Clone, Eq, PartialEq)]
pub struct ComponentStatus {
pub name: String,
#[serde(rename = "type")]
pub component_type: String,
#[serde(rename = "status")]
pub info: StatusInfo,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub traits: Vec<TraitStatus>,
}
#[derive(Debug, Serialize, Deserialize, Default, Clone, Eq, PartialEq)]
pub struct TraitStatus {
#[serde(rename = "type")]
pub trait_type: String,
#[serde(rename = "status")]
pub info: StatusInfo,
}
#[derive(Debug, Serialize, Deserialize, Default, Clone, Eq, PartialEq)]
pub struct ScalerStatus {
#[serde(default)]
pub id: String,
#[serde(default)]
pub kind: String,
#[serde(default)]
pub name: String,
#[serde(rename = "status")]
pub info: StatusInfo,
}
#[derive(Debug, Serialize, Deserialize, Default, Clone, Eq, PartialEq)]
pub struct StatusInfo {
#[serde(rename = "type")]
pub status_type: StatusType,
#[serde(skip_serializing_if = "String::is_empty", default)]
pub message: String,
}
impl StatusInfo {
pub fn undeployed(message: &str) -> Self {
StatusInfo {
status_type: StatusType::Undeployed,
message: message.to_owned(),
}
}
pub fn deployed(message: &str) -> Self {
StatusInfo {
status_type: StatusType::Deployed,
message: message.to_owned(),
}
}
pub fn failed(message: &str) -> Self {
StatusInfo {
status_type: StatusType::Failed,
message: message.to_owned(),
}
}
pub fn reconciling(message: &str) -> Self {
StatusInfo {
status_type: StatusType::Reconciling,
message: message.to_owned(),
}
}
pub fn waiting(message: &str) -> Self {
StatusInfo {
status_type: StatusType::Waiting,
message: message.to_owned(),
}
}
pub fn unhealthy(message: &str) -> Self {
StatusInfo {
status_type: StatusType::Unhealthy,
message: message.to_owned(),
}
}
}
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Copy, Default)]
#[serde(rename_all = "lowercase")]
pub enum StatusType {
Waiting,
#[default]
Undeployed,
#[serde(alias = "compensating")]
Reconciling,
#[serde(alias = "ready")]
Deployed,
Failed,
Unhealthy,
}
impl std::ops::Add for StatusType {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
if self == rhs {
return self;
}
match (self, rhs) {
(Self::Failed, _) => Self::Failed,
(_, Self::Failed) => Self::Failed,
(Self::Undeployed, _) => Self::Undeployed,
(_, Self::Undeployed) => Self::Undeployed,
(Self::Waiting, _) => Self::Waiting,
(_, Self::Waiting) => Self::Waiting,
(Self::Reconciling, _) => Self::Reconciling,
(_, Self::Reconciling) => Self::Reconciling,
(Self::Unhealthy, _) => Self::Unhealthy,
(_, Self::Unhealthy) => Self::Unhealthy,
(Self::Deployed, Self::Deployed) => Self::Deployed,
}
}
}
impl std::iter::Sum for StatusType {
fn sum<I: Iterator<Item = Self>>(mut iter: I) -> Self {
let first = iter.next().unwrap_or_default();
iter.fold(first, |a, b| a + b)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_status_aggregate() {
assert!(matches!(
[StatusType::Deployed, StatusType::Deployed]
.into_iter()
.sum(),
StatusType::Deployed
));
assert!(matches!(
[StatusType::Undeployed, StatusType::Undeployed]
.into_iter()
.sum(),
StatusType::Undeployed
));
assert!(matches!(
[StatusType::Undeployed, StatusType::Failed]
.into_iter()
.sum(),
StatusType::Failed
));
assert!(matches!(
[StatusType::Reconciling, StatusType::Undeployed]
.into_iter()
.sum(),
StatusType::Undeployed
));
assert!(matches!(
[StatusType::Deployed, StatusType::Undeployed]
.into_iter()
.sum(),
StatusType::Undeployed
));
assert!(matches!(
[
StatusType::Deployed,
StatusType::Reconciling,
StatusType::Undeployed,
StatusType::Failed
]
.into_iter()
.sum(),
StatusType::Failed
));
assert!(matches!(
[StatusType::Deployed, StatusType::Unhealthy]
.into_iter()
.sum(),
StatusType::Unhealthy
));
assert!(matches!(
[StatusType::Reconciling, StatusType::Unhealthy]
.into_iter()
.sum(),
StatusType::Reconciling
));
let empty: Vec<StatusType> = Vec::new();
assert!(matches!(empty.into_iter().sum(), StatusType::Undeployed));
}
}