use topology domain to build & push helm package for continuous deliery
This commit is contained in:
parent
54803c40a2
commit
3bf5cb0526
@ -27,7 +27,6 @@ async fn main() {
|
|||||||
};
|
};
|
||||||
let application = Arc::new(RustWebapp {
|
let application = Arc::new(RustWebapp {
|
||||||
name: "example-monitoring".to_string(),
|
name: "example-monitoring".to_string(),
|
||||||
domain: Url::Url(url::Url::parse("https://rustapp.harmony.example.com").unwrap()),
|
|
||||||
project_root: PathBuf::from("./examples/rust/webapp"),
|
project_root: PathBuf::from("./examples/rust/webapp"),
|
||||||
framework: Some(RustWebFramework::Leptos),
|
framework: Some(RustWebFramework::Leptos),
|
||||||
service_port: 3000,
|
service_port: 3000,
|
||||||
|
@ -17,7 +17,6 @@ use harmony_types::net::Url;
|
|||||||
async fn main() {
|
async fn main() {
|
||||||
let application = Arc::new(RustWebapp {
|
let application = Arc::new(RustWebapp {
|
||||||
name: "test-rhob-monitoring".to_string(),
|
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
|
project_root: PathBuf::from("./webapp"), // Relative from 'harmony-path' param
|
||||||
framework: Some(RustWebFramework::Leptos),
|
framework: Some(RustWebFramework::Leptos),
|
||||||
service_port: 3000,
|
service_port: 3000,
|
||||||
|
@ -19,7 +19,6 @@ use harmony_macros::hurl;
|
|||||||
async fn main() {
|
async fn main() {
|
||||||
let application = Arc::new(RustWebapp {
|
let application = Arc::new(RustWebapp {
|
||||||
name: "harmony-example-rust-webapp".to_string(),
|
name: "harmony-example-rust-webapp".to_string(),
|
||||||
domain: hurl!("https://rustapp.harmony.example.com"),
|
|
||||||
project_root: PathBuf::from("./webapp"),
|
project_root: PathBuf::from("./webapp"),
|
||||||
framework: Some(RustWebFramework::Leptos),
|
framework: Some(RustWebFramework::Leptos),
|
||||||
service_port: 3000,
|
service_port: 3000,
|
||||||
|
@ -17,7 +17,6 @@ use harmony_types::net::Url;
|
|||||||
async fn main() {
|
async fn main() {
|
||||||
let application = Arc::new(RustWebapp {
|
let application = Arc::new(RustWebapp {
|
||||||
name: "harmony-example-tryrust".to_string(),
|
name: "harmony-example-tryrust".to_string(),
|
||||||
domain: Url::Url(url::Url::parse("https://tryrust.harmony.example.com").unwrap()),
|
|
||||||
project_root: PathBuf::from("./tryrust.org"),
|
project_root: PathBuf::from("./tryrust.org"),
|
||||||
framework: Some(RustWebFramework::Leptos),
|
framework: Some(RustWebFramework::Leptos),
|
||||||
service_port: 8080,
|
service_port: 8080,
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use crate::topology::{PreparationError, k8s::K8sClient};
|
use crate::topology::PreparationError;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Ingress {
|
pub trait Ingress {
|
||||||
async fn get_domain(&self, client: Arc<K8sClient>) -> Result<String, PreparationError>;
|
async fn get_domain(&self) -> Result<String, PreparationError>;
|
||||||
}
|
}
|
||||||
|
@ -576,7 +576,9 @@ impl TenantManager for K8sAnywhereTopology {
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Ingress for K8sAnywhereTopology {
|
impl Ingress for K8sAnywhereTopology {
|
||||||
//TODO this is specifically for openshift/okd which violates the k8sanywhere idea
|
//TODO this is specifically for openshift/okd which violates the k8sanywhere idea
|
||||||
async fn get_domain(&self, client: Arc<K8sClient>) -> Result<String, PreparationError> {
|
async fn get_domain(&self) -> Result<String, PreparationError> {
|
||||||
|
let client = self.k8s_client().await?;
|
||||||
|
|
||||||
if let Some(Some(k8s_state)) = self.k8s_state.get() {
|
if let Some(Some(k8s_state)) = self.k8s_state.get() {
|
||||||
match k8s_state.source {
|
match k8s_state.source {
|
||||||
K8sSource::LocalK3d => Ok("localhost".to_string()),
|
K8sSource::LocalK3d => Ok("localhost".to_string()),
|
||||||
|
@ -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 async_trait::async_trait;
|
||||||
use log::info;
|
use log::info;
|
||||||
@ -10,10 +10,13 @@ use crate::{
|
|||||||
data::Version,
|
data::Version,
|
||||||
inventory::Inventory,
|
inventory::Inventory,
|
||||||
modules::application::{
|
modules::application::{
|
||||||
features::{ArgoApplication, ArgoHelmScore}, ApplicationFeature, HelmPackage, OCICompliant
|
ApplicationFeature, HelmPackage, OCICompliant,
|
||||||
|
features::{ArgoApplication, ArgoHelmScore},
|
||||||
},
|
},
|
||||||
score::Score,
|
score::Score,
|
||||||
topology::{ingress::Ingress, DeploymentTarget, HelmCommand, K8sclient, MultiTargetTopology, Topology},
|
topology::{
|
||||||
|
DeploymentTarget, HelmCommand, K8sclient, MultiTargetTopology, Topology, ingress::Ingress,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// ContinuousDelivery in Harmony provides this functionality :
|
/// ContinuousDelivery in Harmony provides this functionality :
|
||||||
@ -140,13 +143,17 @@ impl<
|
|||||||
{
|
{
|
||||||
async fn ensure_installed(&self, topology: &T) -> Result<(), String> {
|
async fn ensure_installed(&self, topology: &T) -> Result<(), String> {
|
||||||
let image = self.application.image_name();
|
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
|
// TODO Write CI/CD workflow files
|
||||||
// we can autotedect the CI type using the remote url (default to github action for github
|
// we can autotedect the CI type using the remote url (default to github action for github
|
||||||
// url, etc..)
|
// url, etc..)
|
||||||
// Or ask for it when unknown
|
// 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)")
|
// TODO: Make building image configurable/skippable if image already exists (prompt)")
|
||||||
// https://git.nationtech.io/NationTech/harmony/issues/104
|
// https://git.nationtech.io/NationTech/harmony/issues/104
|
||||||
|
@ -55,7 +55,7 @@ impl<T: Topology + K8sclient + HelmCommand + Ingress> Interpret<T> for ArgoInter
|
|||||||
topology: &T,
|
topology: &T,
|
||||||
) -> Result<Outcome, InterpretError> {
|
) -> Result<Outcome, InterpretError> {
|
||||||
let k8s_client = topology.k8s_client().await?;
|
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 domain = format!("argo.{domain}");
|
||||||
let helm_score =
|
let helm_score =
|
||||||
argo_helm_chart_score(&self.score.namespace, self.score.openshift, &domain);
|
argo_helm_chart_score(&self.score.namespace, self.score.openshift, &domain);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use async_trait::async_trait;
|
|
||||||
|
|
||||||
use super::Application;
|
use super::Application;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait OCICompliant: Application {
|
pub trait OCICompliant: Application {
|
||||||
@ -17,5 +16,9 @@ pub trait HelmPackage: Application {
|
|||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `image_url` - The full URL of the OCI container image to be used in the Deployment.
|
/// * `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<String, String>;
|
async fn build_push_helm_package(
|
||||||
|
&self,
|
||||||
|
image_url: &str,
|
||||||
|
domain_host: &str,
|
||||||
|
) -> Result<String, String>;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use std::fs::{self, File};
|
use std::fs::{self};
|
||||||
use std::io::Read;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -13,12 +12,11 @@ use dockerfile_builder::instruction_builder::CopyBuilder;
|
|||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use log::{debug, info, log_enabled};
|
use log::{debug, info, log_enabled};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tar::{Archive, Builder, Header};
|
use tar::{Builder, Header};
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::config::{REGISTRY_PROJECT, REGISTRY_URL};
|
use crate::config::{REGISTRY_PROJECT, REGISTRY_URL};
|
||||||
use crate::{score::Score, topology::Topology};
|
use crate::{score::Score, topology::Topology};
|
||||||
use harmony_types::net::Url;
|
|
||||||
|
|
||||||
use super::{Application, ApplicationFeature, ApplicationInterpret, HelmPackage, OCICompliant};
|
use super::{Application, ApplicationFeature, ApplicationInterpret, HelmPackage, OCICompliant};
|
||||||
|
|
||||||
@ -58,7 +56,6 @@ pub enum RustWebFramework {
|
|||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct RustWebapp {
|
pub struct RustWebapp {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub domain: Url,
|
|
||||||
/// The path to the root of the Rust project to be containerized.
|
/// The path to the root of the Rust project to be containerized.
|
||||||
pub project_root: PathBuf,
|
pub project_root: PathBuf,
|
||||||
pub service_port: u32,
|
pub service_port: u32,
|
||||||
@ -73,12 +70,17 @@ impl Application for RustWebapp {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl HelmPackage for RustWebapp {
|
impl HelmPackage for RustWebapp {
|
||||||
async fn build_push_helm_package(&self, image_url: &str) -> Result<String, String> {
|
async fn build_push_helm_package(
|
||||||
|
&self,
|
||||||
|
image_url: &str,
|
||||||
|
domain_host: &str,
|
||||||
|
) -> Result<String, String> {
|
||||||
info!("Starting Helm chart build and push for '{}'", self.name);
|
info!("Starting Helm chart build and push for '{}'", self.name);
|
||||||
|
|
||||||
// 1. Create the Helm chart files on disk.
|
// 1. Create the Helm chart files on disk.
|
||||||
let chart_dir = self
|
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))?;
|
.map_err(|e| format!("Failed to create Helm chart files: {}", e))?;
|
||||||
info!("Successfully created Helm chart files in {:?}", chart_dir);
|
info!("Successfully created Helm chart files in {:?}", chart_dir);
|
||||||
|
|
||||||
@ -408,10 +410,10 @@ impl RustWebapp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates all necessary files for a basic Helm chart.
|
/// Creates all necessary files for a basic Helm chart.
|
||||||
fn create_helm_chart_files(
|
async fn create_helm_chart_files(
|
||||||
&self,
|
&self,
|
||||||
image_url: &str,
|
image_url: &str,
|
||||||
topology: &T,
|
domain_host: &str,
|
||||||
) -> Result<PathBuf, Box<dyn std::error::Error>> {
|
) -> Result<PathBuf, Box<dyn std::error::Error>> {
|
||||||
let chart_name = format!("{}-chart", self.name);
|
let chart_name = format!("{}-chart", self.name);
|
||||||
let chart_dir = self
|
let chart_dir = self
|
||||||
@ -425,7 +427,7 @@ impl RustWebapp {
|
|||||||
let (image_repo, image_tag) = image_url.rsplit_once(':').unwrap_or((image_url, "latest"));
|
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
|
//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
|
// Create Chart.yaml
|
||||||
let chart_yaml = format!(
|
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)?;
|
fs::write(chart_dir.join("values.yaml"), values_yaml)?;
|
||||||
|
|
||||||
|
@ -275,7 +275,7 @@ impl RHOBAlertingInterpret {
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| InterpretError::new(e.to_string()))?;
|
.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 name = format!("{}-alert-manager", self.sender.namespace.clone());
|
||||||
let backend_service = format!("{}-alert-manager", self.sender.namespace.clone());
|
let backend_service = format!("{}-alert-manager", self.sender.namespace.clone());
|
||||||
let namespace = self.sender.namespace.clone();
|
let namespace = self.sender.namespace.clone();
|
||||||
@ -510,7 +510,7 @@ impl RHOBAlertingInterpret {
|
|||||||
.apply(&grafana, Some(&self.sender.namespace.clone()))
|
.apply(&grafana, Some(&self.sender.namespace.clone()))
|
||||||
.await
|
.await
|
||||||
.map_err(|e| InterpretError::new(e.to_string()))?;
|
.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 name = format!("{}-grafana", self.sender.namespace.clone());
|
||||||
let backend_service = format!("{}-grafana", self.sender.namespace.clone());
|
let backend_service = format!("{}-grafana", self.sender.namespace.clone());
|
||||||
let grafana_ingress = K8sIngressScore {
|
let grafana_ingress = K8sIngressScore {
|
||||||
|
Loading…
Reference in New Issue
Block a user