Skip to main content

container_pid/
lib.rs

1use std::fmt::Debug;
2use std::fmt::Write;
3
4/// A raw process ID as used by the kernel.
5pub type RawPid = i32;
6
7mod cmd;
8mod command;
9mod containerd;
10mod docker;
11mod errors;
12mod kubernetes;
13mod lxc;
14mod lxd;
15mod nspawn;
16mod podman;
17mod process_id;
18
19pub use errors::Error;
20
21pub trait Container: Debug {
22    fn lookup(&self, id: &str) -> Result<RawPid, Error>;
23    fn check_required_tools(&self) -> Result<(), Error>;
24}
25
26pub const AVAILABLE_CONTAINER_TYPES: &[&str] = &[
27    "process_id",
28    "podman",
29    "docker",
30    "nspawn",
31    "lxc",
32    "lxd",
33    "command",
34    "containerd",
35    "kubernetes",
36];
37
38fn default_order() -> Vec<Box<dyn Container>> {
39    let containers: Vec<Box<dyn Container>> = vec![
40        Box::new(process_id::ProcessId {}),
41        Box::new(podman::Podman {}),
42        Box::new(docker::Docker {}),
43        Box::new(nspawn::Nspawn {}),
44        Box::new(lxc::Lxc {}),
45        Box::new(lxd::Lxd {}),
46        Box::new(containerd::Containerd {}),
47        Box::new(kubernetes::Kubernetes {}),
48    ];
49    containers
50        .into_iter()
51        .filter(|c| c.check_required_tools().is_ok())
52        .collect()
53}
54
55pub fn lookup_container_type(name: &str) -> Option<Box<dyn Container>> {
56    Some(match name {
57        "process_id" => Box::new(process_id::ProcessId {}),
58        "podman" => Box::new(podman::Podman {}),
59        "docker" => Box::new(docker::Docker {}),
60        "nspawn" => Box::new(nspawn::Nspawn {}),
61        "lxc" => Box::new(lxc::Lxc {}),
62        "lxd" => Box::new(lxd::Lxd {}),
63        "containerd" => Box::new(containerd::Containerd {}),
64        "command" => Box::new(command::Command {}),
65        "kubernetes" => Box::new(kubernetes::Kubernetes {}),
66        _ => return None,
67    })
68}
69
70pub fn lookup_container_pid(
71    container_id: &str,
72    container_types: &[Box<dyn Container>],
73) -> Result<RawPid, Error> {
74    for c in container_types {
75        c.check_required_tools()?;
76    }
77    let fallback: Vec<Box<dyn Container>> = default_order();
78    let types = if container_types.is_empty() {
79        fallback.as_slice()
80    } else {
81        container_types
82    };
83
84    let mut tried = String::new();
85    for t in types {
86        match t.lookup(container_id) {
87            Ok(pid) => return Ok(pid),
88            Err(e) => {
89                let _ = write!(tried, "\n  - {:?}: {}", t, errors::format_chain(&e));
90            }
91        };
92    }
93
94    Err(Error::NoRuntimeMatched {
95        container: container_id.to_string(),
96        tried,
97    })
98}