use std::sync::Arc; use domain::cluster::{ validate_image, validate_k8s_name, ClusterOverview, WorkloadRef, MAX_REPLICAS, }; use domain::ports::ClusterGateway; use domain::DomainError; pub struct ClusterService { gateway: Arc, } impl ClusterService { pub fn new(gateway: Arc) -> Self { Self { gateway } } pub async fn overview(&self) -> Result { self.gateway.overview().await } pub async fn restart(&self, w: WorkloadRef) -> Result<(), DomainError> { validate_ref(&w)?; self.gateway.restart(&w).await } pub async fn scale(&self, w: WorkloadRef, replicas: i32) -> Result<(), DomainError> { validate_ref(&w)?; if !(0..=MAX_REPLICAS).contains(&replicas) { return Err(DomainError::Validation(format!( "replicas must be between 0 and {MAX_REPLICAS}" ))); } self.gateway.scale(&w, replicas).await } /// Change the image of `container` (default: the workload's first container). pub async fn set_image( &self, w: WorkloadRef, container: Option, image: &str, ) -> Result<(), DomainError> { validate_ref(&w)?; validate_image(image)?; let container = match container { Some(c) => c, None => { let overview = self.gateway.overview().await?; overview .workloads .iter() .find(|x| x.namespace == w.namespace && x.kind == w.kind && x.name == w.name) .and_then(|x| x.containers.first()) .map(|c| c.name.clone()) .ok_or(DomainError::NotFound)? } }; self.gateway.set_image(&w, &container, image).await } } fn validate_ref(w: &WorkloadRef) -> Result<(), DomainError> { validate_k8s_name(&w.namespace)?; validate_k8s_name(&w.name) }