conmonrs/oom_watcher/
cgroup_path.rs1use super::{CGROUP_ROOT, OOMWatcher};
4use anyhow::{Context, Result, bail};
5use nix::unistd::Pid;
6use std::{
7 fs::File as StdFile,
8 io::{BufRead, BufReader, ErrorKind},
9 path::{Path, PathBuf},
10};
11use tracing::{debug, trace};
12
13impl OOMWatcher {
14 pub(super) fn process_cgroup_subsystem_path_cgroup_v2(pid: Pid) -> Result<Option<PathBuf>> {
16 if let Some(fp) = Self::try_open_cgroup_path(pid)? {
17 return Self::unified_cgroup_path(BufReader::new(fp)).map(Some);
18 }
19
20 Ok(None)
21 }
22
23 pub(super) fn unified_cgroup_path(cgroup_file: impl BufRead) -> Result<PathBuf> {
27 for line in cgroup_file.lines() {
28 let line = line.context("read line from cgroup file")?;
29 if line.starts_with("0::") {
30 return Self::cgroup_v2_path(&line);
31 }
32 }
33 bail!("no unified hierarchy found in cgroup file")
34 }
35
36 pub(super) fn cgroup_v2_path(line: &str) -> Result<PathBuf> {
39 let path = Self::strip_cgroup_root(line.splitn(3, ':').nth(2))?;
40 Ok(Path::new(CGROUP_ROOT).join(path))
41 }
42
43 fn strip_cgroup_root(path: Option<&str>) -> Result<&str> {
45 Ok(path
46 .context("no path found in cgroup")?
47 .strip_prefix("/")
48 .context("strip root path prefix")?
49 .trim_end())
50 }
51
52 fn try_open_cgroup_path(pid: Pid) -> Result<Option<StdFile>> {
53 let cgroup_path = PathBuf::from("/proc").join(pid.to_string()).join("cgroup");
54 debug!("Using cgroup path: {}", cgroup_path.display());
55
56 match StdFile::open(&cgroup_path) {
57 Ok(file) => Ok(file.into()),
58 Err(error) if error.kind() == ErrorKind::NotFound => {
60 trace!("Cgroup path not found: {}", cgroup_path.display());
61 Ok(None)
62 }
63 Err(error) => bail!("open cgroup path {}: {}", cgroup_path.display(), error),
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn cgroup_paths_from_proc_lines() -> Result<()> {
74 let root = Path::new(CGROUP_ROOT);
75 assert_eq!(
76 OOMWatcher::cgroup_v2_path("0::/kubepods.slice/crio-1:2.scope\n")?,
77 root.join("kubepods.slice/crio-1:2.scope")
78 );
79 assert_eq!(OOMWatcher::cgroup_v2_path("0::/")?, root.to_path_buf());
80 assert!(OOMWatcher::cgroup_v2_path("0:").is_err());
81 assert!(OOMWatcher::cgroup_v2_path("0::relative").is_err());
82
83 assert_eq!(
85 OOMWatcher::unified_cgroup_path(
86 &b"1:name=systemd:/user.slice\n0::/kubepods.slice/ctr\n"[..]
87 )?,
88 root.join("kubepods.slice/ctr")
89 );
90 assert_eq!(
91 OOMWatcher::unified_cgroup_path(&b"0::/ctr\n"[..])?,
92 root.join("ctr")
93 );
94 assert!(OOMWatcher::unified_cgroup_path(&b"1:name=systemd:/x\n"[..]).is_err());
95 Ok(())
96 }
97}