beid_api 0.3.1

BeID common lib
Documentation
use itertools::Itertools;

fn is_mac() -> bool {
    cfg!(target_os = "macos")
}

// Note. the fields are sorted in the same way as when split cgroup line.
// see https://man7.org/linux/man-pages/man7/cgroups.7.html, search for /proc/[pid]/cgroup
struct CGroup<'a> {
    #[allow(dead_code)]
    hierarchy_id: &'a str,
    #[allow(dead_code)]
    controllers: &'a str,
    path: &'a str,
}

impl<'a> CGroup<'a> {
    pub fn parse(line: &'a str) -> Option<Self> {
        line.split(':')
            .tuples()
            .map(|(hierarchy_id, controllers, path)| Self {
                hierarchy_id,
                controllers,
                path,
            })
            .next()
    }

    pub fn is_container(&self) -> bool {
        let path = self.path;
        path.starts_with("/docker") || path.starts_with("/kube")
    }
}

/// Test if any input line is match known pattern of docker container
///
/// Unrecognized line is silently ignored
fn is_container(text: &str) -> bool {
    text.lines()
        .flat_map(CGroup::parse)
        .any(|cg| cg.is_container())
}

/// Returns `true` if current process is containerized.
pub fn is_containerized() -> bool {
    // darwin (macos) doesn't support docker natively
    if is_mac() {
        return false;
    }
    let pid = std::process::id();
    let cgroup_path = format!("/proc/{pid}/cgroup");
    // It is fine to panic here since we expect `/proc/<PID>/cgroup` to be readable on linux.
    let contents = std::fs::read_to_string(&cgroup_path).expect("Cannot open cgroup file");
    is_container(&contents)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parse_cgroup_correctly() {
        let actual = CGroup::parse("12:cpu,cpuacct:/").unwrap();
        assert_eq!(actual.hierarchy_id, "12");
        assert_eq!(actual.controllers, "cpu,cpuacct");
        assert_eq!(actual.path, "/");
    }

    #[test]
    fn test_is_container() {
        let docker_cgroup = r#"
12:cpu,cpuacct:/docker/c6fa62a9938149f6098fd0cdaffc9cdf0f526f25d97b5f6e2a4cc1fccc7f7ce1
11:perf_event:/docker/c6fa62a9938149f6098fd0cdaffc9cdf0f526f25d97b5f6e2a4cc1fccc7f7ce1
10:rdma:/"#;
        assert!(is_container(docker_cgroup));
        let init_cgroup = r#"
12:cpu,cpuacct:/
11:perf_event:/
0::/init.scope"#;
        assert!(!is_container(init_cgroup));
        let k8s_cgroup = r#"
12:hugetlb:/kubepods/besteffort/poda00e29fd-7bbd-11e9-8679-fa163ea7e3b8/c4b1403f3d9c7ce261be851df71d9a9773c53419075ccda39ae8fe6a39fd2eb1
11:cpuset:/kubepods/besteffort/poda00e29fd-7bbd-11e9-8679-fa163ea7e3b8/c4b1403f3d9c7ce261be851df71d9a9773c53419075ccda39ae8fe6a39fd2eb1"#;
        assert!(is_container(k8s_cgroup));
    }
}