Skip to main content

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}