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>
67 lines
2.0 KiB
Rust
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)
|
|
}
|