feat(detmir): add rust-first operations tooling
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
fn main() -> anyhow::Result<()> {
|
||||
detmir_status::main_entry()
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fn main() -> anyhow::Result<()> {
|
||||
detmir_status::main_entry()
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use adk_rust::Content;
|
||||
use anyhow::Result;
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use detmir_state::{DEFAULT_STATE_FILE, NormalizedStatus, read_state};
|
||||
use serde_json::json;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(about = "Read-only DetMir status probe with JSON and ADK output.")]
|
||||
struct Cli {
|
||||
#[command(flatten)]
|
||||
status: StatusArgs,
|
||||
|
||||
#[command(subcommand)]
|
||||
command: Option<Command>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum Command {
|
||||
Status(StatusArgs),
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
struct StatusArgs {
|
||||
#[arg(long, default_value = DEFAULT_STATE_FILE)]
|
||||
state: PathBuf,
|
||||
|
||||
#[arg(long)]
|
||||
json: bool,
|
||||
|
||||
#[arg(long)]
|
||||
adk_json: bool,
|
||||
}
|
||||
|
||||
fn render_text(status: &NormalizedStatus) -> String {
|
||||
let s = &status.detmir_summary;
|
||||
let d = &status.dlp_counts;
|
||||
format!(
|
||||
"DetMir status: {severity}\n\
|
||||
check_ok={check_ok} dlp_ok={dlp_ok} needs_heal={needs_heal}\n\
|
||||
buckets: ok={bucket_ok} stale={bucket_stale} dead={bucket_dead}\n\
|
||||
services: fail={service_failures} warn={service_warnings}\n\
|
||||
dlp: ok={dlp_ok_count} warn={dlp_warn} fail={dlp_fail}\n\
|
||||
operator_ok={operator_ok}",
|
||||
severity = status.severity,
|
||||
check_ok = status.check_ok,
|
||||
dlp_ok = status.dlp_ok,
|
||||
needs_heal = status.needs_heal,
|
||||
bucket_ok = s.bucket_ok.unwrap_or(0),
|
||||
bucket_stale = s.bucket_stale.unwrap_or(0),
|
||||
bucket_dead = s.bucket_dead.unwrap_or(0),
|
||||
service_failures = s.service_failures.unwrap_or(0),
|
||||
service_warnings = s.service_warnings.unwrap_or(0),
|
||||
dlp_ok_count = d.ok.unwrap_or(0),
|
||||
dlp_warn = d.warn.unwrap_or(0),
|
||||
dlp_fail = d.fail.unwrap_or(0),
|
||||
operator_ok = status.ok_for_operator,
|
||||
)
|
||||
}
|
||||
|
||||
fn render_adk_content_json(status: &NormalizedStatus) -> Result<String> {
|
||||
let text = render_text(status);
|
||||
let content = Content::new("user").with_text(text);
|
||||
let envelope = json!({
|
||||
"agent": "detmir-status-agent",
|
||||
"mode": "read-only",
|
||||
"adk_content": content,
|
||||
"normalized": status,
|
||||
});
|
||||
Ok(serde_json::to_string_pretty(&envelope)?)
|
||||
}
|
||||
|
||||
fn run_status(args: StatusArgs) -> Result<i32> {
|
||||
let status = read_state(&args.state)?;
|
||||
if args.adk_json {
|
||||
println!("{}", render_adk_content_json(&status)?);
|
||||
} else if args.json {
|
||||
println!("{}", serde_json::to_string_pretty(&status)?);
|
||||
} else {
|
||||
println!("{}", render_text(&status));
|
||||
}
|
||||
Ok(status.exit_code())
|
||||
}
|
||||
|
||||
pub fn main_entry() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
let code = match cli.command {
|
||||
Some(Command::Status(args)) => run_status(args)?,
|
||||
None => run_status(cli.status)?,
|
||||
};
|
||||
std::process::exit(code);
|
||||
}
|
||||
Reference in New Issue
Block a user