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, maestro::Maestro,
modules::{ modules::{
lamp::{LAMPConfig, LAMPScore}, lamp::{LAMPConfig, LAMPScore},
monitoring::monitoring_alerting::{AlertChannel, MonitoringAlertingStackScore}, monitoring::monitoring_alerting::MonitoringAlertingStackScore,
}, },
topology::{K8sAnywhereTopology, Url}, topology::{K8sAnywhereTopology, Url},
}; };
@ -43,9 +43,6 @@ async fn main() {
.await .await
.unwrap(); .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(); let mut monitoring_stack_score = MonitoringAlertingStackScore::new();
monitoring_stack_score.namespace = Some(lamp_stack.config.namespace.clone()); 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 k8s_openapi::{ClusterResourceScope, NamespaceResourceScope};
use kube::{ use kube::{
Api, Client, Config, Error, Resource, Api, Client, Config, Error, Resource,
api::PostParams, api::{Patch, PatchParams},
config::{KubeConfigOptions, Kubeconfig}, config::{KubeConfigOptions, Kubeconfig},
}; };
use log::{debug, error, trace}; 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 where
K: Resource + Clone + std::fmt::Debug + DeserializeOwned + serde::Serialize, K: Resource + Clone + std::fmt::Debug + DeserializeOwned + serde::Serialize,
<K as Resource>::Scope: ApplyStrategy<K>, <K as Resource>::Scope: ApplyStrategy<K>,
@ -29,12 +32,21 @@ impl K8sClient {
debug!( debug!(
"Applying resource {:?} with ns {:?}", "Applying resource {:?} with ns {:?}",
resource.meta().name, resource.meta().name,
ns namespace
); );
trace!("{:#?}", serde_json::to_string(resource)); trace!("{:#?}", serde_json::to_string(resource));
let api: Api<K> = <<K as Resource>::Scope as ApplyStrategy<K>>::get_api(&self.client, ns); let api: Api<K> =
api.create(&PostParams::default(), &resource).await <<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> 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 async_trait::async_trait;
use inquire::Confirm; use inquire::Confirm;
@ -25,7 +25,7 @@ use super::{
struct K8sState { struct K8sState {
client: Arc<K8sClient>, client: Arc<K8sClient>,
source: K8sSource, _source: K8sSource,
message: String, message: String,
} }
@ -122,7 +122,7 @@ impl K8sAnywhereTopology {
Some(client) => { Some(client) => {
return Ok(Some(K8sState { return Ok(Some(K8sState {
client: Arc::new(client), client: Arc::new(client),
source: K8sSource::Kubeconfig, _source: K8sSource::Kubeconfig,
message: format!("Loaded k8s client from kubeconfig {kubeconfig}"), message: format!("Loaded k8s client from kubeconfig {kubeconfig}"),
})); }));
} }
@ -162,7 +162,7 @@ impl K8sAnywhereTopology {
let state = match k3d.get_client().await { let state = match k3d.get_client().await {
Ok(client) => K8sState { Ok(client) => K8sState {
client: Arc::new(K8sClient::new(client)), client: Arc::new(K8sClient::new(client)),
source: K8sSource::LocalK3d, _source: K8sSource::LocalK3d,
message: "Successfully installed K3D cluster and acquired client".to_string(), message: "Successfully installed K3D cluster and acquired client".to_string(),
}, },
Err(_) => todo!(), Err(_) => todo!(),

View File

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

View File

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

View File

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