Compare commits

..

No commits in common. "6e6f57e38c45f31ba516c417570bfd330a240a39" and "49370af176b4c809a489f7c494373b0718120194" have entirely different histories.

7 changed files with 81 additions and 120 deletions

View File

@ -36,59 +36,48 @@ These principles surface as simple, ergonomic Rust APIs that let teams focus on
## 2 · Quick Start ## 2 · Quick Start
The snippet below spins up a complete **production-grade Rust + Leptos Webapp** with monitoring. Swap it for your own scores to deploy anything from microservices to machine-learning pipelines. The snippet below spins up a complete **production-grade LAMP stack** with monitoring. Swap it for your own scores to deploy anything from microservices to machine-learning pipelines.
```rust ```rust
use harmony::{ use harmony::{
data::Version,
inventory::Inventory, inventory::Inventory,
maestro::Maestro,
modules::{ modules::{
application::{ lamp::{LAMPConfig, LAMPScore},
ApplicationScore, RustWebFramework, RustWebapp, monitoring::monitoring_alerting::MonitoringAlertingStackScore,
features::{PackagingDeployment, rhob_monitoring::Monitoring},
}, },
monitoring::alert_channel::discord_alert_channel::DiscordWebhook, topology::{K8sAnywhereTopology, Url},
},
topology::K8sAnywhereTopology,
}; };
use harmony_macros::hurl;
use std::{path::PathBuf, sync::Arc};
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
let application = Arc::new(RustWebapp { // 1. Describe what you want
name: "harmony-example-leptos".to_string(), let lamp_stack = LAMPScore {
project_root: PathBuf::from(".."), // <== Your project root, usually .. if you use the standard `/harmony` folder name: "harmony-lamp-demo".into(),
framework: Some(RustWebFramework::Leptos), domain: Url::Url(url::Url::parse("https://lampdemo.example.com").unwrap()),
service_port: 8080, php_version: Version::from("8.3.0").unwrap(),
}); config: LAMPConfig {
project_root: "./php".into(),
// Define your Application deployment and the features you want database_size: "4Gi".into(),
let app = ApplicationScore { ..Default::default()
features: vec![ },
Box::new(PackagingDeployment {
application: application.clone(),
}),
Box::new(Monitoring {
application: application.clone(),
alert_receiver: vec![
Box::new(DiscordWebhook {
name: "test-discord".to_string(),
url: hurl!("https://discord.doesnt.exist.com"), // <== Get your discord webhook url
}),
],
}),
],
application,
}; };
// 2. Enhance with extra scores (monitoring, CI/CD, …)
let mut monitoring = MonitoringAlertingStackScore::new();
monitoring.namespace = Some(lamp_stack.config.namespace.clone());
// 3. Run your scores on the desired topology & inventory
harmony_cli::run( harmony_cli::run(
Inventory::autoload(), Inventory::autoload(), // auto-detect hardware / kube-config
K8sAnywhereTopology::from_env(), // <== Deploy to local automatically provisioned local k3d by default or connect to any kubernetes cluster K8sAnywhereTopology::from_env(), // local k3d, CI, staging, prod…
vec![Box::new(app)], vec![
None, Box::new(lamp_stack),
) Box::new(monitoring)
.await ],
.unwrap(); None
).await.unwrap();
} }
``` ```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

File diff suppressed because one or more lines are too long

View File

@ -225,17 +225,3 @@ Demo time
--- ---
<img src="./Happy_swimmer.jpg" width="300"/> <img src="./Happy_swimmer.jpg" width="300"/>
---
# 🎼
Harmony : [https://git.nationtech.io/nationtech/harmony](https://git.nationtech.io/nationtech/harmony)
<img src="./qrcode_gitea_nationtech.png" width="120"/>
LinkedIn : [https://www.linkedin.com/in/jean-gabriel-gill-couture/](https://www.linkedin.com/in/jean-gabriel-gill-couture/)
Courriel : [jg@nationtech.io](mailto:jg@nationtech.io)

View File

@ -16,13 +16,16 @@ use std::{path::PathBuf, sync::Arc};
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(),
project_root: PathBuf::from("./tryrust.org"), // <== Project root, in this case it is a project_root: PathBuf::from("./tryrust.org"),
// submodule
framework: Some(RustWebFramework::Leptos), framework: Some(RustWebFramework::Leptos),
service_port: 8080, service_port: 8080,
}); });
// Define your Application deployment and the features you want let discord_receiver = DiscordWebhook {
name: "test-discord".to_string(),
url: hurl!("https://discord.doesnt.exist.com"),
};
let app = ApplicationScore { let app = ApplicationScore {
features: vec![ features: vec![
Box::new(PackagingDeployment { Box::new(PackagingDeployment {
@ -30,10 +33,7 @@ async fn main() {
}), }),
Box::new(Monitoring { Box::new(Monitoring {
application: application.clone(), application: application.clone(),
alert_receiver: vec![Box::new(DiscordWebhook { alert_receiver: vec![Box::new(discord_receiver)],
name: "test-discord".to_string(),
url: hurl!("https://discord.doesnt.exist.com"),
})],
}), }),
], ],
application, application,
@ -41,7 +41,7 @@ async fn main() {
harmony_cli::run( harmony_cli::run(
Inventory::autoload(), Inventory::autoload(),
K8sAnywhereTopology::from_env(), // <== Deploy to local automatically provisioned k3d by default or connect to any kubernetes cluster K8sAnywhereTopology::from_env(),
vec![Box::new(app)], vec![Box::new(app)],
None, None,
) )

View File

@ -55,8 +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 svc = format!("argo-{}", self.score.namespace.clone()); let domain = topology.get_domain("argo").await?;
let domain = topology.get_domain(&svc).await?;
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);
@ -67,17 +66,14 @@ impl<T: Topology + K8sclient + HelmCommand + Ingress> Interpret<T> for ArgoInter
.await .await
.unwrap(); .unwrap();
Ok(Outcome::success_with_details( Ok(Outcome::success(format!(
format!( "ArgoCD installed with {} {}",
"ArgoCD {} {}",
self.argo_apps.len(), self.argo_apps.len(),
match self.argo_apps.len() { match self.argo_apps.len() {
1 => "application", 1 => "application",
_ => "applications", _ => "applications",
} }
), )))
vec![format!("argo application: http://{}", domain)],
))
} }
fn get_name(&self) -> InterpretName { fn get_name(&self) -> InterpretName {

View File

@ -141,10 +141,7 @@ impl<T: Topology + K8sclient> Interpret<T> for K8sIngressInterpret {
InterpretStatus::SUCCESS => { InterpretStatus::SUCCESS => {
let details = match &self.namespace { let details = match &self.namespace {
Some(namespace) => { Some(namespace) => {
vec![format!( vec![format!("{} ({namespace}): {}", self.service, self.host)]
"{} ({namespace}): http://{}",
self.service, self.host
)]
} }
None => vec![format!("{}: {}", self.service, self.host)], None => vec![format!("{}: {}", self.service, self.host)],
}; };