feat: Application Interpret still WIP but now call ensure_installed on features, also introduced a rust app example, completed work on clone_box behavior #72
							
								
								
									
										14
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -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
									
								
							
							
						
						
									
										14
									
								
								examples/rust/Cargo.toml
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										20
									
								
								examples/rust/src/main.rs
									
									
									
									
									
										Normal 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(); | ||||||
|  | } | ||||||
| @ -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 } | ||||||
|  | |||||||
| @ -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!( | ||||||
|  | |||||||
| @ -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] | ||||||
|  | |||||||
| @ -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, | ||||||
| } | } | ||||||
|  | |||||||
| @ -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] | ||||||
|  | |||||||
| @ -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() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -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 { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	
ApplicationFeature name is confusing. People think that it is a feature of the appplication itself, rather than one provided by Harmony as part of the software lifecycle / infrastructure management.