diff --git a/examples/application_monitoring_with_tenant/harmony b/examples/application_monitoring_with_tenant/harmony new file mode 100755 index 0000000..d8d9885 Binary files /dev/null and b/examples/application_monitoring_with_tenant/harmony differ diff --git a/examples/nanodc/src/main.rs b/examples/nanodc/src/main.rs index 51b92d4..10754b4 100644 --- a/examples/nanodc/src/main.rs +++ b/examples/nanodc/src/main.rs @@ -8,7 +8,6 @@ use harmony::{ hardware::{FirewallGroup, HostCategory, Location, PhysicalHost, SwitchGroup}, infra::opnsense::OPNSenseManagementInterface, inventory::Inventory, - maestro::Maestro, modules::{ http::StaticFilesHttpScore, ipxe::IpxeScore, @@ -130,16 +129,21 @@ async fn main() { "./data/watchguard/pxe-http-files".to_string(), )); let ipxe_score = IpxeScore::new(); - let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); - maestro.register_all(vec![ - Box::new(dns_score), - Box::new(bootstrap_dhcp_score), - Box::new(bootstrap_load_balancer_score), - Box::new(load_balancer_score), - Box::new(tftp_score), - Box::new(http_score), - Box::new(ipxe_score), - Box::new(dhcp_score), - ]); - harmony_tui::init(maestro).await.unwrap(); + + harmony_tui::run( + inventory, + topology, + vec![ + Box::new(dns_score), + Box::new(bootstrap_dhcp_score), + Box::new(bootstrap_load_balancer_score), + Box::new(load_balancer_score), + Box::new(tftp_score), + Box::new(http_score), + Box::new(ipxe_score), + Box::new(dhcp_score), + ], + ) + .await + .unwrap(); } diff --git a/examples/opnsense/src/main.rs b/examples/opnsense/src/main.rs index c07c60e..61f8f18 100644 --- a/examples/opnsense/src/main.rs +++ b/examples/opnsense/src/main.rs @@ -8,7 +8,6 @@ use harmony::{ hardware::{FirewallGroup, HostCategory, Location, PhysicalHost, SwitchGroup}, infra::opnsense::OPNSenseManagementInterface, inventory::Inventory, - maestro::Maestro, modules::{ dummy::{ErrorScore, PanicScore, SuccessScore}, http::StaticFilesHttpScore, @@ -84,20 +83,25 @@ async fn main() { let http_score = StaticFilesHttpScore::new(Url::LocalFolder( "./data/watchguard/pxe-http-files".to_string(), )); - let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); - maestro.register_all(vec![ - Box::new(dns_score), - Box::new(dhcp_score), - Box::new(load_balancer_score), - Box::new(tftp_score), - Box::new(http_score), - Box::new(OPNsenseShellCommandScore { - opnsense: opnsense.get_opnsense_config(), - command: "touch /tmp/helloharmonytouching".to_string(), - }), - Box::new(SuccessScore {}), - Box::new(ErrorScore {}), - Box::new(PanicScore {}), - ]); - harmony_tui::init(maestro).await.unwrap(); + + harmony_tui::run( + inventory, + topology, + vec![ + Box::new(dns_score), + Box::new(dhcp_score), + Box::new(load_balancer_score), + Box::new(tftp_score), + Box::new(http_score), + Box::new(OPNsenseShellCommandScore { + opnsense: opnsense.get_opnsense_config(), + command: "touch /tmp/helloharmonytouching".to_string(), + }), + Box::new(SuccessScore {}), + Box::new(ErrorScore {}), + Box::new(PanicScore {}), + ], + ) + .await + .unwrap(); } diff --git a/examples/tui/src/main.rs b/examples/tui/src/main.rs index 39d5039..4b1aabe 100644 --- a/examples/tui/src/main.rs +++ b/examples/tui/src/main.rs @@ -2,7 +2,6 @@ use std::net::{SocketAddr, SocketAddrV4}; use harmony::{ inventory::Inventory, - maestro::Maestro, modules::{ dns::DnsScore, dummy::{ErrorScore, PanicScore, SuccessScore}, @@ -16,18 +15,19 @@ use harmony_macros::ipv4; #[tokio::main] async fn main() { - let inventory = Inventory::autoload(); - let topology = DummyInfra {}; - let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); - - maestro.register_all(vec![ - Box::new(SuccessScore {}), - Box::new(ErrorScore {}), - Box::new(PanicScore {}), - Box::new(DnsScore::new(vec![], None)), - Box::new(build_large_score()), - ]); - harmony_tui::init(maestro).await.unwrap(); + harmony_tui::run( + Inventory::autoload(), + DummyInfra {}, + vec![ + Box::new(SuccessScore {}), + Box::new(ErrorScore {}), + Box::new(PanicScore {}), + Box::new(DnsScore::new(vec![], None)), + Box::new(build_large_score()), + ], + ) + .await + .unwrap(); } fn build_large_score() -> LoadBalancerScore { diff --git a/harmony/src/domain/topology/ha_cluster.rs b/harmony/src/domain/topology/ha_cluster.rs index 02ee66e..737419f 100644 --- a/harmony/src/domain/topology/ha_cluster.rs +++ b/harmony/src/domain/topology/ha_cluster.rs @@ -241,7 +241,7 @@ pub struct DummyInfra; #[async_trait] impl Topology for DummyInfra { fn name(&self) -> &str { - todo!() + "DummyInfra" } async fn ensure_ready(&self) -> Result { diff --git a/harmony_cli/src/lib.rs b/harmony_cli/src/lib.rs index 711a709..53de86e 100644 --- a/harmony_cli/src/lib.rs +++ b/harmony_cli/src/lib.rs @@ -90,13 +90,37 @@ pub async fn run( topology: T, scores: Vec>>, args_struct: Option, +) -> Result<(), Box> { + let args = match args_struct { + Some(args) => args, + None => Args::parse(), + }; + + #[cfg(not(feature = "tui"))] + if args.interactive { + return Err("Not compiled with interactive support".into()); + } + + #[cfg(feature = "tui")] + if args.interactive { + return harmony_tui::run(inventory, topology, scores).await; + } + + run_cli(inventory, topology, scores, args).await +} + +pub async fn run_cli( + inventory: Inventory, + topology: T, + scores: Vec>>, + args: Args, ) -> Result<(), Box> { let cli_logger_handle = cli_logger::init(); let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); maestro.register_all(scores); - let result = init(maestro, args_struct).await; + let result = init(maestro, args).await; instrumentation::instrument(instrumentation::HarmonyEvent::HarmonyFinished).unwrap(); let _ = tokio::try_join!(cli_logger_handle); @@ -105,23 +129,8 @@ pub async fn run( async fn init( maestro: harmony::maestro::Maestro, - args_struct: Option, + args: Args, ) -> Result<(), Box> { - let args = match args_struct { - Some(args) => args, - None => Args::parse(), - }; - - #[cfg(feature = "tui")] - if args.interactive { - return harmony_tui::init(maestro).await; - } - - #[cfg(not(feature = "tui"))] - if args.interactive { - return Err("Not compiled with interactive support".into()); - } - let _ = env_logger::builder().try_init(); let scores_vec = maestro_scores_filter(&maestro, args.all, args.filter, args.number); @@ -193,14 +202,14 @@ mod tests { let maestro = init_test_maestro(); let res = crate::init( maestro, - Some(crate::Args { + crate::Args { yes: true, filter: Some("SuccessScore".to_owned()), interactive: false, all: true, number: 0, list: false, - }), + }, ) .await; @@ -213,14 +222,14 @@ mod tests { let res = crate::init( maestro, - Some(crate::Args { + crate::Args { yes: true, filter: Some("ErrorScore".to_owned()), interactive: false, all: true, number: 0, list: false, - }), + }, ) .await; @@ -233,14 +242,14 @@ mod tests { let res = crate::init( maestro, - Some(crate::Args { + crate::Args { yes: true, filter: None, interactive: false, all: false, number: 0, list: false, - }), + }, ) .await; diff --git a/harmony_tui/src/lib.rs b/harmony_tui/src/lib.rs index 4a807ff..4fb4591 100644 --- a/harmony_tui/src/lib.rs +++ b/harmony_tui/src/lib.rs @@ -9,7 +9,13 @@ use widget::{help::HelpWidget, score::ScoreListWidget}; use std::{panic, sync::Arc, time::Duration}; use crossterm::event::{Event, EventStream, KeyCode, KeyEventKind}; -use harmony::{maestro::Maestro, score::Score, topology::Topology}; +use harmony::{ + instrumentation::{self, HarmonyEvent}, + inventory::Inventory, + maestro::Maestro, + score::Score, + topology::Topology, +}; use ratatui::{ self, Frame, layout::{Constraint, Layout, Position}, @@ -39,22 +45,62 @@ pub mod tui { /// /// #[tokio::main] /// async fn main() { -/// let inventory = Inventory::autoload(); -/// let topology = HAClusterTopology::autoload(); -/// let mut maestro = Maestro::new_without_initialization(inventory, topology); -/// -/// maestro.register_all(vec![ -/// Box::new(SuccessScore {}), -/// Box::new(ErrorScore {}), -/// Box::new(PanicScore {}), -/// ]); -/// harmony_tui::init(maestro).await.unwrap(); +/// harmony_tui::run( +/// Inventory::autoload(), +/// HAClusterTopology::autoload(), +/// vec![ +/// Box::new(SuccessScore {}), +/// Box::new(ErrorScore {}), +/// Box::new(PanicScore {}), +/// ] +/// ).await.unwrap(); /// } /// ``` -pub async fn init( +pub async fn run( + inventory: Inventory, + topology: T, + scores: Vec>>, +) -> Result<(), Box> { + let handle = init_instrumentation().await; + + let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); + maestro.register_all(scores); + + let result = init(maestro).await; + + let _ = tokio::try_join!(handle); + result +} + +async fn init( maestro: Maestro, ) -> Result<(), Box> { - HarmonyTUI::new(maestro).init().await + let result = HarmonyTUI::new(maestro).init().await; + + instrumentation::instrument(HarmonyEvent::HarmonyFinished).unwrap(); + result +} + +async fn init_instrumentation() -> tokio::task::JoinHandle<()> { + let handle = tokio::spawn(handle_harmony_events()); + + loop { + if instrumentation::instrument(HarmonyEvent::HarmonyStarted).is_ok() { + break; + } + } + + handle +} + +async fn handle_harmony_events() { + instrumentation::subscribe("Harmony TUI Logger", async |event| { + if let HarmonyEvent::HarmonyFinished = event { + return false; + }; + true + }) + .await; } pub struct HarmonyTUI {