Files
Infrastruktur-Monitoring-Sy…/backend/crates/application/src/cluster_service.rs
Dennis Nemec 8f36a54da0
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / ui (push) Has been cancelled
WP-12: Kubernetes overview and workload actions
kube-rs gateway (nodes, namespaces, deployments/statefulsets/daemonsets with
images, PVCs; rollout restart, scale, set image via patches) using the
microk8s kubeconfig by default, fake gateway for dev, /api/cluster routes,
Kubernetes page with node cards, workload table with admin actions and PVC
list. Also implements the streaming command runner that WP-11 relied on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 22:33:57 +02:00

67 lines
2.0 KiB
Rust

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<dyn ClusterGateway>,
}
impl ClusterService {
pub fn new(gateway: Arc<dyn ClusterGateway>) -> Self {
Self { gateway }
}
pub async fn overview(&self) -> Result<ClusterOverview, DomainError> {
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<String>,
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)
}