mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-06-27 15:57:09 +00:00
runk: add ps sub-command
ps command supprot two formats, `json` and `table`. `json` format just outputs pids in the container. `table` format will use `ps` utilty in the host, search and output all processes in the container. Add a struct `container` to represent a spawned container. Move the `kill` implemention from kill.rs as a method of `container`. Fixes: #4361 Signed-off-by: Chen Yiyang <cyyzero@qq.com>
This commit is contained in:
parent
7503bdab6e
commit
230a229052
@ -503,11 +503,7 @@ mod tests {
|
|||||||
let root = tempdir().unwrap();
|
let root = tempdir().unwrap();
|
||||||
// let bundle = temp
|
// let bundle = temp
|
||||||
let id = "test".to_string();
|
let id = "test".to_string();
|
||||||
create_activated_dirs(
|
create_activated_dirs(root.path(), &id, bundle_dir.path());
|
||||||
&root.path().to_path_buf(),
|
|
||||||
&id,
|
|
||||||
&bundle_dir.path().to_path_buf(),
|
|
||||||
);
|
|
||||||
let pid = getpid().as_raw();
|
let pid = getpid().as_raw();
|
||||||
|
|
||||||
let mut spec = create_dummy_spec();
|
let mut spec = create_dummy_spec();
|
||||||
@ -517,7 +513,7 @@ mod tests {
|
|||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let status = create_dummy_status(&id, pid, &root.path().to_path_buf(), &spec);
|
let status = create_dummy_status(&id, pid, root.path(), &spec);
|
||||||
status.save().unwrap();
|
status.save().unwrap();
|
||||||
|
|
||||||
let result = ActivatedContainerBuilder::default()
|
let result = ActivatedContainerBuilder::default()
|
||||||
@ -600,13 +596,9 @@ mod tests {
|
|||||||
.join(TEST_ROOTFS_PATH)
|
.join(TEST_ROOTFS_PATH)
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.to_string();
|
.to_string();
|
||||||
create_activated_dirs(
|
create_activated_dirs(root.path(), &id, bundle_dir.path());
|
||||||
&root.path().to_path_buf(),
|
|
||||||
&id,
|
|
||||||
&bundle_dir.path().to_path_buf(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let status = create_dummy_status(&id, pid, &root.path().to_path_buf(), &spec);
|
let status = create_dummy_status(&id, pid, root.path(), &spec);
|
||||||
status.save().unwrap();
|
status.save().unwrap();
|
||||||
let launcher = ActivatedContainerBuilder::default()
|
let launcher = ActivatedContainerBuilder::default()
|
||||||
.id(id)
|
.id(id)
|
||||||
|
@ -3,9 +3,14 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
use crate::status::Status;
|
use crate::status::{self, get_all_pid, get_current_container_state, Status};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use nix::unistd::{chdir, unlink};
|
use nix::sys::signal::kill;
|
||||||
|
use nix::{
|
||||||
|
sys::signal::Signal,
|
||||||
|
unistd::{chdir, unlink, Pid},
|
||||||
|
};
|
||||||
|
use oci::ContainerState;
|
||||||
use rustjail::{
|
use rustjail::{
|
||||||
container::{BaseContainer, LinuxContainer, EXEC_FIFO_FILENAME},
|
container::{BaseContainer, LinuxContainer, EXEC_FIFO_FILENAME},
|
||||||
process::{Process, ProcessOperations},
|
process::{Process, ProcessOperations},
|
||||||
@ -26,6 +31,47 @@ pub enum ContainerAction {
|
|||||||
Run,
|
Run,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Container {
|
||||||
|
pub status: Status,
|
||||||
|
pub state: ContainerState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Container {
|
||||||
|
pub fn load(state_root: &Path, id: &str) -> Result<Self> {
|
||||||
|
let status = Status::load(state_root, id)?;
|
||||||
|
let state = get_current_container_state(&status)?;
|
||||||
|
Ok(Self { status, state })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn processes(&self) -> Result<Vec<Pid>> {
|
||||||
|
get_all_pid(&self.status.cgroup_manager)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kill(&self, signal: Signal, all: bool) -> Result<()> {
|
||||||
|
if all {
|
||||||
|
let pids = self.processes()?;
|
||||||
|
for pid in pids {
|
||||||
|
if !status::is_process_running(pid)? {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
kill(pid, signal)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if self.state == ContainerState::Stopped {
|
||||||
|
return Err(anyhow!("container {} not running", self.status.id));
|
||||||
|
}
|
||||||
|
let pid = Pid::from_raw(self.status.pid);
|
||||||
|
if status::is_process_running(pid)? {
|
||||||
|
kill(pid, signal)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add pause and resume
|
||||||
|
}
|
||||||
|
|
||||||
/// Used to run a process. If init is set, it will create a container and run the process in it.
|
/// Used to run a process. If init is set, it will create a container and run the process in it.
|
||||||
/// If init is not set, it will run the process in an existing container.
|
/// If init is not set, it will run the process in an existing container.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -4,44 +4,22 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
use crate::Kill;
|
use crate::Kill;
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::Result;
|
||||||
use libcontainer::status::{self, get_current_container_state, Status};
|
use libcontainer::container::Container;
|
||||||
use nix::{
|
use nix::sys::signal::Signal;
|
||||||
sys::signal::{kill, Signal},
|
|
||||||
unistd::Pid,
|
|
||||||
};
|
|
||||||
use oci::ContainerState;
|
|
||||||
use slog::{info, Logger};
|
use slog::{info, Logger};
|
||||||
use std::{convert::TryFrom, path::Path, str::FromStr};
|
use std::{convert::TryFrom, path::Path, str::FromStr};
|
||||||
|
|
||||||
pub fn run(opts: Kill, state_root: &Path, logger: &Logger) -> Result<()> {
|
pub fn run(opts: Kill, state_root: &Path, logger: &Logger) -> Result<()> {
|
||||||
let container_id = &opts.container_id;
|
let container_id = &opts.container_id;
|
||||||
let status = Status::load(state_root, container_id)?;
|
let container = Container::load(state_root, container_id)?;
|
||||||
let current_state = get_current_container_state(&status)?;
|
|
||||||
let sig = parse_signal(&opts.signal)?;
|
let sig = parse_signal(&opts.signal)?;
|
||||||
|
|
||||||
// TODO: liboci-cli does not support --all option for kill command.
|
// TODO: liboci-cli does not support --all option for kill command.
|
||||||
// After liboci-cli supports the option, we will change the following code.
|
// After liboci-cli supports the option, we will change the following code.
|
||||||
// as a workaround we use a custom Kill command.
|
// as a workaround we use a custom Kill command.
|
||||||
let all = opts.all;
|
let all = opts.all;
|
||||||
if all {
|
container.kill(sig, all)?;
|
||||||
let pids = status::get_all_pid(&status.cgroup_manager)?;
|
|
||||||
for pid in pids {
|
|
||||||
if !status::is_process_running(pid)? {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
kill(pid, sig)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if current_state == ContainerState::Stopped {
|
|
||||||
return Err(anyhow!("container {} not running", container_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
let p = Pid::from_raw(status.pid);
|
|
||||||
if status::is_process_running(p)? {
|
|
||||||
kill(p, sig)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
info!(&logger, "kill command finished successfully");
|
info!(&logger, "kill command finished successfully");
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ pub mod delete;
|
|||||||
pub mod exec;
|
pub mod exec;
|
||||||
pub mod kill;
|
pub mod kill;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
|
pub mod ps;
|
||||||
pub mod run;
|
pub mod run;
|
||||||
pub mod spec;
|
pub mod spec;
|
||||||
pub mod start;
|
pub mod start;
|
||||||
|
63
src/tools/runk/src/commands/ps.rs
Normal file
63
src/tools/runk/src/commands/ps.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// Copyright 2021-2022 Kata Contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use anyhow::Result;
|
||||||
|
use libcontainer::container::Container;
|
||||||
|
use liboci_cli::Ps;
|
||||||
|
use slog::{info, Logger};
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
pub fn run(opts: Ps, root: &Path, logger: &Logger) -> Result<()> {
|
||||||
|
let container = Container::load(root, opts.container_id.as_str())?;
|
||||||
|
let pids = container
|
||||||
|
.processes()?
|
||||||
|
.iter()
|
||||||
|
.map(|pid| pid.as_raw())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
match opts.format.as_str() {
|
||||||
|
"json" => println!("{}", serde_json::to_string(&pids)?),
|
||||||
|
"table" => {
|
||||||
|
let ps_options = if opts.ps_options.is_empty() {
|
||||||
|
vec!["-ef".to_string()]
|
||||||
|
} else {
|
||||||
|
opts.ps_options
|
||||||
|
};
|
||||||
|
let output = Command::new("ps").args(ps_options).output()?;
|
||||||
|
if !output.status.success() {
|
||||||
|
return Err(anyhow!("{}", std::str::from_utf8(&output.stderr)?));
|
||||||
|
}
|
||||||
|
let lines = str::from_utf8(&output.stdout)?.lines().collect::<Vec<_>>();
|
||||||
|
if lines.is_empty() {
|
||||||
|
return Err(anyhow!("no processes found"));
|
||||||
|
}
|
||||||
|
let pid_index = lines[0]
|
||||||
|
.split_whitespace()
|
||||||
|
.position(|field| field == "PID")
|
||||||
|
.ok_or_else(|| anyhow!("could't find PID field in ps output"))?;
|
||||||
|
println!("{}", lines[0]);
|
||||||
|
for &line in &lines[1..] {
|
||||||
|
if line.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let fields = line.split_whitespace().collect::<Vec<_>>();
|
||||||
|
if pid_index >= fields.len() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let pid: i32 = fields[pid_index].parse()?;
|
||||||
|
if pids.contains(&pid) {
|
||||||
|
println!("{}", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return Err(anyhow!("unknown format: {}", opts.format)),
|
||||||
|
}
|
||||||
|
|
||||||
|
info!(&logger, "ps command finished successfully");
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -80,6 +80,7 @@ async fn cmd_run(subcmd: SubCommand, root_path: &Path, logger: &Logger) -> Resul
|
|||||||
CommonCmd::Spec(spec) => commands::spec::run(spec, logger),
|
CommonCmd::Spec(spec) => commands::spec::run(spec, logger),
|
||||||
CommonCmd::List(list) => commands::list::run(list, root_path, logger),
|
CommonCmd::List(list) => commands::list::run(list, root_path, logger),
|
||||||
CommonCmd::Exec(exec) => commands::exec::run(exec, root_path, logger).await,
|
CommonCmd::Exec(exec) => commands::exec::run(exec, root_path, logger).await,
|
||||||
|
CommonCmd::Ps(ps) => commands::ps::run(ps, root_path, logger),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(anyhow!("command is not implemented yet"));
|
return Err(anyhow!("command is not implemented yet"));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user