Skip to main content

max / makenotwork

2.1 KB · 62 lines History Blame Raw
1 //! `ops-agent` — the on-host executor.
2 //!
3 //! Reads its config (its own grant + the caller identities it trusts), binds
4 //! the configured tailnet socket, and serves `/run` `/health` `/pull`. On
5 //! macOS it is installed as an Aqua LaunchAgent so build+sign run in the GUI
6 //! security session (see `_private/docs/ops-core/executor.md`). No root needed:
7 //! `launchctl bootstrap gui/$(id -u) <plist>`.
8 //!
9 //! Usage: `ops-agent --config /path/to/config.toml`
10
11 use anyhow::{Context, Result};
12 use ops_exec::agent::{AgentConfig, AgentState, router};
13 use std::net::SocketAddr;
14
15 #[tokio::main]
16 async fn main() -> Result<()> {
17 tracing_subscriber::fmt().with_env_filter(env_filter()).init();
18
19 let config_path = parse_config_arg().context(
20 "usage: ops-agent --config <config.toml>",
21 )?;
22 let raw = std::fs::read_to_string(&config_path)
23 .with_context(|| format!("reading config {config_path}"))?;
24 let config: AgentConfig = toml::from_str(&raw).context("parsing config toml")?;
25 let listen = config.listen;
26
27 tracing::info!(%listen, allow = config.allow.len(), "ops-agent starting");
28 let state = AgentState::new(config);
29 let app = router(state);
30
31 let listener = tokio::net::TcpListener::bind(listen)
32 .await
33 .with_context(|| format!("binding {listen}"))?;
34 axum::serve(
35 listener,
36 app.into_make_service_with_connect_info::<SocketAddr>(),
37 )
38 .await
39 .context("serving")?;
40 Ok(())
41 }
42
43 fn env_filter() -> tracing_subscriber::EnvFilter {
44 tracing_subscriber::EnvFilter::try_from_default_env()
45 .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info"))
46 }
47
48 /// Minimal `--config <path>` parser (no clap dependency for one flag).
49 fn parse_config_arg() -> Option<String> {
50 let mut args = std::env::args().skip(1);
51 while let Some(a) = args.next() {
52 match a.as_str() {
53 "--config" | "-c" => return args.next(),
54 other if other.starts_with("--config=") => {
55 return Some(other.trim_start_matches("--config=").to_string());
56 }
57 _ => {}
58 }
59 }
60 None
61 }
62