saluki_env/features/
containerd.rs

1use std::path::PathBuf;
2
3#[cfg(unix)]
4use tracing::debug;
5
6#[cfg(unix)]
7use super::{
8    find_first_available_unix_socket, is_running_inside_docker, path_contains, path_empty, with_host_mount_prefixes,
9};
10
11#[cfg(unix)]
12const DEFAULT_CONTAINERD_SOCKET_PATH_LINUX: &str = "/var/run/containerd/containerd.sock";
13
14/// Helper type for detecting if containerd is available.
15pub struct ContainerdDetector;
16
17impl ContainerdDetector {
18    /// Tries to detect the containerd gRPC socket path.
19    ///
20    /// If `socket_path` is given, that path is used. Otherwise, well-known paths are probed for a Unix domain socket.
21    /// Either way, `None` is returned unless the resulting path refers to containerd.
22    #[cfg(unix)]
23    pub fn detect_grpc_socket_path(socket_path: Option<PathBuf>) -> Option<PathBuf> {
24        let detected_socket_path = match socket_path {
25            Some(socket_path) => Some(socket_path),
26            None => {
27                if is_running_inside_docker() {
28                    None
29                } else {
30                    debug!("No containerd socket path configured. Trying to detect at default paths...");
31
32                    let default_socket_paths = with_host_mount_prefixes([DEFAULT_CONTAINERD_SOCKET_PATH_LINUX]);
33                    find_first_available_unix_socket(default_socket_paths)
34                }
35            }
36        }?;
37
38        // If the path isn't empty, and it contains "containerd", we can assume it's the containerd socket.
39        if !path_empty(&detected_socket_path) && path_contains(&detected_socket_path, "containerd") {
40            debug!(socket_path = %detected_socket_path.to_string_lossy(), "Detected containerd socket path.");
41            Some(detected_socket_path)
42        } else {
43            None
44        }
45    }
46
47    /// Returns `None` because containerd Unix socket detection isn't supported on this platform.
48    #[cfg(not(unix))]
49    pub fn detect_grpc_socket_path(_: Option<PathBuf>) -> Option<PathBuf> {
50        None
51    }
52}
53
54#[cfg(all(test, unix))]
55mod tests {
56    use std::path::PathBuf;
57
58    use super::ContainerdDetector;
59
60    #[test]
61    fn a_configured_socket_path_is_used_without_probing() {
62        let configured = PathBuf::from("/custom/run/containerd/containerd.sock");
63
64        assert_eq!(
65            ContainerdDetector::detect_grpc_socket_path(Some(configured.clone())),
66            Some(configured)
67        );
68    }
69
70    #[test]
71    fn a_configured_empty_socket_path_leaves_containerd_undetected() {
72        assert_eq!(ContainerdDetector::detect_grpc_socket_path(Some(PathBuf::new())), None);
73    }
74
75    #[test]
76    fn a_configured_socket_path_for_another_runtime_leaves_containerd_undetected() {
77        let configured = PathBuf::from("/var/run/crio/crio.sock");
78
79        assert_eq!(ContainerdDetector::detect_grpc_socket_path(Some(configured)), None);
80    }
81}