diff --git a/harmony/src/modules/application/feature.rs b/harmony/src/modules/application/feature.rs index 260f818..870745e 100644 --- a/harmony/src/modules/application/feature.rs +++ b/harmony/src/modules/application/feature.rs @@ -3,7 +3,6 @@ use serde::Serialize; use crate::topology::Topology; -use super::Application; /// An ApplicationFeature provided by harmony, such as Backups, Monitoring, MultisiteAvailability, /// ContinuousIntegration, ContinuousDelivery #[async_trait] diff --git a/harmony/src/modules/application/features/argo_types.rs b/harmony/src/modules/application/features/argo_types.rs index 2c7a077..41ba8a3 100644 --- a/harmony/src/modules/application/features/argo_types.rs +++ b/harmony/src/modules/application/features/argo_types.rs @@ -3,7 +3,7 @@ use std::{backtrace, collections::HashMap}; use k8s_openapi::{Metadata, NamespaceResourceScope, Resource}; use log::debug; use serde::Serialize; -use serde_yaml::{Mapping, Value}; +use serde_yaml::Value; use url::Url; use crate::modules::application::features::CDApplicationConfig; @@ -186,7 +186,7 @@ impl ArgoApplication { let project = &self.project; let source = &self.source; - let mut yaml_str = format!( + let yaml_str = format!( r#" apiVersion: argoproj.io/v1alpha1 kind: Application @@ -210,20 +210,148 @@ spec: "# ); - yaml_str.push_str( - &serde_yaml::to_string(&source.clone()) - .expect("couldn't serialize source to yaml string"), + let mut yaml_value: Value = + serde_yaml::from_str(yaml_str.as_str()).expect("couldn't parse string to YAML"); + + let mut spec = yaml_value + .get_mut("spec") + .expect("couldn't get spec from yaml") + .as_mapping_mut() + .expect("couldn't unwrap spec as mutable mapping"); + + let source = + serde_yaml::to_value(&self.source).expect("couldn't serialize source to value"); + let sync_policy = serde_yaml::to_value(&self.sync_policy) + .expect("couldn't serialize sync_policy to value"); + let revision_history_limit = serde_yaml::to_value(&self.revision_history_limit) + .expect("couldn't serialize revision_history_limit to value"); + + spec.insert( + serde_yaml::to_value("source").expect("string to value failed"), + source, ); - yaml_str.push_str( - &serde_yaml::to_string(&self.sync_policy) - .expect("couldn't serialize sync policy to yaml string"), + spec.insert( + serde_yaml::to_value("syncPolicy").expect("string to value failed"), + sync_policy, ); - yaml_str.push_str( - &serde_yaml::to_string(&self.revision_history_limit) - .expect("couldn't serialize revision history to yaml string"), + spec.insert( + serde_yaml::to_value("revisionHistoryLimit") + .expect("couldn't convert str to yaml value"), + revision_history_limit, ); - debug!("yaml serialize of :\n{yaml_str}"); - serde_yaml::from_str(&yaml_str).expect("Couldn't parse YAML") + debug!("spec: {}", serde_yaml::to_string(spec).unwrap()); + debug!( + "entire yaml_value: {}", + serde_yaml::to_string(&yaml_value).unwrap() + ); + + yaml_value + } +} + +#[cfg(test)] +mod tests { + use url::Url; + + use crate::modules::application::features::{ + ArgoApplication, Automated, Backoff, Helm, Retry, Source, SyncPolicy, + }; + + #[test] + fn test_argo_application_to_yaml_happy_path() { + let app = ArgoApplication { + name: "test".to_string(), + namespace: Some("test-ns".to_string()), + project: "test-project".to_string(), + source: Source { + repo_url: Url::parse("http://test").unwrap(), + target_revision: None, + chart: "test-chart".to_string(), + helm: Helm { + pass_credentials: None, + parameters: vec![], + file_parameters: vec![], + release_name: Some("test-release-neame".to_string()), + value_files: vec![], + ignore_missing_value_files: None, + values: None, + values_object: None, + skip_crds: None, + skip_schema_validation: None, + version: None, + kube_version: None, + api_versions: vec![], + namespace: None, + }, + }, + sync_policy: SyncPolicy { + automated: Automated { + prune: false, + self_heal: false, + allow_empty: false, + }, + sync_options: vec![], + retry: Retry { + limit: 5, + backoff: Backoff { + duration: "5s".to_string(), + factor: 2, + max_duration: "3m".to_string(), + }, + }, + }, + revision_history_limit: 10, + }; + + let expected_yaml_output = r#"apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: test + namespace: test-ns +spec: + project: test-project + destination: + server: https://kubernetes.default.svc + namespace: test-ns + source: + repoUrl: http://test/ + targetRevision: null + chart: test-chart + helm: + passCredentials: null + parameters: [] + fileParameters: [] + releaseName: test-release-neame + valueFiles: [] + ignoreMissingValueFiles: null + values: null + valuesObject: null + skipCrds: null + skipSchemaValidation: null + version: null + kubeVersion: null + apiVersions: [] + namespace: null + syncPolicy: + automated: + prune: false + selfHeal: false + allowEmpty: false + syncOptions: [] + retry: + limit: 5 + backoff: + duration: 5s + factor: 2 + maxDuration: 3m + revisionHistoryLimit: 10"#; + + assert_eq!( + expected_yaml_output.trim(), + serde_yaml::to_string(&app.clone().to_yaml()) + .unwrap() + .trim() + ); } } diff --git a/harmony/src/modules/application/features/endpoint.rs b/harmony/src/modules/application/features/endpoint.rs index d4bff3a..042f0dd 100644 --- a/harmony/src/modules/application/features/endpoint.rs +++ b/harmony/src/modules/application/features/endpoint.rs @@ -2,7 +2,7 @@ use async_trait::async_trait; use log::info; use crate::{ - modules::application::{Application, ApplicationFeature}, + modules::application::ApplicationFeature, topology::{K8sclient, Topology}, }; diff --git a/harmony/src/modules/monitoring/kube_prometheus/prometheus.rs b/harmony/src/modules/monitoring/kube_prometheus/prometheus.rs index f9d8944..137ad6f 100644 --- a/harmony/src/modules/monitoring/kube_prometheus/prometheus.rs +++ b/harmony/src/modules/monitoring/kube_prometheus/prometheus.rs @@ -10,7 +10,7 @@ use crate::{ modules::monitoring::alert_rule::prometheus_alert_rule::AlertManagerRuleGroup, score, topology::{ - HelmCommand, K8sAnywhereTopology, Topology, + HelmCommand, Topology, installable::Installable, oberservability::monitoring::{AlertReceiver, AlertRule, AlertSender}, tenant::TenantManager,