nixfleet_agent/runtime/workers/probe_runners/
exec.rs

1//! Exec probe runner (RFC-0007 ยง3.1). Pass iff exit code 0 within
2//! `timeoutSecs` wallclock. Argv runs as the agent's user; declare
3//! absolute paths to avoid PATH surprises.
4
5use chrono::{DateTime, Utc};
6use std::time::Duration;
7use tokio::process::Command;
8use tokio::time::timeout;
9
10use super::{ProbeDecl, RunnerOutcome};
11
12pub async fn run(decl: &ProbeDecl, now: DateTime<Utc>) -> RunnerOutcome {
13    if decl.command.is_empty() {
14        return RunnerOutcome::fail(now, "exec probe: command argv missing");
15    }
16    let mut cmd = Command::new(&decl.command[0]);
17    cmd.args(&decl.command[1..]);
18    cmd.stdin(std::process::Stdio::null());
19    cmd.stdout(std::process::Stdio::null());
20    cmd.stderr(std::process::Stdio::piped());
21
22    let child = match cmd.spawn() {
23        Ok(c) => c,
24        Err(err) => return RunnerOutcome::fail(now, format!("exec probe: spawn: {err}")),
25    };
26    match timeout(
27        Duration::from_secs(decl.timeout_secs),
28        child.wait_with_output(),
29    )
30    .await
31    {
32        Ok(Ok(out)) => {
33            if out.status.success() {
34                RunnerOutcome::pass(now)
35            } else {
36                let stderr_tail = String::from_utf8_lossy(&out.stderr);
37                let stderr_tail = stderr_tail
38                    .lines()
39                    .rev()
40                    .take(3)
41                    .collect::<Vec<_>>()
42                    .join(" / ");
43                RunnerOutcome::fail(
44                    now,
45                    format!(
46                        "exec probe: exit {:?}; stderr: {stderr_tail}",
47                        out.status.code()
48                    ),
49                )
50            }
51        }
52        Ok(Err(err)) => RunnerOutcome::fail(now, format!("exec probe: wait: {err}")),
53        Err(_elapsed) => RunnerOutcome::fail(
54            now,
55            format!("exec probe: timed out after {}s", decl.timeout_secs),
56        ),
57    }
58}