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