feat: K8s apply function now correctly emulates kubectl apply behavior by either creating or updating resources (#55)
Some checks failed
Run Check Script / check (push) Has been cancelled

Reviewed-on: https://git.nationtech.io/NationTech/harmony/pulls/55
Co-authored-by: Jean-Gabriel Gill-Couture <jg@nationtech.io>
Co-committed-by: Jean-Gabriel Gill-Couture <jg@nationtech.io>
This commit is contained in:
Jean-Gabriel Gill-Couture 2025-06-09 20:19:54 +00:00 committed by johnride
parent bf7a6d590c
commit 415488ba39
6 changed files with 27 additions and 22 deletions

View File

@ -4,7 +4,7 @@ use harmony::{
maestro::Maestro,
modules::{
lamp::{LAMPConfig, LAMPScore},
monitoring::monitoring_alerting::{AlertChannel, MonitoringAlertingStackScore},
monitoring::monitoring_alerting::MonitoringAlertingStackScore,
},
topology::{K8sAnywhereTopology, Url},
};
@ -43,9 +43,6 @@ async fn main() {
.await
.unwrap();
let url = url::Url::parse("https://discord.com/api/webhooks/dummy_channel/dummy_token")
.expect("invalid URL");
let mut monitoring_stack_score = MonitoringAlertingStackScore::new();
monitoring_stack_score.namespace = Some(lamp_stack.config.namespace.clone());

View File

@ -2,7 +2,7 @@ use derive_new::new;
use k8s_openapi::{ClusterResourceScope, NamespaceResourceScope};
use kube::{
Api, Client, Config, Error, Resource,
api::PostParams,
api::{Patch, PatchParams},
config::{KubeConfigOptions, Kubeconfig},
};
use log::{debug, error, trace};
@ -20,7 +20,10 @@ impl K8sClient {
})
}
pub async fn apply<K>(&self, resource: &K, ns: Option<&str>) -> Result<K, Error>
/// Apply a resource in namespace
///
/// See `kubectl apply` for more information on the expected behavior of this function
pub async fn apply<K>(&self, resource: &K, namespace: Option<&str>) -> Result<K, Error>
where
K: Resource + Clone + std::fmt::Debug + DeserializeOwned + serde::Serialize,
<K as Resource>::Scope: ApplyStrategy<K>,
@ -29,12 +32,21 @@ impl K8sClient {
debug!(
"Applying resource {:?} with ns {:?}",
resource.meta().name,
ns
namespace
);
trace!("{:#?}", serde_json::to_string(resource));
let api: Api<K> = <<K as Resource>::Scope as ApplyStrategy<K>>::get_api(&self.client, ns);
api.create(&PostParams::default(), &resource).await
let api: Api<K> =
<<K as Resource>::Scope as ApplyStrategy<K>>::get_api(&self.client, namespace);
// api.create(&PostParams::default(), &resource).await
let patch_params = PatchParams::apply("harmony");
let name = resource
.meta()
.name
.as_ref()
.expect("K8s Resource should have a name");
api.patch(name, &patch_params, &Patch::Apply(resource))
.await
}
pub async fn apply_many<K>(&self, resource: &Vec<K>, ns: Option<&str>) -> Result<Vec<K>, Error>

View File

@ -1,4 +1,4 @@
use std::{io::Error, process::Command, sync::Arc};
use std::{process::Command, sync::Arc};
use async_trait::async_trait;
use inquire::Confirm;
@ -25,7 +25,7 @@ use super::{
struct K8sState {
client: Arc<K8sClient>,
source: K8sSource,
_source: K8sSource,
message: String,
}
@ -122,7 +122,7 @@ impl K8sAnywhereTopology {
Some(client) => {
return Ok(Some(K8sState {
client: Arc::new(client),
source: K8sSource::Kubeconfig,
_source: K8sSource::Kubeconfig,
message: format!("Loaded k8s client from kubeconfig {kubeconfig}"),
}));
}
@ -162,7 +162,7 @@ impl K8sAnywhereTopology {
let state = match k3d.get_client().await {
Ok(client) => K8sState {
client: Arc::new(K8sClient::new(client)),
source: K8sSource::LocalK3d,
_source: K8sSource::LocalK3d,
message: "Successfully installed K3D cluster and acquired client".to_string(),
},
Err(_) => todo!(),

View File

@ -1,7 +1,6 @@
use async_trait::async_trait;
use std::fmt::Debug;
use url::Url;
use crate::interpret::InterpretError;

View File

@ -3,12 +3,9 @@ use std::sync::Arc;
use crate::{data::Id, executors::ExecutorError, topology::k8s::K8sClient};
use async_trait::async_trait;
use derive_new::new;
use k8s_openapi::{
NamespaceResourceScope,
api::{
use k8s_openapi::api::{
core::v1::{Namespace, ResourceQuota},
networking::v1::NetworkPolicy,
},
};
use kube::Resource;
use serde::de::DeserializeOwned;

View File

@ -311,7 +311,7 @@ impl<T: Topology + K8sclient + HelmCommand> Interpret<T> for HelmChartInterpretV
_inventory: &Inventory,
_topology: &T,
) -> Result<Outcome, InterpretError> {
let ns = self
let _ns = self
.score
.chart
.namespace
@ -339,7 +339,7 @@ impl<T: Topology + K8sclient + HelmCommand> Interpret<T> for HelmChartInterpretV
let res = helm_executor.generate();
let output = match res {
let _output = match res {
Ok(output) => output,
Err(err) => return Err(InterpretError::new(err.to_string())),
};