solti_exec/subprocess/mod.rs
1//! # Subprocess: OS process runner for `TaskKind::Subprocess`.
2//!
3//! Executes tasks by spawning child OS processes with optional backend hardening (rlimits, cgroups, security capabilities).
4//!
5//! ## Modules
6//!
7//! | Module | What it does |
8//! |-------------|---------------------------------------------------------|
9//! | `runner` | [`SubprocessRunner`]: `Runner` trait impl + execution |
10//! | `backend` | [`SubprocessBackendConfig`]: rlimits, cgroups, security |
11//! | `task` | [`SubprocessTaskConfig`]: resolved runtime config |
12//! | `logger` | [`LogConfig`] + stream capture, truncation, tracing |
13//!
14//! ## Quick start
15//! ```text
16//! register_subprocess_runner(&mut router, "my-runner")
17//! ├──► creates SubprocessRunner::new("my-runner")
18//! ├──► attaches label "runner-name" = "my-runner"
19//! └──► registers in RunnerRouter
20//!
21//! register_subprocess_runner_with_backend(&mut router, "secure", backend)
22//! ├──► validates SubprocessBackendConfig
23//! ├──► creates SubprocessRunner::with_config("secure", backend)
24//! ├──► attaches label "runner-name" = "secure"
25//! └──► registers in RunnerRouter
26//! ```
27//!
28//! ## Registration guard
29//! - Duplicate runner names are rejected via `router.contains_label()` check
30//! - Returns `ExecError::DuplicateRunner` if a runner with the same name exists
31mod backend;
32pub use backend::SubprocessBackendConfig;
33
34mod task;
35pub use task::SubprocessTaskConfig;
36
37mod logger;
38pub use logger::LogConfig;
39
40mod runner;
41pub use runner::SubprocessRunner;
42
43use std::sync::Arc;
44
45use solti_model::Labels;
46use solti_runner::RunnerRouter;
47
48use crate::ExecError;
49
50/// Well-known label key used to identify a runner by name.
51pub const LABEL_RUNNER_NAME: &str = "runner-name";
52
53/// Register a subprocess runner with default settings.
54pub fn register_subprocess_runner(
55 router: &mut RunnerRouter,
56 name: &'static str,
57) -> Result<(), ExecError> {
58 register_runner_inner(router, name, Arc::new(SubprocessRunner::new(name)))
59}
60
61/// Register a subprocess runner with explicit runner configuration.
62pub fn register_subprocess_runner_with_backend(
63 router: &mut RunnerRouter,
64 name: &'static str,
65 backend: SubprocessBackendConfig,
66) -> Result<(), ExecError> {
67 register_runner_inner(
68 router,
69 name,
70 Arc::new(SubprocessRunner::with_config(name, backend)?),
71 )
72}
73
74fn register_runner_inner(
75 router: &mut RunnerRouter,
76 name: &'static str,
77 runner: Arc<SubprocessRunner>,
78) -> Result<(), ExecError> {
79 if router.contains_label(LABEL_RUNNER_NAME, name) {
80 return Err(ExecError::DuplicateRunner {
81 name: name.to_string(),
82 });
83 }
84 let mut labels = Labels::new();
85 labels.insert(LABEL_RUNNER_NAME, name);
86 router.register_with_labels(runner, labels);
87 Ok(())
88}