1use std::iter;
2
3use crate::cluster;
4use crate::cluster::{discovery, local};
5
6pub async fn run() -> anyhow::Result<()> {
8 if !cluster::enabled() {
9 println!("orch runs on this machine only: the config has no cluster section");
10 return Ok(());
11 }
12
13 let Some(endpoint) = local::daemon_endpoint().await else {
14 anyhow::bail!("the orch service is not running");
15 };
16 let members = local::fetch_nodes(&endpoint).await?;
17 let tailnet = discovery::status().await.ok();
18 let name_of = |addr: &str| {
19 let ip = addr.split(':').next().unwrap_or_default();
20 tailnet
21 .as_ref()
22 .and_then(|t| {
23 iter::once(&t.me)
24 .chain(&t.peers)
25 .find(|h| h.ip == ip)
26 .map(|h| (h.name.clone(), h.online))
27 })
28 .unwrap_or_else(|| (ip.to_string(), true))
29 };
30 println!("{:<20} {:<22} {:<8} STATE", "NODE", "ADDRESS", "ROLE");
31 for m in members {
32 let (name, online) = name_of(&m.addr);
33 let role = if m.voter { "voter" } else { "learner" };
34 let mut state = Vec::new();
35 if m.leader {
36 state.push("leader");
37 }
38 if m.me {
39 state.push("this machine");
40 }
41 if !online {
42 state.push("offline");
43 }
44 println!("{name:<20} {:<22} {role:<8} {}", m.addr, state.join(", "));
45 }
46
47 Ok(())
48}