forked from NationTech/harmony
		
	Merge pull request 'fix: bring back the TUI' (#110) from fix-tui into master
Reviewed-on: https://git.nationtech.io/NationTech/harmony/pulls/110
This commit is contained in:
		
						commit
						84f38974b1
					
				
							
								
								
									
										
											BIN
										
									
								
								examples/application_monitoring_with_tenant/harmony
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								examples/application_monitoring_with_tenant/harmony
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -8,7 +8,6 @@ use harmony::{ | |||||||
|     hardware::{FirewallGroup, HostCategory, Location, PhysicalHost, SwitchGroup}, |     hardware::{FirewallGroup, HostCategory, Location, PhysicalHost, SwitchGroup}, | ||||||
|     infra::opnsense::OPNSenseManagementInterface, |     infra::opnsense::OPNSenseManagementInterface, | ||||||
|     inventory::Inventory, |     inventory::Inventory, | ||||||
|     maestro::Maestro, |  | ||||||
|     modules::{ |     modules::{ | ||||||
|         http::StaticFilesHttpScore, |         http::StaticFilesHttpScore, | ||||||
|         ipxe::IpxeScore, |         ipxe::IpxeScore, | ||||||
| @ -130,16 +129,21 @@ async fn main() { | |||||||
|         "./data/watchguard/pxe-http-files".to_string(), |         "./data/watchguard/pxe-http-files".to_string(), | ||||||
|     )); |     )); | ||||||
|     let ipxe_score = IpxeScore::new(); |     let ipxe_score = IpxeScore::new(); | ||||||
|     let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); | 
 | ||||||
|     maestro.register_all(vec![ |     harmony_tui::run( | ||||||
|         Box::new(dns_score), |         inventory, | ||||||
|         Box::new(bootstrap_dhcp_score), |         topology, | ||||||
|         Box::new(bootstrap_load_balancer_score), |         vec![ | ||||||
|         Box::new(load_balancer_score), |             Box::new(dns_score), | ||||||
|         Box::new(tftp_score), |             Box::new(bootstrap_dhcp_score), | ||||||
|         Box::new(http_score), |             Box::new(bootstrap_load_balancer_score), | ||||||
|         Box::new(ipxe_score), |             Box::new(load_balancer_score), | ||||||
|         Box::new(dhcp_score), |             Box::new(tftp_score), | ||||||
|     ]); |             Box::new(http_score), | ||||||
|     harmony_tui::init(maestro).await.unwrap(); |             Box::new(ipxe_score), | ||||||
|  |             Box::new(dhcp_score), | ||||||
|  |         ], | ||||||
|  |     ) | ||||||
|  |     .await | ||||||
|  |     .unwrap(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,7 +8,6 @@ use harmony::{ | |||||||
|     hardware::{FirewallGroup, HostCategory, Location, PhysicalHost, SwitchGroup}, |     hardware::{FirewallGroup, HostCategory, Location, PhysicalHost, SwitchGroup}, | ||||||
|     infra::opnsense::OPNSenseManagementInterface, |     infra::opnsense::OPNSenseManagementInterface, | ||||||
|     inventory::Inventory, |     inventory::Inventory, | ||||||
|     maestro::Maestro, |  | ||||||
|     modules::{ |     modules::{ | ||||||
|         dummy::{ErrorScore, PanicScore, SuccessScore}, |         dummy::{ErrorScore, PanicScore, SuccessScore}, | ||||||
|         http::StaticFilesHttpScore, |         http::StaticFilesHttpScore, | ||||||
| @ -84,20 +83,25 @@ async fn main() { | |||||||
|     let http_score = StaticFilesHttpScore::new(Url::LocalFolder( |     let http_score = StaticFilesHttpScore::new(Url::LocalFolder( | ||||||
|         "./data/watchguard/pxe-http-files".to_string(), |         "./data/watchguard/pxe-http-files".to_string(), | ||||||
|     )); |     )); | ||||||
|     let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); | 
 | ||||||
|     maestro.register_all(vec![ |     harmony_tui::run( | ||||||
|         Box::new(dns_score), |         inventory, | ||||||
|         Box::new(dhcp_score), |         topology, | ||||||
|         Box::new(load_balancer_score), |         vec![ | ||||||
|         Box::new(tftp_score), |             Box::new(dns_score), | ||||||
|         Box::new(http_score), |             Box::new(dhcp_score), | ||||||
|         Box::new(OPNsenseShellCommandScore { |             Box::new(load_balancer_score), | ||||||
|             opnsense: opnsense.get_opnsense_config(), |             Box::new(tftp_score), | ||||||
|             command: "touch /tmp/helloharmonytouching".to_string(), |             Box::new(http_score), | ||||||
|         }), |             Box::new(OPNsenseShellCommandScore { | ||||||
|         Box::new(SuccessScore {}), |                 opnsense: opnsense.get_opnsense_config(), | ||||||
|         Box::new(ErrorScore {}), |                 command: "touch /tmp/helloharmonytouching".to_string(), | ||||||
|         Box::new(PanicScore {}), |             }), | ||||||
|     ]); |             Box::new(SuccessScore {}), | ||||||
|     harmony_tui::init(maestro).await.unwrap(); |             Box::new(ErrorScore {}), | ||||||
|  |             Box::new(PanicScore {}), | ||||||
|  |         ], | ||||||
|  |     ) | ||||||
|  |     .await | ||||||
|  |     .unwrap(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ use std::net::{SocketAddr, SocketAddrV4}; | |||||||
| 
 | 
 | ||||||
| use harmony::{ | use harmony::{ | ||||||
|     inventory::Inventory, |     inventory::Inventory, | ||||||
|     maestro::Maestro, |  | ||||||
|     modules::{ |     modules::{ | ||||||
|         dns::DnsScore, |         dns::DnsScore, | ||||||
|         dummy::{ErrorScore, PanicScore, SuccessScore}, |         dummy::{ErrorScore, PanicScore, SuccessScore}, | ||||||
| @ -16,18 +15,19 @@ use harmony_macros::ipv4; | |||||||
| 
 | 
 | ||||||
| #[tokio::main] | #[tokio::main] | ||||||
| async fn main() { | async fn main() { | ||||||
|     let inventory = Inventory::autoload(); |     harmony_tui::run( | ||||||
|     let topology = DummyInfra {}; |         Inventory::autoload(), | ||||||
|     let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); |         DummyInfra {}, | ||||||
| 
 |         vec![ | ||||||
|     maestro.register_all(vec![ |             Box::new(SuccessScore {}), | ||||||
|         Box::new(SuccessScore {}), |             Box::new(ErrorScore {}), | ||||||
|         Box::new(ErrorScore {}), |             Box::new(PanicScore {}), | ||||||
|         Box::new(PanicScore {}), |             Box::new(DnsScore::new(vec![], None)), | ||||||
|         Box::new(DnsScore::new(vec![], None)), |             Box::new(build_large_score()), | ||||||
|         Box::new(build_large_score()), |         ], | ||||||
|     ]); |     ) | ||||||
|     harmony_tui::init(maestro).await.unwrap(); |     .await | ||||||
|  |     .unwrap(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn build_large_score() -> LoadBalancerScore { | fn build_large_score() -> LoadBalancerScore { | ||||||
|  | |||||||
| @ -241,7 +241,7 @@ pub struct DummyInfra; | |||||||
| #[async_trait] | #[async_trait] | ||||||
| impl Topology for DummyInfra { | impl Topology for DummyInfra { | ||||||
|     fn name(&self) -> &str { |     fn name(&self) -> &str { | ||||||
|         todo!() |         "DummyInfra" | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async fn ensure_ready(&self) -> Result<PreparationOutcome, PreparationError> { |     async fn ensure_ready(&self) -> Result<PreparationOutcome, PreparationError> { | ||||||
|  | |||||||
| @ -90,13 +90,37 @@ pub async fn run<T: Topology + Send + Sync + 'static>( | |||||||
|     topology: T, |     topology: T, | ||||||
|     scores: Vec<Box<dyn Score<T>>>, |     scores: Vec<Box<dyn Score<T>>>, | ||||||
|     args_struct: Option<Args>, |     args_struct: Option<Args>, | ||||||
|  | ) -> Result<(), Box<dyn std::error::Error>> { | ||||||
|  |     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<T: Topology + Send + Sync + 'static>( | ||||||
|  |     inventory: Inventory, | ||||||
|  |     topology: T, | ||||||
|  |     scores: Vec<Box<dyn Score<T>>>, | ||||||
|  |     args: Args, | ||||||
| ) -> Result<(), Box<dyn std::error::Error>> { | ) -> Result<(), Box<dyn std::error::Error>> { | ||||||
|     let cli_logger_handle = cli_logger::init(); |     let cli_logger_handle = cli_logger::init(); | ||||||
| 
 | 
 | ||||||
|     let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); |     let mut maestro = Maestro::initialize(inventory, topology).await.unwrap(); | ||||||
|     maestro.register_all(scores); |     maestro.register_all(scores); | ||||||
| 
 | 
 | ||||||
|     let result = init(maestro, args_struct).await; |     let result = init(maestro, args).await; | ||||||
| 
 | 
 | ||||||
|     instrumentation::instrument(instrumentation::HarmonyEvent::HarmonyFinished).unwrap(); |     instrumentation::instrument(instrumentation::HarmonyEvent::HarmonyFinished).unwrap(); | ||||||
|     let _ = tokio::try_join!(cli_logger_handle); |     let _ = tokio::try_join!(cli_logger_handle); | ||||||
| @ -105,23 +129,8 @@ pub async fn run<T: Topology + Send + Sync + 'static>( | |||||||
| 
 | 
 | ||||||
| async fn init<T: Topology + Send + Sync + 'static>( | async fn init<T: Topology + Send + Sync + 'static>( | ||||||
|     maestro: harmony::maestro::Maestro<T>, |     maestro: harmony::maestro::Maestro<T>, | ||||||
|     args_struct: Option<Args>, |     args: Args, | ||||||
| ) -> Result<(), Box<dyn std::error::Error>> { | ) -> Result<(), Box<dyn std::error::Error>> { | ||||||
|     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 _ = env_logger::builder().try_init(); | ||||||
| 
 | 
 | ||||||
|     let scores_vec = maestro_scores_filter(&maestro, args.all, args.filter, args.number); |     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 maestro = init_test_maestro(); | ||||||
|         let res = crate::init( |         let res = crate::init( | ||||||
|             maestro, |             maestro, | ||||||
|             Some(crate::Args { |             crate::Args { | ||||||
|                 yes: true, |                 yes: true, | ||||||
|                 filter: Some("SuccessScore".to_owned()), |                 filter: Some("SuccessScore".to_owned()), | ||||||
|                 interactive: false, |                 interactive: false, | ||||||
|                 all: true, |                 all: true, | ||||||
|                 number: 0, |                 number: 0, | ||||||
|                 list: false, |                 list: false, | ||||||
|             }), |             }, | ||||||
|         ) |         ) | ||||||
|         .await; |         .await; | ||||||
| 
 | 
 | ||||||
| @ -213,14 +222,14 @@ mod tests { | |||||||
| 
 | 
 | ||||||
|         let res = crate::init( |         let res = crate::init( | ||||||
|             maestro, |             maestro, | ||||||
|             Some(crate::Args { |             crate::Args { | ||||||
|                 yes: true, |                 yes: true, | ||||||
|                 filter: Some("ErrorScore".to_owned()), |                 filter: Some("ErrorScore".to_owned()), | ||||||
|                 interactive: false, |                 interactive: false, | ||||||
|                 all: true, |                 all: true, | ||||||
|                 number: 0, |                 number: 0, | ||||||
|                 list: false, |                 list: false, | ||||||
|             }), |             }, | ||||||
|         ) |         ) | ||||||
|         .await; |         .await; | ||||||
| 
 | 
 | ||||||
| @ -233,14 +242,14 @@ mod tests { | |||||||
| 
 | 
 | ||||||
|         let res = crate::init( |         let res = crate::init( | ||||||
|             maestro, |             maestro, | ||||||
|             Some(crate::Args { |             crate::Args { | ||||||
|                 yes: true, |                 yes: true, | ||||||
|                 filter: None, |                 filter: None, | ||||||
|                 interactive: false, |                 interactive: false, | ||||||
|                 all: false, |                 all: false, | ||||||
|                 number: 0, |                 number: 0, | ||||||
|                 list: false, |                 list: false, | ||||||
|             }), |             }, | ||||||
|         ) |         ) | ||||||
|         .await; |         .await; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -9,7 +9,13 @@ use widget::{help::HelpWidget, score::ScoreListWidget}; | |||||||
| use std::{panic, sync::Arc, time::Duration}; | use std::{panic, sync::Arc, time::Duration}; | ||||||
| 
 | 
 | ||||||
| use crossterm::event::{Event, EventStream, KeyCode, KeyEventKind}; | 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::{ | use ratatui::{ | ||||||
|     self, Frame, |     self, Frame, | ||||||
|     layout::{Constraint, Layout, Position}, |     layout::{Constraint, Layout, Position}, | ||||||
| @ -39,22 +45,62 @@ pub mod tui { | |||||||
| ///
 | ///
 | ||||||
| /// #[tokio::main]
 | /// #[tokio::main]
 | ||||||
| /// async fn main() {
 | /// async fn main() {
 | ||||||
| ///     let inventory = Inventory::autoload();
 | ///     harmony_tui::run(
 | ||||||
| ///     let topology = HAClusterTopology::autoload();
 | ///         Inventory::autoload(),
 | ||||||
| ///     let mut maestro = Maestro::new_without_initialization(inventory, topology);
 | ///         HAClusterTopology::autoload(),
 | ||||||
| ///
 | ///         vec![
 | ||||||
| ///     maestro.register_all(vec![
 | ///             Box::new(SuccessScore {}),
 | ||||||
| ///         Box::new(SuccessScore {}),
 | ///             Box::new(ErrorScore {}),
 | ||||||
| ///         Box::new(ErrorScore {}),
 | ///             Box::new(PanicScore {}),
 | ||||||
| ///         Box::new(PanicScore {}),
 | ///         ]
 | ||||||
| ///     ]);
 | ///     ).await.unwrap();
 | ||||||
| ///     harmony_tui::init(maestro).await.unwrap();
 |  | ||||||
| /// }
 | /// }
 | ||||||
| /// ```
 | /// ```
 | ||||||
| pub async fn init<T: Topology + Send + Sync + 'static>( | pub async fn run<T: Topology + Send + Sync + 'static>( | ||||||
|  |     inventory: Inventory, | ||||||
|  |     topology: T, | ||||||
|  |     scores: Vec<Box<dyn Score<T>>>, | ||||||
|  | ) -> Result<(), Box<dyn std::error::Error>> { | ||||||
|  |     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<T: Topology + Send + Sync + 'static>( | ||||||
|     maestro: Maestro<T>, |     maestro: Maestro<T>, | ||||||
| ) -> Result<(), Box<dyn std::error::Error>> { | ) -> Result<(), Box<dyn std::error::Error>> { | ||||||
|     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<T: Topology> { | pub struct HarmonyTUI<T: Topology> { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user