From 59fed617a7cdc690af1114e069636b78d5863c0f Mon Sep 17 00:00:00 2001 From: Furisto <24721048+Furisto@users.noreply.github.com> Date: Fri, 11 Jun 2021 17:29:55 +0200 Subject: [PATCH] Add info command --- src/cgroups/common.rs | 27 ++++++++++++---- src/cgroups/v1/controller_type.rs | 42 ++++++++++++++++-------- src/cgroups/v1/cpuset.rs | 8 ++--- src/cgroups/v1/manager.rs | 54 ++++--------------------------- src/cgroups/v1/mod.rs | 1 + src/cgroups/v1/util.rs | 48 +++++++++++++++++++++++++++ src/cgroups/v2/mod.rs | 1 + src/cgroups/v2/util.rs | 13 ++++++++ src/main.rs | 44 +++++++++++++++++++++++++ 9 files changed, 167 insertions(+), 71 deletions(-) create mode 100644 src/cgroups/v1/util.rs create mode 100644 src/cgroups/v2/util.rs diff --git a/src/cgroups/common.rs b/src/cgroups/common.rs index e013dd19..56f3b1a5 100644 --- a/src/cgroups/common.rs +++ b/src/cgroups/common.rs @@ -6,7 +6,8 @@ use std::{ path::{Path, PathBuf}, }; -use anyhow::{anyhow, bail, Context, Result}; + +use anyhow::{bail, Context, Result}; use nix::unistd::Pid; use oci_spec::LinuxResources; use procfs::process::Process; @@ -67,13 +68,27 @@ pub fn write_cgroup_file, T: ToString>(path: P, data: T) -> Resul Ok(()) } -pub fn get_cgroupv1_mount_path(subsystem: &str) -> Result { - Process::myself()? +pub fn get_supported_cgroup_fs() -> Result> { + let cgroup_mount = Process::myself()? .mountinfo()? .into_iter() - .find(|m| m.fs_type == "cgroup" && m.mount_point.ends_with(subsystem)) - .map(|m| m.mount_point) - .ok_or_else(|| anyhow!("could not find mountpoint for {}", subsystem)) + .find(|m| m.fs_type == "cgroup"); + + let cgroup2_mount = Process::myself()? + .mountinfo()? + .into_iter() + .find(|m| m.fs_type == "cgroup2"); + + let mut cgroups = vec![]; + if cgroup_mount.is_some() { + cgroups.push(Cgroup::V1); + } + + if cgroup2_mount.is_some() { + cgroups.push(Cgroup::V2); + } + + Ok(cgroups) } pub fn create_cgroup_manager>(cgroup_path: P) -> Result> { diff --git a/src/cgroups/v1/controller_type.rs b/src/cgroups/v1/controller_type.rs index 735a60a1..722d1b54 100644 --- a/src/cgroups/v1/controller_type.rs +++ b/src/cgroups/v1/controller_type.rs @@ -1,4 +1,4 @@ -use std::string::ToString; +use std::fmt::Display; pub enum ControllerType { Cpu, @@ -12,18 +12,32 @@ pub enum ControllerType { NetworkClassifier, } -impl ToString for ControllerType { - fn to_string(&self) -> String { - match self { - Self::Cpu => "cpu".into(), - Self::CpuSet => "cpuset".into(), - Self::Devices => "devices".into(), - Self::HugeTlb => "hugetlb".into(), - Self::Pids => "pids".into(), - Self::Memory => "memory".into(), - Self::Blkio => "blkio".into(), - Self::NetworkPriority => "net_prio".into(), - Self::NetworkClassifier => "net_cls".into(), - } +impl Display for ControllerType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let print = match *self { + Self::Cpu => "cpu", + Self::CpuSet => "cpuset", + Self::Devices => "devices", + Self::HugeTlb => "hugetlb", + Self::Pids => "pids", + Self::Memory => "memory", + Self::Blkio => "blkio", + Self::NetworkPriority => "net_prio", + Self::NetworkClassifier => "net_cls", + }; + + write!(f, "{}", print) } } + +pub const CONTROLLERS: &[ControllerType] = &[ + ControllerType::Cpu, + ControllerType::CpuSet, + ControllerType::Devices, + ControllerType::HugeTlb, + ControllerType::Memory, + ControllerType::Pids, + ControllerType::Blkio, + ControllerType::NetworkPriority, + ControllerType::NetworkClassifier, +]; diff --git a/src/cgroups/v1/cpuset.rs b/src/cgroups/v1/cpuset.rs index e989e5aa..c08833c5 100644 --- a/src/cgroups/v1/cpuset.rs +++ b/src/cgroups/v1/cpuset.rs @@ -6,7 +6,7 @@ use oci_spec::{LinuxCpu, LinuxResources}; use crate::cgroups::common::{self, CGROUP_PROCS}; -use super::{Controller, ControllerType}; +use super::{util, Controller, ControllerType}; const CGROUP_CPUSET_CPUS: &str = "cpuset.cpus"; const CGROUP_CPUSET_MEMS: &str = "cpuset.mems"; @@ -34,11 +34,11 @@ impl CpuSet { fn apply(cgroup_path: &Path, cpuset: &LinuxCpu) -> Result<()> { if let Some(cpus) = &cpuset.cpus { common::write_cgroup_file_str(cgroup_path.join(CGROUP_CPUSET_CPUS), cpus)?; - } + } if let Some(mems) = &cpuset.mems { common::write_cgroup_file_str(cgroup_path.join(CGROUP_CPUSET_MEMS), mems)?; - } + } Ok(()) } @@ -46,7 +46,7 @@ impl CpuSet { // if a task is moved into the cgroup and a value has not been set for cpus and mems // Errno 28 (no space left on device) will be returned. Therefore we set the value from the parent if required. fn ensure_not_empty(cgroup_path: &Path, interface_file: &str) -> Result<()> { - let mut current = common::get_cgroupv1_mount_path(&ControllerType::CpuSet.to_string())?; + let mut current = util::get_subsystem_mount_points(&ControllerType::CpuSet.to_string())?; let relative_cgroup_path = cgroup_path.strip_prefix(¤t)?; for component in relative_cgroup_path.components() { diff --git a/src/cgroups/v1/manager.rs b/src/cgroups/v1/manager.rs index 2a6a18d0..886b065d 100644 --- a/src/cgroups/v1/manager.rs +++ b/src/cgroups/v1/manager.rs @@ -8,28 +8,15 @@ use nix::unistd::Pid; use procfs::process::Process; use super::{ - blkio::Blkio, cpu::Cpu, cpuset::CpuSet, devices::Devices, hugetlb::Hugetlb, memory::Memory, - network_classifier::NetworkClassifier, network_priority::NetworkPriority, pids::Pids, - Controller, ControllerType, + blkio::Blkio, controller_type::CONTROLLERS, cpu::Cpu, cpuset::CpuSet, devices::Devices, + hugetlb::Hugetlb, memory::Memory, network_classifier::NetworkClassifier, + network_priority::NetworkPriority, pids::Pids, util, Controller, }; use crate::cgroups::common::CGROUP_PROCS; use crate::utils; use crate::{cgroups::common::CgroupManager, utils::PathBufExt}; use oci_spec::LinuxResources; - -const CONTROLLERS: &[ControllerType] = &[ - ControllerType::Cpu, - ControllerType::CpuSet, - ControllerType::Devices, - ControllerType::HugeTlb, - ControllerType::Memory, - ControllerType::Pids, - ControllerType::Blkio, - ControllerType::NetworkPriority, - ControllerType::NetworkClassifier, -]; - pub struct Manager { subsystems: HashMap, } @@ -49,32 +36,7 @@ impl Manager { fn get_subsystem_path(cgroup_path: &Path, subsystem: &str) -> anyhow::Result { log::debug!("Get path for subsystem: {}", subsystem); - let mount = Process::myself()? - .mountinfo()? - .into_iter() - .find(|m| { - if m.fs_type == "cgroup" { - // Some systems mount net_prio and net_cls in the same directory - // other systems mount them in their own diretories. This - // should handle both cases. - if subsystem == "net_cls" { - return m.mount_point.ends_with("net_cls,net_prio") - || m.mount_point.ends_with("net_prio,net_cls") - || m.mount_point.ends_with("net_cls"); - } else if subsystem == "net_prio" { - return m.mount_point.ends_with("net_cls,net_prio") - || m.mount_point.ends_with("net_prio,net_cls") - || m.mount_point.ends_with("net_prio"); - } - - if subsystem == "cpu" { - return m.mount_point.ends_with("cpu,cpuacct") - || m.mount_point.ends_with("cpu"); - } - } - m.mount_point.ends_with(subsystem) - }) - .unwrap(); + let mount_point = util::get_subsystem_mount_points(subsystem)?; let cgroup = Process::myself()? .cgroups()? @@ -83,13 +45,11 @@ impl Manager { .unwrap(); let p = if cgroup_path.to_string_lossy().into_owned().is_empty() { - mount - .mount_point - .join_absolute_path(Path::new(&cgroup.pathname))? + mount_point.join_absolute_path(Path::new(&cgroup.pathname))? } else if cgroup_path.is_absolute() { - mount.mount_point.join_absolute_path(&cgroup_path)? + mount_point.join_absolute_path(&cgroup_path)? } else { - mount.mount_point.join(cgroup_path) + mount_point.join(cgroup_path) }; Ok(p) diff --git a/src/cgroups/v1/mod.rs b/src/cgroups/v1/mod.rs index d3eb050b..7d9b75b0 100644 --- a/src/cgroups/v1/mod.rs +++ b/src/cgroups/v1/mod.rs @@ -10,6 +10,7 @@ mod memory; mod network_classifier; mod network_priority; mod pids; +pub mod util; pub use controller::Controller; pub use controller_type::ControllerType; pub use manager::Manager; diff --git a/src/cgroups/v1/util.rs b/src/cgroups/v1/util.rs new file mode 100644 index 00000000..76236c69 --- /dev/null +++ b/src/cgroups/v1/util.rs @@ -0,0 +1,48 @@ +use std::{collections::HashMap, path::PathBuf}; + +use anyhow::{anyhow, Result}; +use procfs::process::Process; + +use super::controller_type::CONTROLLERS; + +pub fn list_subsystem_mount_points() -> Result> { + let mut mount_paths = HashMap::with_capacity(CONTROLLERS.len()); + + for controller in CONTROLLERS { + if let Ok(mount_point) = get_subsystem_mount_points(&controller.to_string()) { + mount_paths.insert(controller.to_string(), mount_point); + } + } + + Ok(mount_paths) +} + +pub fn get_subsystem_mount_points(subsystem: &str) -> Result { + Process::myself()? + .mountinfo()? + .into_iter() + .find(|m| { + if m.fs_type == "cgroup" { + // Some systems mount net_prio and net_cls in the same directory + // other systems mount them in their own diretories. This + // should handle both cases. + if subsystem == "net_cls" { + return m.mount_point.ends_with("net_cls,net_prio") + || m.mount_point.ends_with("net_prio,net_cls") + || m.mount_point.ends_with("net_cls"); + } else if subsystem == "net_prio" { + return m.mount_point.ends_with("net_cls,net_prio") + || m.mount_point.ends_with("net_prio,net_cls") + || m.mount_point.ends_with("net_prio"); + } + + if subsystem == "cpu" { + return m.mount_point.ends_with("cpu,cpuacct") + || m.mount_point.ends_with("cpu"); + } + } + m.mount_point.ends_with(&subsystem) + }) + .map(|m| m.mount_point) + .ok_or_else(|| anyhow!("could not find mountpoint for {}", subsystem)) +} \ No newline at end of file diff --git a/src/cgroups/v2/mod.rs b/src/cgroups/v2/mod.rs index df18307c..cea672f0 100644 --- a/src/cgroups/v2/mod.rs +++ b/src/cgroups/v2/mod.rs @@ -7,3 +7,4 @@ mod io; pub mod manager; mod memory; mod pids; +pub mod util; diff --git a/src/cgroups/v2/util.rs b/src/cgroups/v2/util.rs new file mode 100644 index 00000000..e8712b51 --- /dev/null +++ b/src/cgroups/v2/util.rs @@ -0,0 +1,13 @@ +use std::path::PathBuf; + +use anyhow::{anyhow, Result}; +use procfs::process::Process; + +pub fn get_unified_mount_point() -> Result { + Process::myself()? + .mountinfo()? + .into_iter() + .find(|m| m.fs_type == "cgroup2") + .map(|m| m.mount_point) + .ok_or_else(|| anyhow!("could not find mountpoint for unified")) +} diff --git a/src/main.rs b/src/main.rs index a362203b..f174cb60 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ //! Container Runtime written in Rust, inspired by [railcar](https://github.com/oracle/railcar) //! This crate provides a container runtime which can be used by a high-level container runtime to run containers. +use procfs; use std::fs; use std::path::{Path, PathBuf}; @@ -66,6 +67,8 @@ enum SubCommand { Delete(Delete), #[clap(version = "0.0.1", author = "utam0k ")] State(StateArgs), + #[clap(version = "0.0.1", author = "utam0k ")] + Info, } /// This is the entry point in the container runtime. The binary is run by a high-level container runtime, @@ -162,5 +165,46 @@ fn main() -> Result<()> { println!("{}", serde_json::to_string_pretty(&container.state)?); std::process::exit(0); } + + SubCommand::Info => { + let uname = nix::sys::utsname::uname(); + println!("{:<18}{}", "Kernel-Release", uname.release()); + println!("{:<18}{}", "Kernel-Version", uname.version()); + println!("{:<18}{}", "Architecture", uname.machine()); + + let cpu_info = procfs::CpuInfo::new()?; + println!("{:<18}{}", "Cores", cpu_info.num_cores()); + let mem_info = procfs::Meminfo::new()?; + println!( + "{:<18}{}", + "Total Memory", + mem_info.mem_total / u64::pow(1024, 2) + ); + + let cgroup_fs: Vec = cgroups::common::get_supported_cgroup_fs()? + .into_iter() + .map(|c| c.to_string()) + .collect(); + println!("{:<18}{}", "cgroup version", cgroup_fs.join(" and ")); + + println!("cgroup mounts"); + let mut cgroup_v1_mounts: Vec = + cgroups::v1::util::list_subsystem_mount_points()? + .iter() + .map(|kv| format!(" {:<16}{:?}", kv.0, kv.1)) + .collect(); + + cgroup_v1_mounts.sort(); + for cgroup_mount in cgroup_v1_mounts { + println!("{}", cgroup_mount); + } + + let unified = cgroups::v2::util::get_unified_mount_point(); + if let Ok(mount_point) = unified { + println!(" {:<16}{:?}", "unified", mount_point); + } + + Ok(()) + } } }