1
0
mirror of https://github.com/containers/youki synced 2024-11-22 17:02:00 +01:00

Merge pull request #83 from Furisto/info-cmd

Add info command
This commit is contained in:
Furisto 2021-06-12 11:03:50 +02:00 committed by GitHub
commit 0378410c24
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 167 additions and 71 deletions

@ -6,7 +6,8 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use anyhow::{anyhow, bail, Context, Result};
use anyhow::{bail, Context, Result};
use nix::unistd::Pid; use nix::unistd::Pid;
use oci_spec::LinuxResources; use oci_spec::LinuxResources;
use procfs::process::Process; use procfs::process::Process;
@ -67,13 +68,27 @@ pub fn write_cgroup_file<P: AsRef<Path>, T: ToString>(path: P, data: T) -> Resul
Ok(()) Ok(())
} }
pub fn get_cgroupv1_mount_path(subsystem: &str) -> Result<PathBuf> { pub fn get_supported_cgroup_fs() -> Result<Vec<Cgroup>> {
Process::myself()? let cgroup_mount = Process::myself()?
.mountinfo()? .mountinfo()?
.into_iter() .into_iter()
.find(|m| m.fs_type == "cgroup" && m.mount_point.ends_with(subsystem)) .find(|m| m.fs_type == "cgroup");
.map(|m| m.mount_point)
.ok_or_else(|| anyhow!("could not find mountpoint for {}", subsystem)) 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<P: Into<PathBuf>>(cgroup_path: P) -> Result<Box<dyn CgroupManager>> { pub fn create_cgroup_manager<P: Into<PathBuf>>(cgroup_path: P) -> Result<Box<dyn CgroupManager>> {

@ -1,4 +1,4 @@
use std::string::ToString; use std::fmt::Display;
pub enum ControllerType { pub enum ControllerType {
Cpu, Cpu,
@ -12,18 +12,32 @@ pub enum ControllerType {
NetworkClassifier, NetworkClassifier,
} }
impl ToString for ControllerType { impl Display for ControllerType {
fn to_string(&self) -> String { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { let print = match *self {
Self::Cpu => "cpu".into(), Self::Cpu => "cpu",
Self::CpuSet => "cpuset".into(), Self::CpuSet => "cpuset",
Self::Devices => "devices".into(), Self::Devices => "devices",
Self::HugeTlb => "hugetlb".into(), Self::HugeTlb => "hugetlb",
Self::Pids => "pids".into(), Self::Pids => "pids",
Self::Memory => "memory".into(), Self::Memory => "memory",
Self::Blkio => "blkio".into(), Self::Blkio => "blkio",
Self::NetworkPriority => "net_prio".into(), Self::NetworkPriority => "net_prio",
Self::NetworkClassifier => "net_cls".into(), 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,
];

@ -6,7 +6,7 @@ use oci_spec::{LinuxCpu, LinuxResources};
use crate::cgroups::common::{self, CGROUP_PROCS}; 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_CPUS: &str = "cpuset.cpus";
const CGROUP_CPUSET_MEMS: &str = "cpuset.mems"; const CGROUP_CPUSET_MEMS: &str = "cpuset.mems";
@ -34,11 +34,11 @@ impl CpuSet {
fn apply(cgroup_path: &Path, cpuset: &LinuxCpu) -> Result<()> { fn apply(cgroup_path: &Path, cpuset: &LinuxCpu) -> Result<()> {
if let Some(cpus) = &cpuset.cpus { if let Some(cpus) = &cpuset.cpus {
common::write_cgroup_file_str(cgroup_path.join(CGROUP_CPUSET_CPUS), cpus)?; common::write_cgroup_file_str(cgroup_path.join(CGROUP_CPUSET_CPUS), cpus)?;
} }
if let Some(mems) = &cpuset.mems { if let Some(mems) = &cpuset.mems {
common::write_cgroup_file_str(cgroup_path.join(CGROUP_CPUSET_MEMS), mems)?; common::write_cgroup_file_str(cgroup_path.join(CGROUP_CPUSET_MEMS), mems)?;
} }
Ok(()) 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 // 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. // 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<()> { 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)?; let relative_cgroup_path = cgroup_path.strip_prefix(&current)?;
for component in relative_cgroup_path.components() { for component in relative_cgroup_path.components() {

@ -8,28 +8,15 @@ use nix::unistd::Pid;
use procfs::process::Process; use procfs::process::Process;
use super::{ use super::{
blkio::Blkio, cpu::Cpu, cpuset::CpuSet, devices::Devices, hugetlb::Hugetlb, memory::Memory, blkio::Blkio, controller_type::CONTROLLERS, cpu::Cpu, cpuset::CpuSet, devices::Devices,
network_classifier::NetworkClassifier, network_priority::NetworkPriority, pids::Pids, hugetlb::Hugetlb, memory::Memory, network_classifier::NetworkClassifier,
Controller, ControllerType, network_priority::NetworkPriority, pids::Pids, util, Controller,
}; };
use crate::cgroups::common::CGROUP_PROCS; use crate::cgroups::common::CGROUP_PROCS;
use crate::utils; use crate::utils;
use crate::{cgroups::common::CgroupManager, utils::PathBufExt}; use crate::{cgroups::common::CgroupManager, utils::PathBufExt};
use oci_spec::LinuxResources; 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 { pub struct Manager {
subsystems: HashMap<String, PathBuf>, subsystems: HashMap<String, PathBuf>,
} }
@ -49,32 +36,7 @@ impl Manager {
fn get_subsystem_path(cgroup_path: &Path, subsystem: &str) -> anyhow::Result<PathBuf> { fn get_subsystem_path(cgroup_path: &Path, subsystem: &str) -> anyhow::Result<PathBuf> {
log::debug!("Get path for subsystem: {}", subsystem); log::debug!("Get path for subsystem: {}", subsystem);
let mount = Process::myself()? let mount_point = util::get_subsystem_mount_points(subsystem)?;
.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 cgroup = Process::myself()? let cgroup = Process::myself()?
.cgroups()? .cgroups()?
@ -83,13 +45,11 @@ impl Manager {
.unwrap(); .unwrap();
let p = if cgroup_path.to_string_lossy().into_owned().is_empty() { 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() { } else if cgroup_path.is_absolute() {
mount.mount_point.join_absolute_path(&cgroup_path)? mount_point.join_absolute_path(&cgroup_path)?
} else { } else {
mount.mount_point.join(cgroup_path) mount_point.join(cgroup_path)
}; };
Ok(p) Ok(p)

@ -10,6 +10,7 @@ mod memory;
mod network_classifier; mod network_classifier;
mod network_priority; mod network_priority;
mod pids; mod pids;
pub mod util;
pub use controller::Controller; pub use controller::Controller;
pub use controller_type::ControllerType; pub use controller_type::ControllerType;
pub use manager::Manager; pub use manager::Manager;

48
src/cgroups/v1/util.rs Normal file

@ -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))
}

@ -7,3 +7,4 @@ mod io;
pub mod manager; pub mod manager;
mod memory; mod memory;
mod pids; mod pids;
pub mod util;

13
src/cgroups/v2/util.rs Normal file

@ -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"))
}

@ -2,6 +2,7 @@
//! Container Runtime written in Rust, inspired by [railcar](https://github.com/oracle/railcar) //! 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. //! 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::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -66,6 +67,8 @@ enum SubCommand {
Delete(Delete), Delete(Delete),
#[clap(version = "0.0.1", author = "utam0k <k0ma@utam0k.jp>")] #[clap(version = "0.0.1", author = "utam0k <k0ma@utam0k.jp>")]
State(StateArgs), State(StateArgs),
#[clap(version = "0.0.1", author = "utam0k <k0ma@utam0k.jp>")]
Info,
} }
/// This is the entry point in the container runtime. The binary is run by a high-level container runtime, /// 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)?); println!("{}", serde_json::to_string_pretty(&container.state)?);
std::process::exit(0); 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(())
}
} }
} }