feat: Application Interpret still WIP but now call ensure_installed on features, also introduced a rust app example, completed work on clone_box behavior
All checks were successful
Run Check Script / check (pull_request) Successful in -6s

This commit is contained in:
Jean-Gabriel Gill-Couture 2025-07-01 22:44:44 -04:00
parent ee02906ce9
commit 8ae0d6b548
10 changed files with 86 additions and 11 deletions

14
Cargo.lock generated
View File

@ -1194,6 +1194,20 @@ dependencies = [
"url", "url",
] ]
[[package]]
name = "example-rust"
version = "0.1.0"
dependencies = [
"env_logger",
"harmony",
"harmony_cli",
"harmony_macros",
"harmony_types",
"log",
"tokio",
"url",
]
[[package]] [[package]]
name = "example-tenant" name = "example-tenant"
version = "0.1.0" version = "0.1.0"

14
examples/rust/Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "example-rust"
version = "0.1.0"
edition = "2024"
[dependencies]
harmony = { path = "../../harmony" }
harmony_cli = { path = "../../harmony_cli" }
harmony_types = { path = "../../harmony_types" }
harmony_macros = { path = "../../harmony_macros" }
tokio = { workspace = true }
log = { workspace = true }
env_logger = { workspace = true }
url = { workspace = true }

20
examples/rust/src/main.rs Normal file
View File

@ -0,0 +1,20 @@
use harmony::{
inventory::Inventory,
maestro::Maestro,
modules::application::{RustWebappScore, features::ContinuousDelivery},
topology::{K8sAnywhereTopology, Url},
};
#[tokio::main]
async fn main() {
let app = RustWebappScore {
name: "Example Rust Webapp".to_string(),
domain: Url::Url(url::Url::parse("https://rustapp.harmony.example.com").unwrap()),
features: vec![Box::new(ContinuousDelivery {})],
};
let topology = K8sAnywhereTopology::from_env();
let mut maestro = Maestro::new(Inventory::autoload(), topology);
maestro.register_all(vec![Box::new(app)]);
harmony_cli::init(maestro, None).await.unwrap();
}

View File

@ -10,9 +10,9 @@ publish = false
harmony = { path = "../../harmony" } harmony = { path = "../../harmony" }
harmony_tui = { path = "../../harmony_tui" } harmony_tui = { path = "../../harmony_tui" }
harmony_types = { path = "../../harmony_types" } harmony_types = { path = "../../harmony_types" }
harmony_macros = { path = "../../harmony_macros" }
cidr = { workspace = true } cidr = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
harmony_macros = { path = "../../harmony_macros" }
log = { workspace = true } log = { workspace = true }
env_logger = { workspace = true } env_logger = { workspace = true }
url = { workspace = true } url = { workspace = true }

View File

@ -46,7 +46,7 @@ pub struct HAClusterTopology {
#[async_trait] #[async_trait]
impl Topology for HAClusterTopology { impl Topology for HAClusterTopology {
fn name(&self) -> &str { fn name(&self) -> &str {
todo!() "HAClusterTopology"
} }
async fn ensure_ready(&self) -> Result<Outcome, InterpretError> { async fn ensure_ready(&self) -> Result<Outcome, InterpretError> {
todo!( todo!(

View File

@ -30,7 +30,7 @@ use crate::{modules::application::ApplicationFeature, topology::Topology};
/// - Harbor as artifact registru /// - Harbor as artifact registru
/// - ArgoCD to install/upgrade/rollback/inspect k8s resources /// - ArgoCD to install/upgrade/rollback/inspect k8s resources
/// - Kubernetes for runtime orchestration /// - Kubernetes for runtime orchestration
#[derive(Debug, Default)] #[derive(Debug, Default, Clone)]
pub struct ContinuousDelivery {} pub struct ContinuousDelivery {}
#[async_trait] #[async_trait]

View File

@ -6,7 +6,7 @@ use crate::{
topology::{K8sclient, Topology}, topology::{K8sclient, Topology},
}; };
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct PublicEndpoint { pub struct PublicEndpoint {
application_port: u16, application_port: u16,
} }

View File

@ -6,7 +6,7 @@ use crate::{
topology::{HelmCommand, Topology}, topology::{HelmCommand, Topology},
}; };
#[derive(Debug, Default)] #[derive(Debug, Default, Clone)]
pub struct Monitoring {} pub struct Monitoring {}
#[async_trait] #[async_trait]

View File

@ -22,9 +22,19 @@ impl<T: Topology + std::fmt::Debug> Interpret<T> for ApplicationInterpret<T> {
async fn execute( async fn execute(
&self, &self,
_inventory: &Inventory, _inventory: &Inventory,
_topology: &T, topology: &T,
) -> Result<Outcome, InterpretError> { ) -> Result<Outcome, InterpretError> {
todo!() for feature in self.features.iter() {
let _ = match feature.ensure_installed(topology).await {
Ok(()) => (),
Err(msg) => {
return Err(InterpretError::new(format!(
"Application Interpret failed to install feature : {msg}"
)));
}
};
}
todo!("Do I need to do anything more than this here??")
} }
fn get_name(&self) -> InterpretName { fn get_name(&self) -> InterpretName {
@ -47,10 +57,25 @@ impl<T: Topology + std::fmt::Debug> Interpret<T> for ApplicationInterpret<T> {
/// An ApplicationFeature provided by harmony, such as Backups, Monitoring, MultisiteAvailability, /// An ApplicationFeature provided by harmony, such as Backups, Monitoring, MultisiteAvailability,
/// ContinuousIntegration, ContinuousDelivery /// ContinuousIntegration, ContinuousDelivery
#[async_trait] #[async_trait]
pub trait ApplicationFeature<T: Topology>: std::fmt::Debug + Send + Sync { pub trait ApplicationFeature<T: Topology>:
std::fmt::Debug + Send + Sync + ApplicationFeatureClone<T>
{
async fn ensure_installed(&self, topology: &T) -> Result<(), String>; async fn ensure_installed(&self, topology: &T) -> Result<(), String>;
} }
trait ApplicationFeatureClone<T: Topology> {
fn clone_box(&self) -> Box<dyn ApplicationFeature<T>>;
}
impl<A, T: Topology> ApplicationFeatureClone<T> for A
where
A: ApplicationFeature<T> + Clone + 'static,
{
fn clone_box(&self) -> Box<dyn ApplicationFeature<T>> {
Box::new(self.clone())
}
}
impl<T: Topology> Serialize for Box<dyn ApplicationFeature<T>> { impl<T: Topology> Serialize for Box<dyn ApplicationFeature<T>> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@ -62,6 +87,6 @@ impl<T: Topology> Serialize for Box<dyn ApplicationFeature<T>> {
impl<T: Topology> Clone for Box<dyn ApplicationFeature<T>> { impl<T: Topology> Clone for Box<dyn ApplicationFeature<T>> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
todo!() self.clone_box()
} }
} }

View File

@ -5,7 +5,7 @@ use crate::{
topology::{Topology, Url}, topology::{Topology, Url},
}; };
use super::{ApplicationFeature, ApplicationInterpret}; use super::{ApplicationFeature, ApplicationInterpret, features::ContinuousDelivery};
#[derive(Debug, Serialize, Clone)] #[derive(Debug, Serialize, Clone)]
pub struct RustWebappScore<T: Topology + Clone + Serialize> { pub struct RustWebappScore<T: Topology + Clone + Serialize> {
@ -16,7 +16,9 @@ pub struct RustWebappScore<T: Topology + Clone + Serialize> {
impl<T: Topology + std::fmt::Debug + Clone + Serialize + 'static> Score<T> for RustWebappScore<T> { impl<T: Topology + std::fmt::Debug + Clone + Serialize + 'static> Score<T> for RustWebappScore<T> {
fn create_interpret(&self) -> Box<dyn crate::interpret::Interpret<T>> { fn create_interpret(&self) -> Box<dyn crate::interpret::Interpret<T>> {
Box::new(ApplicationInterpret { features: todo!() }) Box::new(ApplicationInterpret {
features: self.features.clone(),
})
} }
fn name(&self) -> String { fn name(&self) -> String {