From 6b6128010686b06df1e1228077b80c9b39b6da6d Mon Sep 17 00:00:00 2001 From: Roland Sherwin Date: Thu, 14 Mar 2024 16:45:58 +0530 Subject: [PATCH] feat: add example to update log levels of all testnet nodes --- Cargo.lock | 1 + sn_node_manager/Cargo.toml | 9 ++- sn_node_manager/examples/update_log_levels.rs | 78 +++++++++++++++++++ 3 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 sn_node_manager/examples/update_log_levels.rs diff --git a/Cargo.lock b/Cargo.lock index c640087220..58fce9740d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4853,6 +4853,7 @@ dependencies = [ "color-eyre", "colored", "dirs-next", + "futures", "indicatif", "libp2p", "libp2p-identity", diff --git a/sn_node_manager/Cargo.toml b/sn_node_manager/Cargo.toml index 0447e0c87a..721241bbc7 100644 --- a/sn_node_manager/Cargo.toml +++ b/sn_node_manager/Cargo.toml @@ -66,12 +66,13 @@ assert_cmd = "2.0.12" assert_fs = "1.0.13" assert_matches = "1.5.0" async-trait = "0.1" -# Do not specify the version field. Release process expects even the local dev deps to be published. -# Removing the version field is a workaround. -test_utils = { path = "../test_utils" } +futures = "~0.3.13" mockall = "0.11.3" +predicates = "2.0" reqwest = { version = "0.11", default-features = false, features = [ "json", "rustls-tls", ] } -predicates = "2.0" +# Do not specify the version field. Release process expects even the local dev deps to be published. +# Removing the version field is a workaround. +test_utils = { path = "../test_utils" } diff --git a/sn_node_manager/examples/update_log_levels.rs b/sn_node_manager/examples/update_log_levels.rs new file mode 100644 index 0000000000..db3efa5a3f --- /dev/null +++ b/sn_node_manager/examples/update_log_levels.rs @@ -0,0 +1,78 @@ +// Copyright (C) 2024 MaidSafe.net limited. +// +// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3. +// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed +// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. Please review the Licences for the specific language governing +// permissions and limitations relating to use of the SAFE Network Software. + +use clap::Parser; +use color_eyre::{eyre::eyre, Result}; +use futures::StreamExt; +use sn_service_management::rpc::{RpcActions, RpcClient}; +use std::net::SocketAddr; +use test_utils::testnet::DeploymentInventory; + +#[derive(Parser, Debug)] +#[clap(name = "Update Log level")] +struct Opt { + /// Provide the path to the DeploymentInventory file or the name of the deployment. + /// If the name is provided, we search for the inventory file in the default location. + #[clap(long)] + inventory: String, + /// Change the log level of the safenode. + /// + /// Example: --log-level SN_LOG=all,RUST_LOG=libp2p=debug + #[clap(long)] + log_level: String, + /// The number of nodes to update concurrently. + #[clap(long, short = 'c', default_value_t = 10)] + concurrent_updates: usize, +} + +// Run using `cargo run --release --example update_log_levels -- --inventory --log-level safenode=trace,RUST_LOG=libp2p=debug` +#[tokio::main] +async fn main() -> Result<()> { + let opt = Opt::parse(); + let inventory = DeploymentInventory::load_from_str(&opt.inventory)?; + + let node_endpoints = inventory + .rpc_endpoints + .values() + .cloned() + .collect::>(); + let mut stream = futures::stream::iter(node_endpoints.iter()) + .map(|endpoint| update_log_level(*endpoint, opt.log_level.clone())) + .buffer_unordered(opt.concurrent_updates); + + let mut failed_list = vec![]; + let mut last_error = Ok(()); + let mut success_counter = 0; + while let Some((endpoint, result)) = stream.next().await { + match result { + Ok(_) => success_counter += 1, + Err(err) => { + failed_list.push(endpoint); + last_error = Err(err); + } + } + } + + println!("==== Update Log Levels Summary ===="); + println!("Successfully updated: {success_counter} nodes"); + if !failed_list.is_empty() { + println!("Failed to update: {} nodes", failed_list.len()); + println!("Last error: {last_error:?}") + } + + Ok(()) +} + +async fn update_log_level(endpoint: SocketAddr, log_levels: String) -> (SocketAddr, Result<()>) { + let client = RpcClient::from_socket_addr(endpoint); + let res = client + .update_log_level(log_levels) + .await + .map_err(|err| eyre!("{err:?}")); + (endpoint, res) +}