From 4154c3240a1aad5dce0dd0ab25c092456d5a82b5 Mon Sep 17 00:00:00 2001 From: Hansie Odendaal <39146854+hansieodendaal@users.noreply.github.com> Date: Thu, 12 Dec 2024 08:32:06 +0200 Subject: [PATCH] feat: update peer liveness (#6723) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Description --- - Updated peer liveness to print test results to the console, one item per row. - Added a command-line arg option to disable the splash screen; this is useful for screen scraping in an automated test environment. Motivation and Context --- These changes will simplify automated monitoring. How Has This Been Tested? --- System-level testing ``` .\minotari_node.exe --non-interactive-mode --watch "test-peer-liveness 8a24a7fb8ff2f1183c02ac52d488a13cc1104f970cc9a6fb3dd5f17ea1d85212 /ip4/3.248.103.200/tcp/18189 true true false" -p esmeralda.p2p.seeds.dns_seeds="" -p esmeralda.p2p.seeds.peer_seeds="" --network esmeralda --disable-splash-screen Initializing logging according to "C:\\Users\\hansie\\.tari\\esmeralda\\config\\base_node\\log4rs.yml" Node started in non-interactive mode (pid = 17156) Testing peer liveness... ๐Ÿ“ Peer (b7ed45c971da86409939de9397, 8a24a7fb8ff2f1183c02ac52d488a13cc1104f970cc9a6fb3dd5f17ea1d85212) dialed successfully โ˜Ž๏ธ Dialing peer... ๐Ÿ“ Pinging peer (b7ed45c971da86409939de9397, 8a24a7fb8ff2f1183c02ac52d488a13cc1104f970cc9a6fb3dd5f17ea1d85212) with nonce 3324112300086574482 ... โšก๏ธ Peer connected in 1537ms! Connection: Id: 0, Node ID: b7ed45c971da8640, Direction: Outbound, Peer Address: /ip4/3.248.103.200/tcp/18189, Age: 276ยตs, #Substreams: 2, #Refs: 5 ๐Ÿ“๏ธ Pong: peer (b7ed45c971da86409939de9397, 8a24a7fb8ff2f1183c02ac52d488a13cc1104f970cc9a6fb3dd5f17ea1d85212) responded with nonce 3324112300086574482, round-trip-time is 2.19s! โœ… Peer is responsive Date Time: 2024-12-11 18:20:40 Public Key: 8a24a7fb8ff2f1183c02ac52d488a13cc1104f970cc9a6fb3dd5f17ea1d85212 Node ID: b7ed45c971da86409939de9397 Address: /ip4/3.248.103.200/tcp/18189 Result: Success Test Duration: 2.19s ๐Ÿ“ Test result written to file: peer_liveness_test.csv The liveness test is complete and base node will now exit ``` What process can a PR reviewer use to test or verify this change? --- Code review System-level testing Breaking Changes --- - [x] None - [ ] Requires data directory on base node to be deleted - [ ] Requires hard fork - [ ] Other - Please specify --- applications/minotari_node/src/cli.rs | 7 ++ .../minotari_node/src/commands/cli_loop.rs | 6 +- .../commands/command/test_peer_liveness.rs | 113 +++++++++++------- applications/minotari_node/src/lib.rs | 3 +- 4 files changed, 83 insertions(+), 46 deletions(-) diff --git a/applications/minotari_node/src/cli.rs b/applications/minotari_node/src/cli.rs index 3105dd4574..091f621f86 100644 --- a/applications/minotari_node/src/cli.rs +++ b/applications/minotari_node/src/cli.rs @@ -43,14 +43,21 @@ pub struct Cli { /// Watch a command in the non-interactive mode. #[clap(long)] pub watch: Option, + /// Run in test profile mode #[clap(long, alias = "profile")] pub profile_with_tokio_console: bool, + /// Enable gRPC #[clap(long, env = "MINOTARI_NODE_ENABLE_GRPC", alias = "enable-grpc")] pub grpc_enabled: bool, + /// Enable mining #[clap(long, env = "MINOTARI_NODE_ENABLE_MINING", alias = "enable-mining")] pub mining_enabled: bool, + /// Enable the second layer gRPC server #[clap(long, env = "MINOTARI_NODE_SECOND_LAYER_GRPC_ENABLED", alias = "enable-second-layer")] pub second_layer_grpc_enabled: bool, + /// Disable the splash screen + #[clap(long)] + pub disable_splash_screen: bool, } impl ConfigOverrideProvider for Cli { diff --git a/applications/minotari_node/src/commands/cli_loop.rs b/applications/minotari_node/src/commands/cli_loop.rs index be4a34c7e2..28a6f5bf69 100644 --- a/applications/minotari_node/src/commands/cli_loop.rs +++ b/applications/minotari_node/src/commands/cli_loop.rs @@ -79,8 +79,10 @@ impl CliLoop { /// /// ## Returns /// Doesn't return anything - pub async fn cli_loop(mut self) { - cli::print_banner(self.commands.clone(), 3); + pub async fn cli_loop(mut self, disable_splash_screen: bool) { + if !disable_splash_screen { + cli::print_banner(self.commands.clone(), 3); + } if self.non_interactive { self.watch_loop_non_interactive().await; diff --git a/applications/minotari_node/src/commands/command/test_peer_liveness.rs b/applications/minotari_node/src/commands/command/test_peer_liveness.rs index d3bdf7f622..08b9a8a03c 100644 --- a/applications/minotari_node/src/commands/command/test_peer_liveness.rs +++ b/applications/minotari_node/src/commands/command/test_peer_liveness.rs @@ -40,7 +40,7 @@ use tari_comms::{ net_address::{MultiaddressesWithStats, PeerAddressSource}, peer_manager::{NodeId, Peer, PeerFeatures, PeerFlags}, }; -use tari_p2p::services::liveness::LivenessEvent; +use tari_p2p::services::liveness::{LivenessEvent, LivenessHandle}; use tokio::{sync::watch, task}; use super::{CommandContext, HandleCommand}; @@ -107,41 +107,14 @@ impl HandleCommand for CommandContext { for _ in 0..5 { if self.dial_peer(node_id.clone()).await.is_ok() { println!("๐Ÿ“ Peer ({}, {}) dialed successfully", node_id, public_key); - let mut liveness_events = self.liveness.get_event_stream(); - let mut liveness = self.liveness.clone(); + let liveness = self.liveness.clone(); task::spawn(async move { - if let Ok(nonce) = liveness.send_ping(node_id.clone()).await { - println!("๐Ÿ“ Pinging peer ({}, {}) with nonce {} ...", node_id, public_key, nonce); - for _ in 0..5 { - match liveness_events.recv().await { - Ok(event) => { - if let LivenessEvent::ReceivedPong(pong) = &*event { - if pong.node_id == node_id && pong.nonce == nonce { - println!( - "๐Ÿ“๏ธ Pong: peer ({}, {}) responded with nonce {}, round-trip-time is \ - {:.2?}!", - pong.node_id, - public_key, - pong.nonce, - pong.latency.unwrap_or_default() - ); - let _ = tx.send(PingResult::Success); - return; - } - } - }, - Err(e) => { - println!("๐Ÿ“ Ping peer ({}, {}) gave error: {}", node_id, public_key, e); - }, - } - } - let _ = tx.send(PingResult::Fail); - } + ping_peer_liveness(liveness, node_id, public_key, tx).await; }); // Break if the dial was successful break; } else { - tokio::time::sleep(std::time::Duration::from_secs(5)).await; + tokio::time::sleep(Duration::from_secs(5)).await; } } @@ -151,15 +124,13 @@ impl HandleCommand for CommandContext { _ = rx.changed() => { let test_duration = start.elapsed(); let responsive = *rx.borrow(); - println!("\nWhen rx.changed(): {:?}\n", responsive); - if responsive == PingResult::Success { - println!("โœ… Peer ({}, {}) is responsive", node_id_clone, public_key_clone); - } else { - println!("โŒ Peer ({}, {}) is unresponsive", node_id_clone, public_key_clone); - } + let date_time = Local::now().format("%Y-%m-%d %H:%M:%S").to_string(); + + print_results_to_console(&date_time, responsive, &public_key_clone, &node_id_clone, &address_clone, test_duration); if let Some(true) = args.output_to_file { print_to_file( + &date_time, responsive, args.output_directory, args.refresh_file, @@ -168,12 +139,11 @@ impl HandleCommand for CommandContext { test_duration ).await; } - println!(); if let Some(true) = args.exit { println!("The liveness test is complete and base node will now exit\n"); self.shutdown.trigger(); - tokio::time::sleep(std::time::Duration::from_secs(1)).await; + tokio::time::sleep(Duration::from_secs(1)).await; match responsive { PingResult::Success => process::exit(0), _ => process::exit(1), @@ -183,7 +153,7 @@ impl HandleCommand for CommandContext { break; }, - _ = tokio::time::sleep(std::time::Duration::from_secs(1)) => {}, + _ = tokio::time::sleep(Duration::from_secs(1)) => {}, } } @@ -191,7 +161,66 @@ impl HandleCommand for CommandContext { } } +fn print_results_to_console( + date_time: &str, + responsive: PingResult, + public_key: &PublicKey, + node_id: &NodeId, + address: &Multiaddr, + test_duration: Duration, +) { + println!(); + if responsive == PingResult::Success { + println!("โœ… Peer is responsive"); + } else { + println!("โŒ Peer is unresponsive"); + } + println!(" Date Time: {}", date_time); + println!(" Public Key: {}", public_key); + println!(" Node ID: {}", node_id); + println!(" Address: {}", address); + println!(" Result: {:?}", responsive); + println!(" Test Duration: {:.2?}", test_duration); + println!(); +} + +async fn ping_peer_liveness( + mut liveness: LivenessHandle, + node_id: NodeId, + public_key: PublicKey, + tx: watch::Sender, +) { + let mut liveness_events = liveness.get_event_stream(); + if let Ok(nonce) = liveness.send_ping(node_id.clone()).await { + println!("๐Ÿ“ Pinging peer ({}, {}) with nonce {} ...", node_id, public_key, nonce); + for _ in 0..5 { + match liveness_events.recv().await { + Ok(event) => { + if let LivenessEvent::ReceivedPong(pong) = &*event { + if pong.node_id == node_id && pong.nonce == nonce { + println!( + "๐Ÿ“๏ธ Pong: peer ({}, {}) responded with nonce {}, round-trip-time is {:.2?}!", + pong.node_id, + public_key, + pong.nonce, + pong.latency.unwrap_or_default() + ); + let _ = tx.send(PingResult::Success); + return; + } + } + }, + Err(e) => { + println!("๐Ÿ“ Ping peer ({}, {}) gave error: {}", node_id, public_key, e); + }, + } + } + let _ = tx.send(PingResult::Fail); + } +} + async fn print_to_file( + date_time: &str, responsive: PingResult, output_directory: Option, refresh_file: Option, @@ -204,8 +233,6 @@ async fn print_to_file( } else { "FAIL" }; - let now = Local::now(); - let date_time = now.format("%Y-%m-%d %H:%M:%S").to_string(); let file_name = "peer_liveness_test.csv"; let file_path = if let Some(path) = output_directory.clone() { @@ -222,7 +249,7 @@ async fn print_to_file( if let Some(true) = refresh_file { let _unused = fs::remove_file(&file_path); - tokio::time::sleep(std::time::Duration::from_secs(1)).await; + tokio::time::sleep(Duration::from_secs(1)).await; } let write_header = !file_path.exists(); if let Ok(mut file) = OpenOptions::new().append(true).create(true).open(file_path.clone()) { diff --git a/applications/minotari_node/src/lib.rs b/applications/minotari_node/src/lib.rs index 2c40ac2101..f0f0867141 100644 --- a/applications/minotari_node/src/lib.rs +++ b/applications/minotari_node/src/lib.rs @@ -91,6 +91,7 @@ pub async fn run_base_node( grpc_enabled: false, mining_enabled: false, second_layer_grpc_enabled: false, + disable_splash_screen: false, }; run_base_node_with_cli(node_identity, config, cli, shutdown).await @@ -170,7 +171,7 @@ pub async fn run_base_node_with_cli( } info!(target: LOG_TARGET, "Minotari base node has STARTED"); - main_loop.cli_loop().await; + main_loop.cli_loop(cli.disable_splash_screen).await; ctx.wait_for_shutdown().await;