Skip to content

Commit

Permalink
Merge pull request #172 from zidoshare/implementation-of-ps-commmand
Browse files Browse the repository at this point in the history
Implementation of ps commmand
  • Loading branch information
Furisto authored Jul 31, 2021
2 parents 62a1121 + 1398da8 commit ae7089b
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 3 deletions.
40 changes: 38 additions & 2 deletions src/cgroups/common.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::{
env,
fmt::{Debug, Display},
fs,
io::Write,
fs::{self, File},
io::{BufRead, BufReader, Write},
path::{Path, PathBuf},
};

Expand Down Expand Up @@ -36,6 +36,8 @@ pub trait CgroupManager {
fn freeze(&self, state: FreezerState) -> Result<()>;
/// Retrieve statistics for the cgroup
fn stats(&self) -> Result<Stats>;
// Gets the PIDs inside the cgroup
fn get_all_pids(&self) -> Result<Vec<Pid>>;
}

#[derive(Debug)]
Expand Down Expand Up @@ -177,3 +179,37 @@ pub fn create_cgroup_manager<P: Into<PathBuf>>(
_ => bail!("could not find cgroup filesystem"),
}
}

pub fn get_all_pids(path: &Path) -> Result<Vec<Pid>> {
log::debug!("scan pids in folder: {:?}", path);
let mut result = vec![];
walk_dir(&path, &mut |p| {
let file_path = p.join(CGROUP_PROCS);
if file_path.exists() {
let file = File::open(file_path)?;
for line in BufReader::new(file).lines() {
if let Ok(line) = line {
result.push(Pid::from_raw(line.parse::<i32>()?))
}
}
}
Ok(())
})?;
Ok(result)
}

fn walk_dir<F>(path: &Path, c: &mut F) -> Result<()>
where
F: FnMut(&Path) -> Result<()>,
{
c(&path)?;
for entry in fs::read_dir(path)? {
let entry = entry?;
let path = entry.path();

if path.is_dir() {
walk_dir(&path, c)?;
}
}
Ok(())
}
10 changes: 9 additions & 1 deletion src/cgroups/v1/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use super::{
perf_event::PerfEvent, pids::Pids, util, Controller,
};

use crate::cgroups::common::CGROUP_PROCS;
use crate::cgroups::common::{self, CGROUP_PROCS};
use crate::cgroups::stats::{Stats, StatsProvider};
use crate::utils;
use crate::{cgroups::common::CgroupManager, utils::PathBufExt};
Expand Down Expand Up @@ -101,6 +101,14 @@ impl Manager {
}

impl CgroupManager for Manager {
fn get_all_pids(&self) -> Result<Vec<Pid>> {
let devices = self.subsystems.get(&CtrlType::Devices);
if let Some(p) = devices {
common::get_all_pids(p)
} else {
bail!("subsystem does not exist")
}
}
fn add_task(&self, pid: Pid) -> Result<()> {
for subsys in &self.subsystems {
match subsys.0 {
Expand Down
4 changes: 4 additions & 0 deletions src/cgroups/v2/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,8 @@ impl CgroupManager for Manager {
fn stats(&self) -> Result<Stats> {
Ok(Stats::default())
}

fn get_all_pids(&self) -> Result<Vec<Pid>> {
common::get_all_pids(&self.full_path)
}
}
4 changes: 4 additions & 0 deletions src/cgroups/v2/systemd_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ impl CgroupManager for SystemDCGroupManager {
fn stats(&self) -> Result<Stats> {
Ok(Stats::default())
}

fn get_all_pids(&self) -> Result<Vec<Pid>> {
common::get_all_pids(&self.full_path)
}
}

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod info;
pub mod kill;
pub mod list;
pub mod pause;
pub mod ps;
pub mod resume;
pub mod run;
pub mod spec_json;
Expand Down
86 changes: 86 additions & 0 deletions src/commands/ps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use crate::{cgroups, container::Container, utils};
use anyhow::{bail, Context, Result};
use clap::{self, Clap};
use std::{path::PathBuf, process::Command};

/// display the processes inside a container
#[derive(Clap, Debug)]
pub struct Ps {
/// format to display processes: table or json (default: "table")
#[clap(short, long, default_value = "table")]
format: String,
pub container_id: String,
/// options will be passed to the ps utility
#[clap(setting = clap::ArgSettings::Last)]
ps_options: Vec<String>,
}
impl Ps {
pub fn exec(&self, root_path: PathBuf) -> Result<()> {
let container_root = root_path.join(&self.container_id);
if !container_root.exists() {
bail!("{} doesn't exist.", self.container_id)
}
let container = Container::load(container_root)?.refresh_status()?;
if container.root.exists() {
let config_absolute_path = container.root.join("config.json");
log::debug!("load spec from {:?}", config_absolute_path);
let spec = oci_spec::Spec::load(config_absolute_path)?;
log::debug!("spec: {:?}", spec);
let cgroups_path = utils::get_cgroup_path(
&spec.linux.context("no linux in spec")?.cgroups_path,
container.id(),
);
let systemd_cgroup = container
.systemd()
.context("could not determine cgroup manager")?;
let cmanager = cgroups::common::create_cgroup_manager(cgroups_path, systemd_cgroup)?;
let pids: Vec<i32> = cmanager
.get_all_pids()?
.iter()
.map(|pid| pid.as_raw())
.collect();

if self.format == "json" {
println!("{}", serde_json::to_string(&pids)?);
} else if self.format == "table" {
let default_ps_options = vec![String::from("-ef")];
let ps_options = if self.ps_options.is_empty() {
&default_ps_options
} else {
&self.ps_options
};
let output = Command::new("ps").args(ps_options).output()?;
if !output.status.success() {
println!("{}", std::str::from_utf8(&output.stderr)?);
} else {
let lines = std::str::from_utf8(&output.stdout)?;
let lines: Vec<&str> = lines.split("\n").collect();
let pid_index = get_pid_index(lines[0])?;
println!("{}", &lines[0]);
for line in &lines[1..] {
if line.is_empty() {
continue;
}
let fields: Vec<&str> = line.split_whitespace().collect();
let pid: i32 = fields[pid_index].parse()?;
if pids.contains(&pid) {
println!("{}", line);
}
}
}
}
}
Ok(())
}
}

fn get_pid_index(title: &str) -> Result<usize> {
let titles = title.split_whitespace();

for (index, name) in titles.enumerate() {
if name == "PID" {
return Ok(index);
}
}
bail!("could't find PID field in ps output");
}
4 changes: 4 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use youki::commands::info;
use youki::commands::kill;
use youki::commands::list;
use youki::commands::pause;
use youki::commands::ps;
use youki::commands::resume;
use youki::commands::run;
use youki::commands::spec_json;
Expand Down Expand Up @@ -74,6 +75,8 @@ enum SubCommand {
Resume(resume::Resume),
#[clap(version = "0.0.1", author = "utam0k <k0ma@utam0k.jp>")]
Events(events::Events),
#[clap(version = "0.0.1", author = "utam0k <k0ma@utam0k.jp>", setting=clap::AppSettings::AllowLeadingHyphen)]
Ps(ps::Ps),
}

/// This is the entry point in the container runtime. The binary is run by a high-level container runtime,
Expand Down Expand Up @@ -108,5 +111,6 @@ fn main() -> Result<()> {
SubCommand::Pause(pause) => pause.exec(root_path, systemd_cgroup),
SubCommand::Resume(resume) => resume.exec(root_path, systemd_cgroup),
SubCommand::Events(events) => events.exec(root_path),
SubCommand::Ps(ps) => ps.exec(root_path),
}
}

0 comments on commit ae7089b

Please sign in to comment.