From 3bf5cb052654688b9323abb0520218f4d58f5682 Mon Sep 17 00:00:00 2001 From: Ian Letourneau Date: Mon, 8 Sep 2025 21:53:44 -0400 Subject: [PATCH] use topology domain to build & push helm package for continuous deliery --- .../src/main.rs | 1 - .../rhob_application_monitoring/src/main.rs | 1 - examples/rust/src/main.rs | 1 - examples/try_rust_webapp/src/main.rs | 1 - harmony/src/domain/topology/ingress.rs | 5 ++-- harmony/src/domain/topology/k8s_anywhere.rs | 4 ++- .../features/continuous_delivery.rs | 15 ++++++++--- .../application/features/helm_argocd_score.rs | 2 +- harmony/src/modules/application/oci.rs | 9 ++++--- harmony/src/modules/application/rust.rs | 26 ++++++++++--------- .../modules/prometheus/rhob_alerting_score.rs | 4 +-- 11 files changed, 39 insertions(+), 30 deletions(-) diff --git a/examples/application_monitoring_with_tenant/src/main.rs b/examples/application_monitoring_with_tenant/src/main.rs index f46a993..ad6e634 100644 --- a/examples/application_monitoring_with_tenant/src/main.rs +++ b/examples/application_monitoring_with_tenant/src/main.rs @@ -27,7 +27,6 @@ async fn main() { }; let application = Arc::new(RustWebapp { name: "example-monitoring".to_string(), - domain: Url::Url(url::Url::parse("https://rustapp.harmony.example.com").unwrap()), project_root: PathBuf::from("./examples/rust/webapp"), framework: Some(RustWebFramework::Leptos), service_port: 3000, diff --git a/examples/rhob_application_monitoring/src/main.rs b/examples/rhob_application_monitoring/src/main.rs index dd6a05c..fdcff48 100644 --- a/examples/rhob_application_monitoring/src/main.rs +++ b/examples/rhob_application_monitoring/src/main.rs @@ -17,7 +17,6 @@ use harmony_types::net::Url; async fn main() { let application = Arc::new(RustWebapp { name: "test-rhob-monitoring".to_string(), - domain: Url::Url(url::Url::parse("htps://some-fake-url").unwrap()), project_root: PathBuf::from("./webapp"), // Relative from 'harmony-path' param framework: Some(RustWebFramework::Leptos), service_port: 3000, diff --git a/examples/rust/src/main.rs b/examples/rust/src/main.rs index 063fdb6..ff6d769 100644 --- a/examples/rust/src/main.rs +++ b/examples/rust/src/main.rs @@ -19,7 +19,6 @@ use harmony_macros::hurl; async fn main() { let application = Arc::new(RustWebapp { name: "harmony-example-rust-webapp".to_string(), - domain: hurl!("https://rustapp.harmony.example.com"), project_root: PathBuf::from("./webapp"), framework: Some(RustWebFramework::Leptos), service_port: 3000, diff --git a/examples/try_rust_webapp/src/main.rs b/examples/try_rust_webapp/src/main.rs index 6e1ab63..84fe19b 100644 --- a/examples/try_rust_webapp/src/main.rs +++ b/examples/try_rust_webapp/src/main.rs @@ -17,7 +17,6 @@ use harmony_types::net::Url; async fn main() { let application = Arc::new(RustWebapp { name: "harmony-example-tryrust".to_string(), - domain: Url::Url(url::Url::parse("https://tryrust.harmony.example.com").unwrap()), project_root: PathBuf::from("./tryrust.org"), framework: Some(RustWebFramework::Leptos), service_port: 8080, diff --git a/harmony/src/domain/topology/ingress.rs b/harmony/src/domain/topology/ingress.rs index d27eb48..8ef3502 100644 --- a/harmony/src/domain/topology/ingress.rs +++ b/harmony/src/domain/topology/ingress.rs @@ -1,8 +1,7 @@ -use crate::topology::{PreparationError, k8s::K8sClient}; +use crate::topology::PreparationError; use async_trait::async_trait; -use std::sync::Arc; #[async_trait] pub trait Ingress { - async fn get_domain(&self, client: Arc) -> Result; + async fn get_domain(&self) -> Result; } diff --git a/harmony/src/domain/topology/k8s_anywhere.rs b/harmony/src/domain/topology/k8s_anywhere.rs index 571f9ea..0f46eca 100644 --- a/harmony/src/domain/topology/k8s_anywhere.rs +++ b/harmony/src/domain/topology/k8s_anywhere.rs @@ -576,7 +576,9 @@ impl TenantManager for K8sAnywhereTopology { #[async_trait] impl Ingress for K8sAnywhereTopology { //TODO this is specifically for openshift/okd which violates the k8sanywhere idea - async fn get_domain(&self, client: Arc) -> Result { + async fn get_domain(&self) -> Result { + let client = self.k8s_client().await?; + if let Some(Some(k8s_state)) = self.k8s_state.get() { match k8s_state.source { K8sSource::LocalK3d => Ok("localhost".to_string()), diff --git a/harmony/src/modules/application/features/continuous_delivery.rs b/harmony/src/modules/application/features/continuous_delivery.rs index 4ad06aa..33c03eb 100644 --- a/harmony/src/modules/application/features/continuous_delivery.rs +++ b/harmony/src/modules/application/features/continuous_delivery.rs @@ -1,4 +1,4 @@ -use std::{io::Write, process::Command, sync::Arc}; +use std::{io::Write, marker::PhantomData, process::Command, sync::Arc}; use async_trait::async_trait; use log::info; @@ -10,10 +10,13 @@ use crate::{ data::Version, inventory::Inventory, modules::application::{ - features::{ArgoApplication, ArgoHelmScore}, ApplicationFeature, HelmPackage, OCICompliant + ApplicationFeature, HelmPackage, OCICompliant, + features::{ArgoApplication, ArgoHelmScore}, }, score::Score, - topology::{ingress::Ingress, DeploymentTarget, HelmCommand, K8sclient, MultiTargetTopology, Topology}, + topology::{ + DeploymentTarget, HelmCommand, K8sclient, MultiTargetTopology, Topology, ingress::Ingress, + }, }; /// ContinuousDelivery in Harmony provides this functionality : @@ -140,13 +143,17 @@ impl< { async fn ensure_installed(&self, topology: &T) -> Result<(), String> { let image = self.application.image_name(); + let domain_host = topology.get_domain().await.map_err(|e| e.to_string())?; // TODO Write CI/CD workflow files // we can autotedect the CI type using the remote url (default to github action for github // url, etc..) // Or ask for it when unknown - let helm_chart = self.application.build_push_helm_package(&image).await?; + let helm_chart = self + .application + .build_push_helm_package(&image, &domain_host) + .await?; // TODO: Make building image configurable/skippable if image already exists (prompt)") // https://git.nationtech.io/NationTech/harmony/issues/104 diff --git a/harmony/src/modules/application/features/helm_argocd_score.rs b/harmony/src/modules/application/features/helm_argocd_score.rs index f49ca0d..944eedc 100644 --- a/harmony/src/modules/application/features/helm_argocd_score.rs +++ b/harmony/src/modules/application/features/helm_argocd_score.rs @@ -55,7 +55,7 @@ impl Interpret for ArgoInter topology: &T, ) -> Result { let k8s_client = topology.k8s_client().await?; - let domain = topology.get_domain(k8s_client.clone()).await?; + let domain = topology.get_domain().await?; let domain = format!("argo.{domain}"); let helm_score = argo_helm_chart_score(&self.score.namespace, self.score.openshift, &domain); diff --git a/harmony/src/modules/application/oci.rs b/harmony/src/modules/application/oci.rs index bf9f393..4085aa0 100644 --- a/harmony/src/modules/application/oci.rs +++ b/harmony/src/modules/application/oci.rs @@ -1,6 +1,5 @@ -use async_trait::async_trait; - use super::Application; +use async_trait::async_trait; #[async_trait] pub trait OCICompliant: Application { @@ -17,5 +16,9 @@ pub trait HelmPackage: Application { /// /// # Arguments /// * `image_url` - The full URL of the OCI container image to be used in the Deployment. - async fn build_push_helm_package(&self, image_url: &str) -> Result; + async fn build_push_helm_package( + &self, + image_url: &str, + domain_host: &str, + ) -> Result; } diff --git a/harmony/src/modules/application/rust.rs b/harmony/src/modules/application/rust.rs index 8fe28d6..b56ac94 100644 --- a/harmony/src/modules/application/rust.rs +++ b/harmony/src/modules/application/rust.rs @@ -1,5 +1,4 @@ -use std::fs::{self, File}; -use std::io::Read; +use std::fs::{self}; use std::path::{Path, PathBuf}; use std::process; use std::sync::Arc; @@ -13,12 +12,11 @@ use dockerfile_builder::instruction_builder::CopyBuilder; use futures_util::StreamExt; use log::{debug, info, log_enabled}; use serde::Serialize; -use tar::{Archive, Builder, Header}; +use tar::{Builder, Header}; use walkdir::WalkDir; use crate::config::{REGISTRY_PROJECT, REGISTRY_URL}; use crate::{score::Score, topology::Topology}; -use harmony_types::net::Url; use super::{Application, ApplicationFeature, ApplicationInterpret, HelmPackage, OCICompliant}; @@ -58,7 +56,6 @@ pub enum RustWebFramework { #[derive(Debug, Clone, Serialize)] pub struct RustWebapp { pub name: String, - pub domain: Url, /// The path to the root of the Rust project to be containerized. pub project_root: PathBuf, pub service_port: u32, @@ -73,12 +70,17 @@ impl Application for RustWebapp { #[async_trait] impl HelmPackage for RustWebapp { - async fn build_push_helm_package(&self, image_url: &str) -> Result { + async fn build_push_helm_package( + &self, + image_url: &str, + domain_host: &str, + ) -> Result { info!("Starting Helm chart build and push for '{}'", self.name); // 1. Create the Helm chart files on disk. let chart_dir = self - .create_helm_chart_files(image_url) + .create_helm_chart_files(image_url, domain_host) + .await .map_err(|e| format!("Failed to create Helm chart files: {}", e))?; info!("Successfully created Helm chart files in {:?}", chart_dir); @@ -408,10 +410,10 @@ impl RustWebapp { } /// Creates all necessary files for a basic Helm chart. - fn create_helm_chart_files( + async fn create_helm_chart_files( &self, image_url: &str, - topology: &T, + domain_host: &str, ) -> Result> { let chart_name = format!("{}-chart", self.name); let chart_dir = self @@ -423,9 +425,9 @@ impl RustWebapp { fs::create_dir_all(&templates_dir)?; let (image_repo, image_tag) = image_url.rsplit_once(':').unwrap_or((image_url, "latest")); - + //TODO need to find a way to use topology to get the domain - let domain = topology.get_domain(client.clone()).await?; + let domain = format!("{}.{domain_host}", self.name); // Create Chart.yaml let chart_yaml = format!( @@ -478,7 +480,7 @@ ingress: - {} "#, - chart_name, image_repo, image_tag, self.service_port, domain, self.name + chart_name, image_repo, image_tag, self.service_port, domain, self.name, domain ); fs::write(chart_dir.join("values.yaml"), values_yaml)?; diff --git a/harmony/src/modules/prometheus/rhob_alerting_score.rs b/harmony/src/modules/prometheus/rhob_alerting_score.rs index 71a3596..83e41dd 100644 --- a/harmony/src/modules/prometheus/rhob_alerting_score.rs +++ b/harmony/src/modules/prometheus/rhob_alerting_score.rs @@ -275,7 +275,7 @@ impl RHOBAlertingInterpret { .await .map_err(|e| InterpretError::new(e.to_string()))?; - let domain = topology.get_domain(client.clone()).await?; + let domain = topology.get_domain().await?; let name = format!("{}-alert-manager", self.sender.namespace.clone()); let backend_service = format!("{}-alert-manager", self.sender.namespace.clone()); let namespace = self.sender.namespace.clone(); @@ -510,7 +510,7 @@ impl RHOBAlertingInterpret { .apply(&grafana, Some(&self.sender.namespace.clone())) .await .map_err(|e| InterpretError::new(e.to_string()))?; - let domain = topology.get_domain(client.clone()).await?; + let domain = topology.get_domain().await?; let name = format!("{}-grafana", self.sender.namespace.clone()); let backend_service = format!("{}-grafana", self.sender.namespace.clone()); let grafana_ingress = K8sIngressScore {