saluki_env/workload/on_demand_pid/
mod.rs

1use std::path::PathBuf;
2#[cfg(target_os = "linux")]
3use std::sync::Arc;
4
5use saluki_error::GenericError;
6use stringtheory::interning::GenericMapInterner;
7
8use crate::{features::FeatureDetector, workload::EntityId};
9
10#[cfg(target_os = "linux")]
11mod linux;
12
13/// A resolver for mapping process IDs to their container IDs based on querying the underlying host.
14///
15/// # Platform support
16///
17/// On Linux, PIDs are resolved by querying procfs to find the cgroup of the process, if one exists, the cgroup
18/// hierarchy is queried to discover the container ID that owns the process, if possible.
19///
20/// On all other platforms, resolving a PID is a no-op.
21#[derive(Clone)]
22pub struct OnDemandPIDResolver {
23    #[cfg(target_os = "linux")]
24    inner: Arc<linux::ResolverImpl>,
25    #[cfg(not(target_os = "linux"))]
26    _empty: (),
27}
28
29impl OnDemandPIDResolver {
30    /// Creates a new `OnDemandPIDResolver` for the given container filesystem roots.
31    ///
32    /// If a root is given, that path is used. Otherwise, it is resolved from the detected features.
33    ///
34    /// # Errors
35    ///
36    /// On Linux, if a cgroups hierarchy can't be found, or the internal cache can't be created, an error is returned.
37    /// On all other platforms, no error is possible.
38    pub fn new(
39        procfs_root: Option<PathBuf>, cgroupfs_root: Option<PathBuf>, feature_detector: &FeatureDetector,
40        interner: GenericMapInterner,
41    ) -> Result<Self, GenericError> {
42        #[cfg(target_os = "linux")]
43        {
44            let cgroups_config = crate::workload::helpers::cgroups::CgroupsConfiguration::new(
45                procfs_root,
46                cgroupfs_root,
47                feature_detector,
48            );
49            let resolver_inner = linux::ResolverImpl::new(&cgroups_config, interner)?;
50            Ok(Self {
51                inner: Arc::new(resolver_inner),
52            })
53        }
54
55        #[cfg(not(target_os = "linux"))]
56        {
57            // Rebind to make compiler happy.
58            let _procfs_root = procfs_root;
59            let _cgroupfs_root = cgroupfs_root;
60            let _feature_detector = feature_detector;
61            let _interner = interner;
62
63            Ok(Self { _empty: () })
64        }
65    }
66
67    /// Resolves a process ID to the container ID of the container is part of.
68    ///
69    /// If the process ID isn't part of a container, or can't be found, `None` is returned.
70    pub fn resolve(&self, process_id: u32) -> Option<EntityId> {
71        #[cfg(target_os = "linux")]
72        let resolved = self.inner.resolve(process_id);
73
74        #[cfg(not(target_os = "linux"))]
75        let resolved = {
76            // Rebind to make compiler happy.
77            let _process_id = process_id;
78            None
79        };
80
81        resolved
82    }
83
84    /// Resolves the current process's container entity from local cgroup membership.
85    ///
86    /// On non-Linux platforms, or when the process is not in a recognizable container cgroup, this returns `None`.
87    pub fn resolve_self_container(&self) -> Option<EntityId> {
88        #[cfg(target_os = "linux")]
89        let resolved = self.inner.resolve_self_container();
90
91        #[cfg(not(target_os = "linux"))]
92        let resolved = None;
93
94        resolved
95    }
96}