From 833e7eca228c244eab20f2e402aa40056b43d543 Mon Sep 17 00:00:00 2001 From: "Sijie.Sun" Date: Fri, 23 Aug 2024 11:50:11 +0800 Subject: [PATCH] add command to show local node info (#271) --- easytier/proto/cli.proto | 21 ++++++++++- easytier/src/easytier-cli.rs | 56 +++++++++++++++++++++++++++++- easytier/src/peers/peer_manager.rs | 29 +++++++++++++++- easytier/src/peers/rpc_service.rs | 11 +++++- 4 files changed, 113 insertions(+), 4 deletions(-) diff --git a/easytier/proto/cli.proto b/easytier/proto/cli.proto index 76a47a2..c98fe14 100644 --- a/easytier/proto/cli.proto +++ b/easytier/proto/cli.proto @@ -39,7 +39,10 @@ message PeerInfo { message ListPeerRequest {} -message ListPeerResponse { repeated PeerInfo peer_infos = 1; } +message ListPeerResponse { + repeated PeerInfo peer_infos = 1; + NodeInfo my_info = 2; +} enum NatType { // has NAT; but own a single public IP, port is not changed @@ -73,6 +76,21 @@ message Route { string inst_id = 8; } +message NodeInfo { + uint32 peer_id = 1; + string ipv4_addr = 2; + repeated string proxy_cidrs = 3; + string hostname = 4; + StunInfo stun_info = 5; + string inst_id = 6; + repeated string listeners = 7; + string config = 8; +} + +message ShowNodeInfoRequest {} + +message ShowNodeInfoResponse { NodeInfo node_info = 1; } + message ListRouteRequest {} message ListRouteResponse { repeated Route routes = 1; } @@ -95,6 +113,7 @@ service PeerManageRpc { rpc DumpRoute(DumpRouteRequest) returns (DumpRouteResponse); rpc ListForeignNetwork(ListForeignNetworkRequest) returns (ListForeignNetworkResponse); + rpc ShowNodeInfo(ShowNodeInfoRequest) returns (ShowNodeInfoResponse); } enum ConnectorStatus { diff --git a/easytier/src/easytier-cli.rs b/easytier/src/easytier-cli.rs index 08f49f2..a83c0f0 100644 --- a/easytier/src/easytier-cli.rs +++ b/easytier/src/easytier-cli.rs @@ -24,7 +24,7 @@ use crate::{ utils::{cost_to_str, float_to_str}, }; use humansize::format_size; -use tabled::settings::Style; +use tabled::{col, row, settings::Style}; #[derive(Parser, Debug)] #[command(name = "easytier-cli", author, version, about, long_about = None)] @@ -48,6 +48,7 @@ enum SubCommand { Route(RouteArgs), PeerCenter, VpnPortal, + Node(NodeArgs), } #[derive(Args, Debug)] @@ -101,12 +102,26 @@ enum ConnectorSubCommand { List, } +#[derive(Subcommand, Debug)] +enum NodeSubCommand { + Info, + Config, +} + +#[derive(Args, Debug)] +struct NodeArgs { + #[command(subcommand)] + sub_command: Option, +} + #[derive(thiserror::Error, Debug)] enum Error { #[error("tonic transport error")] TonicTransportError(#[from] tonic::transport::Error), #[error("tonic rpc error")] TonicRpcError(#[from] tonic::Status), + #[error("anyhow error")] + Anyhow(#[from] anyhow::Error), } struct CommandHandler { @@ -447,6 +462,45 @@ async fn main() -> Result<(), Error> { ); println!("connected_clients:\n{:#?}", resp.connected_clients); } + SubCommand::Node(sub_cmd) => { + let mut client = handler.get_peer_manager_client().await?; + let node_info = client + .show_node_info(ShowNodeInfoRequest::default()) + .await? + .into_inner() + .node_info + .ok_or(anyhow::anyhow!("node info not found"))?; + match sub_cmd.sub_command { + Some(NodeSubCommand::Info) | None => { + let stun_info = node_info.stun_info.clone().unwrap_or_default(); + + let mut builder = tabled::builder::Builder::default(); + builder.push_record(vec!["Virtual IP", node_info.ipv4_addr.as_str()]); + builder.push_record(vec!["Hostname", node_info.hostname.as_str()]); + builder.push_record(vec![ + "Proxy CIDRs", + node_info.proxy_cidrs.join(", ").as_str(), + ]); + builder.push_record(vec!["Peer ID", node_info.peer_id.to_string().as_str()]); + builder.push_record(vec!["Public IP", stun_info.public_ip.join(", ").as_str()]); + builder.push_record(vec![ + "UDP Stun Type", + format!("{:?}", stun_info.udp_nat_type()).as_str(), + ]); + for (idx, l) in node_info.listeners.iter().enumerate() { + if l.starts_with("ring") { + continue; + } + builder.push_record(vec![format!("Listener {}", idx).as_str(), l]); + } + + println!("{}", builder.build().with(Style::modern()).to_string()); + } + Some(NodeSubCommand::Config) => { + println!("{}", node_info.config); + } + } + } } Ok(()) diff --git a/easytier/src/peers/peer_manager.rs b/easytier/src/peers/peer_manager.rs index f10fba6..32d66be 100644 --- a/easytier/src/peers/peer_manager.rs +++ b/easytier/src/peers/peer_manager.rs @@ -20,7 +20,7 @@ use tokio_stream::wrappers::ReceiverStream; use tokio_util::bytes::Bytes; use crate::{ - common::{error::Error, global_ctx::ArcGlobalCtx, PeerId}, + common::{error::Error, global_ctx::ArcGlobalCtx, stun::StunInfoCollectorTrait, PeerId}, peers::{ peer_conn::PeerConn, peer_rpc::PeerRpcManagerTransport, @@ -746,6 +746,33 @@ impl PeerManager { pub fn get_foreign_network_client(&self) -> Arc { self.foreign_network_client.clone() } + + pub fn get_my_info(&self) -> crate::rpc::NodeInfo { + crate::rpc::NodeInfo { + peer_id: self.my_peer_id, + ipv4_addr: self + .global_ctx + .get_ipv4() + .map(|x| x.to_string()) + .unwrap_or_default(), + proxy_cidrs: self + .global_ctx + .get_proxy_cidrs() + .into_iter() + .map(|x| x.to_string()) + .collect(), + hostname: self.global_ctx.get_hostname(), + stun_info: Some(self.global_ctx.get_stun_info_collector().get_stun_info()), + inst_id: self.global_ctx.get_id().to_string(), + listeners: self + .global_ctx + .get_running_listeners() + .iter() + .map(|x| x.to_string()) + .collect(), + config: self.global_ctx.config.dump(), + } + } } #[cfg(test)] diff --git a/easytier/src/peers/rpc_service.rs b/easytier/src/peers/rpc_service.rs index 425e530..dacf5a7 100644 --- a/easytier/src/peers/rpc_service.rs +++ b/easytier/src/peers/rpc_service.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use crate::rpc::{ cli::PeerInfo, peer_manage_rpc_server::PeerManageRpc, DumpRouteRequest, DumpRouteResponse, ListForeignNetworkRequest, ListForeignNetworkResponse, ListPeerRequest, ListPeerResponse, - ListRouteRequest, ListRouteResponse, + ListRouteRequest, ListRouteResponse, ShowNodeInfoRequest, ShowNodeInfoResponse, }; use tonic::{Request, Response, Status}; @@ -81,4 +81,13 @@ impl PeerManageRpc for PeerManagerRpcService { .await; Ok(Response::new(reply)) } + + async fn show_node_info( + &self, + _request: Request, // Accept request of type HelloRequest + ) -> Result, Status> { + Ok(Response::new(ShowNodeInfoResponse { + node_info: Some(self.peer_manager.get_my_info()), + })) + } }