mod endpoint_mode;
pub mod resources;
use std::{
fmt::{self, Display, Formatter},
time::Duration,
};
use serde::{Deserialize, Serialize};
use crate::{serde::duration_option, Extensions, ListOrMap};
pub use self::{endpoint_mode::EndpointMode, resources::Resources};
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
pub struct Deploy {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub endpoint_mode: Option<EndpointMode>,
#[serde(default, skip_serializing_if = "ListOrMap::is_empty")]
pub labels: ListOrMap,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mode: Option<Mode>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub placement: Option<Placement>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub replicas: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub resources: Option<Resources>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub restart_policy: Option<RestartPolicy>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub rollback_config: Option<UpdateOrRollbackConfig>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub update_config: Option<UpdateOrRollbackConfig>,
#[serde(flatten)]
pub extensions: Extensions,
}
impl Deploy {
#[must_use]
pub fn is_empty(&self) -> bool {
let Self {
endpoint_mode,
labels,
mode,
placement,
replicas,
resources,
restart_policy,
rollback_config,
update_config,
extensions,
} = self;
endpoint_mode.is_none()
&& labels.is_empty()
&& mode.is_none()
&& !placement
.as_ref()
.is_some_and(|placement| !placement.is_empty())
&& replicas.is_none()
&& !resources
.as_ref()
.is_some_and(|resources| !resources.is_empty())
&& !restart_policy
.as_ref()
.is_some_and(|restart| !restart.is_empty())
&& !rollback_config
.as_ref()
.is_some_and(|rollback| !rollback.is_empty())
&& !update_config
.as_ref()
.is_some_and(|update| !update.is_empty())
&& extensions.is_empty()
}
}
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub enum Mode {
Global,
#[default]
Replicated,
}
impl Mode {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Global => "global",
Self::Replicated => "replicated",
}
}
}
impl AsRef<str> for Mode {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Display for Mode {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
pub struct Placement {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub constraints: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub preferences: Vec<Preference>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max_replicas_per_node: Option<u64>,
#[serde(flatten)]
pub extensions: Extensions,
}
impl Placement {
#[must_use]
pub fn is_empty(&self) -> bool {
let Self {
constraints,
preferences,
max_replicas_per_node,
extensions,
} = self;
constraints.is_empty()
&& preferences.iter().all(Preference::is_empty)
&& max_replicas_per_node.is_none()
&& extensions.is_empty()
}
}
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
pub struct Preference {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub spread: Option<String>,
#[serde(flatten)]
pub extensions: Extensions,
}
impl Preference {
#[must_use]
pub fn is_empty(&self) -> bool {
let Self { spread, extensions } = self;
spread.is_none() && extensions.is_empty()
}
}
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
pub struct RestartPolicy {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub condition: Option<RestartCondition>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "duration_option"
)]
pub delay: Option<Duration>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max_attempts: Option<u64>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "duration_option"
)]
pub window: Option<Duration>,
#[serde(flatten)]
pub extensions: Extensions,
}
impl RestartPolicy {
#[must_use]
pub fn is_empty(&self) -> bool {
let Self {
condition,
delay,
max_attempts,
window,
extensions,
} = self;
condition.is_none()
&& delay.is_none()
&& max_attempts.is_none()
&& window.is_none()
&& extensions.is_empty()
}
}
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub enum RestartCondition {
None,
OnFailure,
#[default]
Any,
}
impl RestartCondition {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::None => "none",
Self::OnFailure => "on-failure",
Self::Any => "any",
}
}
}
impl AsRef<str> for RestartCondition {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Display for RestartCondition {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
pub struct UpdateOrRollbackConfig {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parallelism: Option<u64>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "duration_option"
)]
pub delay: Option<Duration>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub failure_action: Option<FailureAction>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "duration_option"
)]
pub monitor: Option<Duration>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max_failure_ratio: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub order: Option<Order>,
#[serde(flatten)]
pub extensions: Extensions,
}
impl UpdateOrRollbackConfig {
#[must_use]
pub fn is_empty(&self) -> bool {
let Self {
parallelism,
delay,
failure_action,
monitor,
max_failure_ratio,
order,
extensions,
} = self;
parallelism.is_none()
&& delay.is_none()
&& failure_action.is_none()
&& monitor.is_none()
&& max_failure_ratio.is_none()
&& order.is_none()
&& extensions.is_empty()
}
}
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub enum FailureAction {
Continue,
#[default]
Pause,
}
impl FailureAction {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Continue => "continue",
Self::Pause => "pause",
}
}
}
impl AsRef<str> for FailureAction {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Display for FailureAction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub enum Order {
#[default]
StopFirst,
StartFirst,
}
impl Order {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::StopFirst => "stop-first",
Self::StartFirst => "start-first",
}
}
}
impl AsRef<str> for Order {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Display for Order {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str(self.as_str())
}
}