From 38a3188206d1949a0934064af81379cef3bd2187 Mon Sep 17 00:00:00 2001 From: Chen Yiyang Date: Thu, 2 Jun 2022 11:22:20 +0800 Subject: [PATCH] runk: Support `list` sub-command Support list sub-command. It will traverse the root directory, parse status file and print basic information of containers. Behavior and print format consistent with runc. To handle race with runk delete or system user modify, the loop will continue to traverse when errors are encountered. Fixes: #4362 Signed-off-by: Chen Yiyang --- src/tools/runk/Cargo.lock | 27 +++++++++++ src/tools/runk/Cargo.toml | 2 + src/tools/runk/src/commands/list.rs | 69 +++++++++++++++++++++++++++++ src/tools/runk/src/commands/mod.rs | 1 + src/tools/runk/src/main.rs | 1 + 5 files changed, 100 insertions(+) create mode 100644 src/tools/runk/src/commands/list.rs diff --git a/src/tools/runk/Cargo.lock b/src/tools/runk/Cargo.lock index f8628cbf7..a1691a796 100644 --- a/src/tools/runk/Cargo.lock +++ b/src/tools/runk/Cargo.lock @@ -985,7 +985,9 @@ dependencies = [ "serde_json", "slog", "slog-async", + "tabwriter", "tokio", + "users", ] [[package]] @@ -1166,6 +1168,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tabwriter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36205cfc997faadcc4b0b87aaef3fbedafe20d38d4959a7ca6ff803564051111" +dependencies = [ + "unicode-width", +] + [[package]] name = "take_mut" version = "0.2.2" @@ -1348,12 +1359,28 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "users" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" +dependencies = [ + "libc", + "log", +] + [[package]] name = "version_check" version = "0.9.4" diff --git a/src/tools/runk/Cargo.toml b/src/tools/runk/Cargo.toml index 83aca82ca..973ae21c7 100644 --- a/src/tools/runk/Cargo.toml +++ b/src/tools/runk/Cargo.toml @@ -22,6 +22,8 @@ slog-async = "2.7.0" tokio = { version = "1.15.0", features = ["full"] } serde = { version = "1.0.133", features = ["derive"] } serde_json = "1.0.74" +users = "0.11.0" +tabwriter = "1.2.1" [workspace] members = [ diff --git a/src/tools/runk/src/commands/list.rs b/src/tools/runk/src/commands/list.rs new file mode 100644 index 000000000..dbd427755 --- /dev/null +++ b/src/tools/runk/src/commands/list.rs @@ -0,0 +1,69 @@ +// Copyright 2021-2022 Kata Contributors +// +// SPDX-License-Identifier: Apache-2.0 +// + +use super::state::get_container_state_name; +use anyhow::Result; +use libcontainer::status::{get_current_container_state, Status}; +use liboci_cli::List; +use oci::ContainerState; +use slog::{info, Logger}; +use std::{fs, os::unix::prelude::MetadataExt, path::Path}; +use std::{io, io::Write}; +use tabwriter::TabWriter; +use users::get_user_by_uid; + +pub fn run(_: List, root: &Path, logger: &Logger) -> Result<()> { + let mut content = String::new(); + for entry in fs::read_dir(root)? { + let entry = entry?; + // Possibly race with runk delete, so continue loop when any error occurs below + let metadata = match entry.metadata() { + Ok(metadata) => metadata, + Err(_) => continue, + }; + if !metadata.is_dir() { + continue; + } + let container_id = match entry.file_name().into_string() { + Ok(id) => id, + Err(_) => continue, + }; + let status = match Status::load(root, &container_id) { + Ok(status) => status, + Err(_) => continue, + }; + let state = match get_current_container_state(&status) { + Ok(state) => state, + Err(_) => continue, + }; + // Just like runc, pid of stopped container is 0 + let pid = match state { + ContainerState::Stopped => 0, + _ => status.pid, + }; + // May replace get_user_by_uid with getpwuid(3) + let owner = match get_user_by_uid(metadata.uid()) { + Some(user) => String::from(user.name().to_string_lossy()), + None => format!("#{}", metadata.uid()), + }; + content.push_str(&format!( + "{}\t{}\t{}\t{}\t{}\t{}\n", + container_id, + pid, + get_container_state_name(state), + status.bundle.display(), + status.created, + owner + )); + } + + let mut tab_writer = TabWriter::new(io::stdout()); + writeln!(&mut tab_writer, "ID\tPID\tSTATUS\tBUNDLE\tCREATED\tOWNER")?; + write!(&mut tab_writer, "{}", content)?; + tab_writer.flush()?; + + info!(&logger, "list command finished successfully"); + Ok(()) +} diff --git a/src/tools/runk/src/commands/mod.rs b/src/tools/runk/src/commands/mod.rs index 12017263d..216686506 100644 --- a/src/tools/runk/src/commands/mod.rs +++ b/src/tools/runk/src/commands/mod.rs @@ -6,6 +6,7 @@ pub mod create; pub mod delete; pub mod kill; +pub mod list; pub mod run; pub mod spec; pub mod start; diff --git a/src/tools/runk/src/main.rs b/src/tools/runk/src/main.rs index 8f464f438..0171a229f 100644 --- a/src/tools/runk/src/main.rs +++ b/src/tools/runk/src/main.rs @@ -78,6 +78,7 @@ async fn cmd_run(subcmd: SubCommand, root_path: &Path, logger: &Logger) -> Resul SubCommand::Common(cmd) => match cmd { CommonCmd::Run(run) => commands::run::run(run, root_path, logger).await, CommonCmd::Spec(spec) => commands::spec::run(spec, logger), + CommonCmd::List(list) => commands::list::run(list, root_path, logger), _ => { return Err(anyhow!("command is not implemented yet")); }