use chrono::Duration;
use serde::{Deserialize, Serialize};
use crate::health::HealthCheckConfig;
use crate::storage::LargeReleaseStrategy;
#[derive(Debug, Clone, Default)]
pub struct InstallOptions {
pub name: String,
pub namespace: String,
pub wait: bool,
pub timeout: Option<Duration>,
pub health_check: Option<HealthCheckConfig>,
pub atomic: bool,
pub create_namespace: bool,
pub large_release_strategy: LargeReleaseStrategy,
pub skip_schema_validation: bool,
pub dry_run: bool,
pub show_diff: bool,
pub labels: std::collections::HashMap<String, String>,
pub description: Option<String>,
}
impl InstallOptions {
pub fn new(name: impl Into<String>, namespace: impl Into<String>) -> Self {
Self {
name: name.into(),
namespace: namespace.into(),
..Default::default()
}
}
pub fn with_wait(mut self, timeout: Duration) -> Self {
self.wait = true;
self.timeout = Some(timeout);
self
}
pub fn with_atomic(mut self, timeout: Duration) -> Self {
self.wait = true;
self.atomic = true;
self.timeout = Some(timeout);
self
}
pub fn with_health_check(mut self, config: HealthCheckConfig) -> Self {
self.health_check = Some(config);
self
}
pub fn dry_run(mut self) -> Self {
self.dry_run = true;
self
}
pub fn with_diff(mut self) -> Self {
self.show_diff = true;
self
}
}
#[derive(Debug, Clone, Default)]
pub struct UpgradeOptions {
pub name: String,
pub namespace: String,
pub wait: bool,
pub timeout: Option<Duration>,
pub health_check: Option<HealthCheckConfig>,
pub atomic: bool,
pub install: bool,
pub force: bool,
pub immutable_strategy: ImmutableStrategy,
pub skip_schema_validation: bool,
pub reset_values: bool,
pub reuse_values: bool,
pub dry_run: bool,
pub show_diff: bool,
pub no_hooks: bool,
pub max_history: Option<u32>,
pub labels: std::collections::HashMap<String, String>,
pub description: Option<String>,
}
impl UpgradeOptions {
pub fn new(name: impl Into<String>, namespace: impl Into<String>) -> Self {
Self {
name: name.into(),
namespace: namespace.into(),
..Default::default()
}
}
pub fn with_install(mut self) -> Self {
self.install = true;
self
}
pub fn with_atomic(mut self, timeout: Duration) -> Self {
self.wait = true;
self.atomic = true;
self.timeout = Some(timeout);
self
}
pub fn with_force(mut self) -> Self {
self.force = true;
self
}
pub fn with_immutable_strategy(mut self, strategy: ImmutableStrategy) -> Self {
self.immutable_strategy = strategy;
self
}
}
#[derive(Debug, Clone, Default)]
pub struct UninstallOptions {
pub name: String,
pub namespace: String,
pub wait: bool,
pub timeout: Option<Duration>,
pub keep_history: bool,
pub no_hooks: bool,
pub dry_run: bool,
pub cascade: DeletionCascade,
pub description: Option<String>,
}
impl UninstallOptions {
pub fn new(name: impl Into<String>, namespace: impl Into<String>) -> Self {
Self {
name: name.into(),
namespace: namespace.into(),
cascade: DeletionCascade::Background,
..Default::default()
}
}
pub fn keep_history(mut self) -> Self {
self.keep_history = true;
self
}
pub fn with_wait(mut self, timeout: Duration) -> Self {
self.wait = true;
self.timeout = Some(timeout);
self
}
}
#[derive(Debug, Clone, Default)]
pub struct RollbackOptions {
pub name: String,
pub namespace: String,
pub revision: u32,
pub wait: bool,
pub timeout: Option<Duration>,
pub health_check: Option<HealthCheckConfig>,
pub force: bool,
pub immutable_strategy: ImmutableStrategy,
pub pvc_strategy: PvcStrategy,
pub no_hooks: bool,
pub dry_run: bool,
pub show_diff: bool,
pub recreate_pods: bool,
pub max_history: Option<u32>,
pub description: Option<String>,
}
impl RollbackOptions {
pub fn new(name: impl Into<String>, namespace: impl Into<String>) -> Self {
Self {
name: name.into(),
namespace: namespace.into(),
..Default::default()
}
}
pub fn to_revision(mut self, revision: u32) -> Self {
self.revision = revision;
self
}
pub fn with_force(mut self) -> Self {
self.force = true;
self
}
pub fn with_wait(mut self, timeout: Duration) -> Self {
self.wait = true;
self.timeout = Some(timeout);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ImmutableStrategy {
#[default]
Fail,
Recreate,
Skip,
}
impl std::fmt::Display for ImmutableStrategy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Fail => write!(f, "fail"),
Self::Recreate => write!(f, "recreate"),
Self::Skip => write!(f, "skip"),
}
}
}
impl std::str::FromStr for ImmutableStrategy {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"fail" => Ok(Self::Fail),
"recreate" => Ok(Self::Recreate),
"skip" => Ok(Self::Skip),
_ => Err(format!("unknown immutable strategy: {}", s)),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum PvcStrategy {
#[default]
Preserve,
WarnAndPreserve,
RestoreSnapshot {
snapshot_class: String,
},
}
impl std::fmt::Display for PvcStrategy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Preserve => write!(f, "preserve"),
Self::WarnAndPreserve => write!(f, "warn"),
Self::RestoreSnapshot { .. } => write!(f, "restore-snapshot"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum DeletionCascade {
#[default]
Background,
Foreground,
Orphan,
}
impl std::fmt::Display for DeletionCascade {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Background => write!(f, "background"),
Self::Foreground => write!(f, "foreground"),
Self::Orphan => write!(f, "orphan"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_install_options_builder() {
let opts = InstallOptions::new("myapp", "default")
.with_wait(Duration::minutes(5))
.with_diff();
assert_eq!(opts.name, "myapp");
assert_eq!(opts.namespace, "default");
assert!(opts.wait);
assert!(opts.show_diff);
}
#[test]
fn test_upgrade_options_atomic() {
let opts = UpgradeOptions::new("myapp", "default")
.with_atomic(Duration::minutes(10))
.with_install();
assert!(opts.wait);
assert!(opts.atomic);
assert!(opts.install);
}
#[test]
fn test_rollback_options() {
let opts = RollbackOptions::new("myapp", "default")
.to_revision(3)
.with_force();
assert_eq!(opts.revision, 3);
assert!(opts.force);
}
#[test]
fn test_immutable_strategy_parse() {
assert_eq!(
"recreate".parse::<ImmutableStrategy>().unwrap(),
ImmutableStrategy::Recreate
);
assert_eq!(
"fail".parse::<ImmutableStrategy>().unwrap(),
ImmutableStrategy::Fail
);
}
}