diff --git a/Cargo.lock b/Cargo.lock index 314f25a..70d4551 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -279,7 +279,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "cm-dashboard" -version = "0.1.261" +version = "0.1.262" dependencies = [ "anyhow", "chrono", @@ -301,7 +301,7 @@ dependencies = [ [[package]] name = "cm-dashboard-agent" -version = "0.1.261" +version = "0.1.262" dependencies = [ "anyhow", "async-trait", @@ -325,7 +325,7 @@ dependencies = [ [[package]] name = "cm-dashboard-shared" -version = "0.1.261" +version = "0.1.262" dependencies = [ "chrono", "serde", diff --git a/agent/Cargo.toml b/agent/Cargo.toml index 76d1d97..6dc9212 100644 --- a/agent/Cargo.toml +++ b/agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard-agent" -version = "0.1.262" +version = "0.1.263" edition = "2021" [dependencies] diff --git a/agent/src/collectors/systemd.rs b/agent/src/collectors/systemd.rs index 9a30322..4fc0db7 100644 --- a/agent/src/collectors/systemd.rs +++ b/agent/src/collectors/systemd.rs @@ -217,14 +217,15 @@ impl SystemdCollector { } if service_name == "tailscaled" && status_info.active_state == "active" { - // Add Tailscale connection method as sub-service - if let Some(conn_method) = self.get_tailscale_connection_method() { + // Add Tailscale peers with their connection methods as sub-services + let peers = self.get_tailscale_peers(); + for (peer_name, conn_method) in peers { let metrics = Vec::new(); sub_services.push(SubServiceData { - name: format!("Connection: {}", conn_method), + name: format!("{}: {}", peer_name, conn_method), service_status: Status::Info, metrics, - service_type: "tailscale_connection".to_string(), + service_type: "tailscale_peer".to_string(), }); } } @@ -936,50 +937,63 @@ impl SystemdCollector { None } - /// Get Tailscale connection method (direct, relay, or proxy) - fn get_tailscale_connection_method(&self) -> Option { + /// Get Tailscale connected peers with their connection methods + /// Returns a list of (device_name, connection_method) tuples + fn get_tailscale_peers(&self) -> Vec<(String, String)> { match Command::new("timeout") .args(["2", "tailscale", "status", "--json"]) .output() { Ok(output) if output.status.success() => { let json_str = String::from_utf8_lossy(&output.stdout); + let mut peers = Vec::new(); if let Ok(json_data) = serde_json::from_str::(&json_str) { // Look for the self peer (current node) in the peer list - if let Some(peers) = json_data["Peer"].as_object() { - // Find the first active peer connection to determine connection method - for (_peer_id, peer_data) in peers { - if peer_data["Active"].as_bool().unwrap_or(false) { + if let Some(peer_map) = json_data["Peer"].as_object() { + // Iterate through all peers + for (_peer_id, peer_data) in peer_map { + // Only include active/online peers + if !peer_data["Online"].as_bool().unwrap_or(false) { + continue; + } + + // Get peer hostname or DNS name + let peer_name = peer_data["HostName"] + .as_str() + .or_else(|| peer_data["DNSName"].as_str()) + .unwrap_or("unknown") + .trim_end_matches('.') + .to_string(); + + // Determine connection method + let connection_method = if peer_data["Active"].as_bool().unwrap_or(false) { // Check if using relay let relay_node = peer_data["Relay"].as_str().unwrap_or(""); if !relay_node.is_empty() { - return Some("relay".to_string()); - } - - // Check if using direct connection - if let Some(endpoints) = peer_data["CurAddr"].as_str() { - if !endpoints.is_empty() { - return Some("direct".to_string()); + "relay" + } else if let Some(cur_addr) = peer_data["CurAddr"].as_str() { + // Check if using direct connection + if !cur_addr.is_empty() { + "direct" + } else { + "unknown" } + } else { + "unknown" } - } - } - } + } else { + "idle" + }; - // Check if using proxy from backend state - if let Some(backend_state) = json_data["BackendState"].as_str() { - if backend_state == "Running" { - // If we're running but have no direct or relay, might be proxy - // This is a fallback heuristic - return Some("unknown".to_string()); + peers.push((peer_name, connection_method.to_string())); } } } - None + peers } - _ => None, + _ => Vec::new(), } } diff --git a/dashboard/Cargo.toml b/dashboard/Cargo.toml index f03b199..680d50c 100644 --- a/dashboard/Cargo.toml +++ b/dashboard/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard" -version = "0.1.262" +version = "0.1.263" edition = "2021" [dependencies] diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 1f9e531..484b134 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard-shared" -version = "0.1.262" +version = "0.1.263" edition = "2021" [dependencies]