Skip to content

Commit

Permalink
Merge pull request #83 from Furisto/info-cmd
Browse files Browse the repository at this point in the history
Add info command
  • Loading branch information
Furisto authored Jun 12, 2021
2 parents a6a8435 + 59fed61 commit 0378410
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 71 deletions.
27 changes: 21 additions & 6 deletions src/cgroups/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -67,13 +68,27 @@ pub fn write_cgroup_file<P: AsRef<Path>, T: ToString>(path: P, data: T) -> Resul
Ok(())
}

pub fn get_cgroupv1_mount_path(subsystem: &str) -> Result<PathBuf> {
Process::myself()?
pub fn get_supported_cgroup_fs() -> Result<Vec<Cgroup>> {
let cgroup_mount = Process::myself()?
.mountinfo()?
.into_iter()
.find(|m| m.fs_type == "cgroup");

let cgroup2_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 == "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<P: Into<PathBuf>>(cgroup_path: P) -> Result<Box<dyn CgroupManager>> {
Expand Down
42 changes: 28 additions & 14 deletions src/cgroups/v1/controller_type.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::string::ToString;
use std::fmt::Display;

pub enum ControllerType {
Cpu,
Expand All @@ -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,
];
8 changes: 4 additions & 4 deletions src/cgroups/v1/cpuset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -34,19 +34,19 @@ 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(())
}

// 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(&current)?;

for component in relative_cgroup_path.components() {
Expand Down
54 changes: 7 additions & 47 deletions src/cgroups/v1/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, PathBuf>,
}
Expand All @@ -49,32 +36,7 @@ impl Manager {

fn get_subsystem_path(cgroup_path: &Path, subsystem: &str) -> anyhow::Result<PathBuf> {
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()?
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions src/cgroups/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
48 changes: 48 additions & 0 deletions src/cgroups/v1/util.rs
Original file line number Diff line number Diff line change
@@ -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<HashMap<String, PathBuf>> {
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<PathBuf> {
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))
}
1 change: 1 addition & 0 deletions src/cgroups/v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ mod io;
pub mod manager;
mod memory;
mod pids;
pub mod util;
13 changes: 13 additions & 0 deletions src/cgroups/v2/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use std::path::PathBuf;

use anyhow::{anyhow, Result};
use procfs::process::Process;

pub fn get_unified_mount_point() -> Result<PathBuf> {
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"))
}
44 changes: 44 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -66,6 +67,8 @@ enum SubCommand {
Delete(Delete),
#[clap(version = "0.0.1", author = "utam0k <[email protected]>")]
State(StateArgs),
#[clap(version = "0.0.1", author = "utam0k <[email protected]>")]
Info,
}

/// This is the entry point in the container runtime. The binary is run by a high-level container runtime,
Expand Down Expand Up @@ -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<String> = 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<String> =
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(())
}
}
}

0 comments on commit 0378410

Please sign in to comment.