use crate::config::Config;
use anyhow::Result;
use clap::Args as ClapArgs;
use serde::Serialize;
#[derive(Debug, ClapArgs)]
pub struct Args {
#[arg(long)]
health: bool,
#[arg(long)]
jail: Option<String>,
#[arg(long)]
json: bool,
#[arg(short, long)]
quiet: bool,
}
#[derive(Debug, Serialize)]
struct JailStatus {
jail: String,
service: String,
jail_state: String,
service_state: String,
address: String,
health: String,
}
pub async fn run(args: Args) -> Result<()> {
let config = Config::load().unwrap_or_default();
config.init_logging();
tracing::info!("Checking jail status");
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(5))
.build()?;
let jails = vec![
("rmpca-extract", "extract", "10.10.0.2", Some(4000), Some("/")),
("rmpca-backend", "backend", "10.10.0.3", Some(3000), Some("/health")),
("rmpca-optimizer", "optimizer", "10.10.0.5", Some(8000), Some("/health")),
("rmpca-nginx-opt", "nginx", "10.10.0.7", Some(80), Some("/health")),
];
let mut results = Vec::new();
for (jail, service, ip, port, health_path) in jails {
if let Some(ref filter) = args.jail {
if jail != filter && service != filter {
continue;
}
}
let address = match port {
Some(p) => format!("{ip}:{p}"),
None => ip.to_string(),
};
let health_status = if args.health {
if let (Some(_p), Some(hp)) = (port, health_path) {
let url = format!("http://{address}{hp}");
match client.get(&url).send().await {
Ok(resp) if resp.status().is_success() => {
format!("ok ({})", resp.status())
}
Ok(resp) => format!("fail ({})", resp.status()),
Err(_) => "fail (connection error)".to_string(),
}
} else {
"–".to_string()
}
} else {
"–".to_string()
};
results.push(JailStatus {
jail: jail.to_string(),
service: service.to_string(),
jail_state: "up".to_string(), service_state: "running".to_string(), address,
health: health_status,
});
}
if args.json {
println!("{}", serde_json::to_string_pretty(&results)?);
} else if args.quiet {
for r in &results {
println!("{} {} {}", r.jail, r.jail_state, r.service_state);
}
} else {
println!("{:<24} {:<10} {:<10} {:<14} HEALTH",
"JAIL", "JAIL", "SERVICE", "IP:PORT");
println!("{}", "-".repeat(78));
for r in &results {
println!("{:<24} {:<10} {:<10} {:<14} {}",
r.jail, r.jail_state, r.service_state, r.address, r.health);
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_status_args() {
let args = Args {
health: true,
jail: Some("rmpca-backend".to_string()),
json: false,
quiet: true,
};
assert!(args.health);
assert_eq!(args.jail, Some("rmpca-backend".to_string()));
assert!(args.quiet);
}
}