Skip to content

Commit

Permalink
Merge pull request #286 from Furisto/info-cgv2
Browse files Browse the repository at this point in the history
Extend info cmd with status of cgroup controllers
  • Loading branch information
utam0k authored Sep 13, 2021
2 parents b57382f + e922063 commit 8923a98
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 62 deletions.
14 changes: 9 additions & 5 deletions cgroups/src/v2/controller_type.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::fmt::Display;

#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum ControllerType {
Cpu,
CpuSet,
Io,
Memory,
HugeTlb,
Pids,
Freezer,
}

impl Display for ControllerType {
Expand All @@ -19,7 +19,6 @@ impl Display for ControllerType {
Self::Memory => "memory",
Self::HugeTlb => "hugetlb",
Self::Pids => "pids",
Self::Freezer => "freezer",
};

write!(f, "{}", print)
Expand All @@ -33,24 +32,29 @@ pub const CONTROLLER_TYPES: &[ControllerType] = &[
ControllerType::Io,
ControllerType::Memory,
ControllerType::Pids,
ControllerType::Freezer,
];

#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum PseudoControllerType {
Devices,
Freezer,
Unified,
}

impl Display for PseudoControllerType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let print = match self {
Self::Devices => "devices",
Self::Freezer => "freezer",
Self::Unified => "unified",
};

write!(f, "{}", print)
}
}

pub const PSEUDO_CONTROLLER_TYPES: &[PseudoControllerType] =
&[PseudoControllerType::Devices, PseudoControllerType::Unified];
pub const PSEUDO_CONTROLLER_TYPES: &[PseudoControllerType] = &[
PseudoControllerType::Devices,
PseudoControllerType::Freezer,
PseudoControllerType::Unified,
];
41 changes: 5 additions & 36 deletions cgroups/src/v2/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{
path::{Path, PathBuf},
};

use anyhow::{bail, Result};
use anyhow::Result;

use nix::unistd::Pid;

Expand All @@ -23,15 +23,12 @@ use super::{
memory::Memory,
pids::Pids,
unified::Unified,
util::{self, CGROUP_SUBTREE_CONTROL},
};
use crate::{
common::{self, CgroupManager, ControllerOpt, FreezerState, PathBufExt, CGROUP_PROCS},
stats::{Stats, StatsProvider},
};

const CGROUP_CONTROLLERS: &str = "cgroup.controllers";
const CGROUP_SUBTREE_CONTROL: &str = "cgroup.subtree_control";

pub struct Manager {
root_path: PathBuf,
cgroup_path: PathBuf,
Expand All @@ -52,8 +49,7 @@ impl Manager {
}

fn create_unified_cgroup(&self, pid: Pid) -> Result<()> {
let controllers: Vec<String> = self
.get_available_controllers()?
let controllers: Vec<String> = util::get_available_controllers(&self.root_path)?
.iter()
.map(|c| format!("{}{}", "+", c.to_string()))
.collect();
Expand All @@ -80,32 +76,6 @@ impl Manager {
Ok(())
}

fn get_available_controllers(&self) -> Result<Vec<ControllerType>> {
let controllers_path = self.root_path.join(CGROUP_CONTROLLERS);
if !controllers_path.exists() {
bail!(
"cannot get available controllers. {:?} does not exist",
controllers_path
)
}

let mut controllers = Vec::new();
for controller in fs::read_to_string(&controllers_path)?.split_whitespace() {
match controller {
"cpu" => controllers.push(ControllerType::Cpu),
"cpuset" => controllers.push(ControllerType::CpuSet),
"hugetlb" => controllers.push(ControllerType::HugeTlb),
"io" => controllers.push(ControllerType::Io),
"memory" => controllers.push(ControllerType::Memory),
"pids" => controllers.push(ControllerType::Pids),
"freezer" => controllers.push(ControllerType::Freezer),
tpe => log::warn!("Controller {} is not yet implemented.", tpe),
}
}

Ok(controllers)
}

fn write_controllers(path: &Path, controllers: &[String]) -> Result<()> {
for controller in controllers {
common::write_cgroup_file_str(path.join(CGROUP_SUBTREE_CONTROL), controller)?;
Expand All @@ -130,7 +100,6 @@ impl CgroupManager for Manager {
ControllerType::Io => Io::apply(controller_opt, &self.full_path)?,
ControllerType::Memory => Memory::apply(controller_opt, &self.full_path)?,
ControllerType::Pids => Pids::apply(controller_opt, &self.full_path)?,
ControllerType::Freezer => Freezer::apply(controller_opt, &self.full_path)?,
}
}

Expand All @@ -142,8 +111,8 @@ impl CgroupManager for Manager {
Unified::apply(
controller_opt,
&self.cgroup_path,
self.get_available_controllers()?,
)?
util::get_available_controllers(&self.root_path)?,
)?;
}
}

Expand Down
2 changes: 1 addition & 1 deletion cgroups/src/v2/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mod controller;
mod controller_type;
pub mod controller_type;
mod cpu;
mod cpuset;
mod freezer;
Expand Down
1 change: 0 additions & 1 deletion cgroups/src/v2/systemd_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,6 @@ impl CgroupManager for SystemDCGroupManager {
ControllerType::Io => Io::apply(controller_opt, &self.full_path)?,
ControllerType::Memory => Memory::apply(controller_opt, &self.full_path)?,
ControllerType::Pids => Pids::apply(controller_opt, &self.full_path)?,
ControllerType::Freezer => Freezer::apply(controller_opt, &self.full_path)?,
}
}

Expand Down
36 changes: 34 additions & 2 deletions cgroups/src/v2/util.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
use std::path::PathBuf;
use std::path::{Path, PathBuf};

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

use crate::common;

use super::controller_type::ControllerType;

pub const CGROUP_CONTROLLERS: &str = "cgroup.controllers";
pub const CGROUP_SUBTREE_CONTROL: &str = "cgroup.subtree_control";

pub fn get_unified_mount_point() -> Result<PathBuf> {
Process::myself()?
.mountinfo()?
Expand All @@ -11,3 +18,28 @@ pub fn get_unified_mount_point() -> Result<PathBuf> {
.map(|m| m.mount_point)
.ok_or_else(|| anyhow!("could not find mountpoint for unified"))
}

pub fn get_available_controllers(root_path: &Path) -> Result<Vec<ControllerType>> {
let controllers_path = root_path.join(CGROUP_CONTROLLERS);
if !controllers_path.exists() {
bail!(
"cannot get available controllers. {:?} does not exist",
controllers_path
)
}

let mut controllers = Vec::new();
for controller in common::read_cgroup_file(controllers_path)?.split_whitespace() {
match controller {
"cpu" => controllers.push(ControllerType::Cpu),
"cpuset" => controllers.push(ControllerType::CpuSet),
"hugetlb" => controllers.push(ControllerType::HugeTlb),
"io" => controllers.push(ControllerType::Io),
"memory" => controllers.push(ControllerType::Memory),
"pids" => controllers.push(ControllerType::Pids),
tpe => log::warn!("Controller {} is not yet implemented.", tpe),
}
}

Ok(controllers)
}
89 changes: 72 additions & 17 deletions src/commands/info.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! Contains functions related to printing information about system running Youki
use std::{fs, path::Path};
use std::{collections::HashSet, fs, path::Path};

use anyhow::Result;
use clap::Clap;
use procfs::{CpuInfo, Meminfo};

use cgroups;
use cgroups::{self, common::CgroupSetup, v2::controller_type::ControllerType};

#[derive(Clap, Debug)]
pub struct Info {}
Expand Down Expand Up @@ -106,7 +106,8 @@ pub fn print_hardware() {

/// Print cgroups info of system
pub fn print_cgroups() {
if let Ok(cgroup_setup) = cgroups::common::get_cgroup_setup() {
let cgroup_setup = cgroups::common::get_cgroup_setup();
if let Ok(cgroup_setup) = &cgroup_setup {
println!("{:<18}{}", "Cgroup setup", cgroup_setup);
}

Expand All @@ -124,19 +125,49 @@ pub fn print_cgroups() {
}

let unified = cgroups::v2::util::get_unified_mount_point();
if let Ok(mount_point) = unified {
if let Ok(mount_point) = &unified {
println!(" {:<16}{}", "unified", mount_point.display());
}

if let Ok(cgroup_setup) = cgroup_setup {
if let Ok(unified) = &unified {
if matches!(cgroup_setup, CgroupSetup::Hybrid | CgroupSetup::Unified) {
if let Ok(controllers) = cgroups::v2::util::get_available_controllers(unified) {
println!("CGroup v2 controllers");
let active_controllers: HashSet<ControllerType> =
controllers.into_iter().collect();
for controller in cgroups::v2::controller_type::CONTROLLER_TYPES {
let status = if active_controllers.contains(controller) {
"attached"
} else {
"detached"
};

println!(" {:<16}{}", controller.to_string(), status);
}
}

if let Some(config) = read_kernel_config() {
let display = FeatureDisplay::with_status("device", "attached", "detached");
print_feature_status(&config, "CONFIG_CGROUP_BPF", display);
}
}
}
}
}

pub fn print_namespaces() {
fn read_kernel_config() -> Option<String> {
let uname = nix::sys::utsname::uname();
let kernel_config = Path::new("/boot").join(format!("config-{}", uname.release()));
if !kernel_config.exists() {
return;
return None;
}

if let Ok(content) = fs::read_to_string(kernel_config) {
fs::read_to_string(kernel_config).ok()
}

pub fn print_namespaces() {
if let Some(content) = read_kernel_config() {
if let Some(ns_enabled) = find_parameter(&content, "CONFIG_NAMESPACES") {
if ns_enabled == "y" {
println!("{:<18}enabled", "Namespaces");
Expand All @@ -148,24 +179,48 @@ pub fn print_namespaces() {

// mount namespace is always enabled if namespaces are enabled
println!(" {:<16}enabled", "mount");
print_feature_status(&content, "CONFIG_UTS_NS", "uts");
print_feature_status(&content, "CONFIG_IPC_NS", "ipc");
print_feature_status(&content, "CONFIG_USER_NS", "user");
print_feature_status(&content, "CONFIG_PID_NS", "pid");
print_feature_status(&content, "CONFIG_NET_NS", "network");
print_feature_status(&content, "CONFIG_UTS_NS", FeatureDisplay::new("uts"));
print_feature_status(&content, "CONFIG_IPC_NS", FeatureDisplay::new("ipc"));
print_feature_status(&content, "CONFIG_USER_NS", FeatureDisplay::new("user"));
print_feature_status(&content, "CONFIG_PID_NS", FeatureDisplay::new("pid"));
print_feature_status(&content, "CONFIG_NET_NS", FeatureDisplay::new("network"));
}
}

fn print_feature_status(config: &str, feature: &str, display: &str) {
fn print_feature_status(config: &str, feature: &str, display: FeatureDisplay) {
if let Some(status_flag) = find_parameter(config, feature) {
let status = if status_flag == "y" {
"enabled"
display.enabled
} else {
"disabled"
display.disabled
};

println!(" {:<16}{}", display, status);
println!(" {:<16}{}", display.name, status);
} else {
println!(" {:<16}disabled", display);
println!(" {:<16}{}", display.name, display.disabled);
}
}

struct FeatureDisplay<'a> {
name: &'a str,
enabled: &'a str,
disabled: &'a str,
}

impl<'a> FeatureDisplay<'a> {
fn new(name: &'a str) -> Self {
Self {
name,
enabled: "enabled",
disabled: "disabled",
}
}

fn with_status(name: &'a str, enabled: &'a str, disabled: &'a str) -> Self {
Self {
name,
enabled,
disabled,
}
}
}

0 comments on commit 8923a98

Please sign in to comment.