1use anyhow::{Context, Result};
4use tabled::{Table, Tabled};
5
6use crate::cli::StatusArgs;
7use crate::deploy::DeploymentState;
8
9#[derive(Tabled)]
10struct ServiceRow {
11 #[tabled(rename = "Service")]
12 name: String,
13 #[tabled(rename = "Status")]
14 status: String,
15 #[tabled(rename = "URL")]
16 url: String,
17 #[tabled(rename = "Service ID")]
18 service_id: String,
19}
20
21pub async fn run(args: StatusArgs) -> Result<()> {
22 let state = DeploymentState::load(&args.agent)
23 .with_context(|| format!("no deployment found for agent '{}'", args.agent))?;
24
25 let backend = crate::deploy::create_backend(&state.target)?;
27 let live_status = backend.status(&state.project_id).await;
28
29 match &args.format[..] {
30 "json" => {
31 match &live_status {
32 Ok(services) => {
33 let output = serde_json::json!({
34 "agent": state.agent_name,
35 "project_name": state.project_name,
36 "project_id": state.project_id,
37 "target": state.target,
38 "template": state.template_name,
39 "deployed_at": state.deployed_at.to_rfc3339(),
40 "services": services,
41 });
42 println!("{}", serde_json::to_string_pretty(&output)?);
43 }
44 Err(e) => {
45 let output = serde_json::json!({
47 "agent": state.agent_name,
48 "project_name": state.project_name,
49 "project_id": state.project_id,
50 "target": state.target,
51 "template": state.template_name,
52 "deployed_at": state.deployed_at.to_rfc3339(),
53 "services": state.services,
54 "warning": format!("live status unavailable: {e}"),
55 });
56 println!("{}", serde_json::to_string_pretty(&output)?);
57 }
58 }
59 }
60 _ => {
61 println!("Agent: {}", state.agent_name);
62 println!("Project: {} ({})", state.project_name, state.project_id);
63 println!("Target: {}", state.target);
64 println!("Template: {}", state.template_name);
65 println!(
66 "Deployed: {}",
67 state.deployed_at.format("%Y-%m-%d %H:%M:%S UTC")
68 );
69 println!();
70
71 match live_status {
72 Ok(services) => {
73 let rows: Vec<ServiceRow> = services
74 .iter()
75 .map(|(name, svc)| ServiceRow {
76 name: name.clone(),
77 status: svc.status.clone(),
78 url: svc.url.clone().unwrap_or_else(|| "(internal)".to_string()),
79 service_id: svc.service_id.clone(),
80 })
81 .collect();
82
83 println!("{}", Table::new(rows));
84 }
85 Err(e) => {
86 eprintln!("Warning: could not fetch live status: {e}");
87 eprintln!("Showing last known state:");
88 println!();
89
90 let rows: Vec<ServiceRow> = state
91 .services
92 .iter()
93 .map(|(name, svc)| ServiceRow {
94 name: name.clone(),
95 status: svc.status.clone(),
96 url: svc.url.clone().unwrap_or_else(|| "(internal)".to_string()),
97 service_id: svc.service_id.clone(),
98 })
99 .collect();
100
101 println!("{}", Table::new(rows));
102 }
103 }
104 }
105 }
106
107 Ok(())
108}