diff --git a/crates/containerd-shim-wasm/src/sandbox/metrics_unix.rs b/crates/containerd-shim-wasm/src/sandbox/metrics_unix.rs new file mode 100644 index 000000000..27f7701a2 --- /dev/null +++ b/crates/containerd-shim-wasm/src/sandbox/metrics_unix.rs @@ -0,0 +1,114 @@ +use super::Error; +use super::Result; +use cgroups_rs::cgroup::get_cgroups_relative_paths_by_pid; +use cgroups_rs::hierarchies::{self}; +use cgroups_rs::{Cgroup, Subsystem}; +use containerd_shim::{self as shim}; +use protobuf::well_known_types::any::Any; +use shim::protos::cgroups::metrics::{ + CPUStat, CPUUsage, MemoryEntry, MemoryStat, Metrics, PidsStat, Throttle, +}; +use shim::util::convert_to_any; +use std::fs; +use std::path::Path; + +pub fn get_metrics(pid: u32) -> Result { + let mut metrics = Metrics::new(); + let hier = hierarchies::auto(); + + let cgroup = if hier.v2() { + let path = format!("/proc/{}/cgroup", pid); + let content = fs::read_to_string(path)?; + let content = content.strip_suffix('\n').unwrap_or_default(); + + let parts: Vec<&str> = content.split("::").collect(); + let path_parts: Vec<&str> = parts[1].split('/').collect(); + let namespace = path_parts[1]; + let cgroup_name = path_parts[2]; + Cgroup::load( + hierarchies::auto(), + format!("/sys/fs/cgroup/{namespace}/{cgroup_name}"), + ) + } else { + let path = get_cgroups_relative_paths_by_pid(pid).unwrap(); + Cgroup::load_with_relative_paths(hierarchies::auto(), Path::new("."), path) + }; + + // from https://github.com/containerd/rust-extensions/blob/main/crates/shim/src/cgroup.rs#L97-L127 + for sub_system in Cgroup::subsystems(&cgroup) { + match sub_system { + Subsystem::Mem(mem_ctr) => { + let mem = mem_ctr.memory_stat(); + let mut mem_entry = MemoryEntry::new(); + mem_entry.set_usage(mem.usage_in_bytes); + let mut mem_stat = MemoryStat::new(); + mem_stat.set_usage(mem_entry); + mem_stat.set_total_inactive_file(mem.stat.total_inactive_file); + metrics.set_memory(mem_stat); + } + Subsystem::Cpu(cpu_ctr) => { + let mut cpu_usage = CPUUsage::new(); + let mut throttle = Throttle::new(); + let stat = cpu_ctr.cpu().stat; + for line in stat.lines() { + let parts = line.split(' ').collect::>(); + if parts.len() != 2 { + Err(Error::Others(format!("invalid cpu stat line: {}", line)))?; + } + + // https://github.com/opencontainers/runc/blob/dbe8434359ca35af1c1e10df42b1f4391c1e1010/libcontainer/cgroups/fs2/cpu.go#L70 + match parts[0] { + "usage_usec" => { + cpu_usage.set_total(parts[1].parse::().unwrap()); + } + "user_usec" => { + cpu_usage.set_user(parts[1].parse::().unwrap()); + } + "system_usec" => { + cpu_usage.set_kernel(parts[1].parse::().unwrap()); + } + "nr_periods" => { + throttle.set_periods(parts[1].parse::().unwrap()); + } + "nr_throttled" => { + throttle.set_throttled_periods(parts[1].parse::().unwrap()); + } + "throttled_usec" => { + throttle.set_throttled_time(parts[1].parse::().unwrap()); + } + _ => {} + } + } + let mut cpu_stats = CPUStat::new(); + cpu_stats.set_throttling(throttle); + cpu_stats.set_usage(cpu_usage); + metrics.set_cpu(cpu_stats); + } + Subsystem::Pid(pid_ctr) => { + let mut pid_stats = PidsStat::new(); + pid_stats.set_current( + pid_ctr.get_pid_current().map_err(|err| { + Error::Others(format!("failed to get current pid: {}", err)) + })?, + ); + pid_stats.set_limit( + pid_ctr + .get_pid_max() + .map(|val| match val { + // See https://github.com/opencontainers/runc/blob/dbe8434359ca35af1c1e10df42b1f4391c1e1010/libcontainer/cgroups/fs/pids.go#L55 + cgroups_rs::MaxValue::Max => 0, + cgroups_rs::MaxValue::Value(val) => val as u64, + }) + .map_err(|err| Error::Others(format!("failed to get max pid: {}", err)))?, + ); + metrics.set_pids(pid_stats); + } + _ => { + // TODO: add other subsystems + } + } + } + + let metrics = convert_to_any(Box::new(metrics)).map_err(|e| Error::Others(e.to_string()))?; + Ok(metrics) +} diff --git a/crates/containerd-shim-wasm/src/sandbox/metrics_windows.rs b/crates/containerd-shim-wasm/src/sandbox/metrics_windows.rs new file mode 100644 index 000000000..82ae02b38 --- /dev/null +++ b/crates/containerd-shim-wasm/src/sandbox/metrics_windows.rs @@ -0,0 +1,14 @@ +use super::Error; +use super::Result; +use containerd_shim::{self as shim}; +use protobuf::well_known_types::any::Any; +use shim::util::convert_to_any; + +pub fn get_metrics(pid: u32) -> Result { + // Create empty message for now + // https://github.com/containerd/rust-extensions/pull/178 + let m = protobuf::well_known_types::any::Any::new(); + + let metrics = convert_to_any(Box::new(m)).map_err(|e| Error::Others(e.to_string()))?; + Ok(metrics) +} diff --git a/crates/containerd-shim-wasm/src/sandbox/mod.rs b/crates/containerd-shim-wasm/src/sandbox/mod.rs index c5b79537c..15885b977 100644 --- a/crates/containerd-shim-wasm/src/sandbox/mod.rs +++ b/crates/containerd-shim-wasm/src/sandbox/mod.rs @@ -8,6 +8,10 @@ pub mod instance_utils; pub mod manager; pub mod shim; +#[cfg_attr(target_family = "unix", path = "metrics_unix.rs")] +#[cfg_attr(windows, path = "metrics_windows.rs")] +mod metrics; + pub use error::{Error, Result}; pub use instance::{Instance, InstanceConfig}; pub use manager::{Sandbox as SandboxService, Service as ManagerService}; diff --git a/crates/containerd-shim-wasm/src/sandbox/shim.rs b/crates/containerd-shim-wasm/src/sandbox/shim.rs index f93677037..8da430020 100644 --- a/crates/containerd-shim-wasm/src/sandbox/shim.rs +++ b/crates/containerd-shim-wasm/src/sandbox/shim.rs @@ -15,6 +15,7 @@ use std::thread; use super::instance::{Instance, InstanceConfig, Nop, Wait}; use super::{oci, Error, SandboxService}; +use crate::sandbox::metrics::get_metrics; use chrono::{DateTime, Utc}; use containerd_shim::{ @@ -40,20 +41,13 @@ use crate::cfg_unix; use std::fs::DirBuilder; cfg_unix! { - use cgroups_rs::cgroup::get_cgroups_relative_paths_by_pid; - use cgroups_rs::hierarchies::{self}; - use cgroups_rs::{Cgroup, Subsystem}; use containerd_shim::mount::mount_rootfs; use nix::mount::{mount, MsFlags}; use nix::sched::{setns, unshare, CloneFlags}; use std::os::unix::fs::DirBuilderExt; use std::os::unix::io::AsRawFd; - use shim::protos::cgroups::metrics::{ - CPUStat, CPUUsage, MemoryEntry, MemoryStat, Metrics, PidsStat, Throttle, - }; } -use shim::util::convert_to_any; use shim::Flags; use ttrpc::context::Context; @@ -1221,119 +1215,13 @@ impl Local { return Err(Error::InvalidArgument("task is not running".to_string())); } - #[cfg(unix)] - { - let mut metrics = Metrics::new(); - let hier = hierarchies::auto(); - - let cgroup = if hier.v2() { - let path = format!("/proc/{}/cgroup", pid.unwrap()); - let content = fs::read_to_string(path)?; - let content = content.strip_suffix('\n').unwrap_or_default(); - - let parts: Vec<&str> = content.split("::").collect(); - let path_parts: Vec<&str> = parts[1].split('/').collect(); - let namespace = path_parts[1]; - let cgroup_name = path_parts[2]; - Cgroup::load( - hierarchies::auto(), - format!("/sys/fs/cgroup/{namespace}/{cgroup_name}"), - ) - } else { - let path = get_cgroups_relative_paths_by_pid(pid.unwrap()).unwrap(); - Cgroup::load_with_relative_paths(hierarchies::auto(), Path::new("."), path) - }; + let metrics = get_metrics(pid.unwrap())?; - // from https://github.com/containerd/rust-extensions/blob/main/crates/shim/src/cgroup.rs#L97-L127 - for sub_system in Cgroup::subsystems(&cgroup) { - match sub_system { - Subsystem::Mem(mem_ctr) => { - let mem = mem_ctr.memory_stat(); - let mut mem_entry = MemoryEntry::new(); - mem_entry.set_usage(mem.usage_in_bytes); - let mut mem_stat = MemoryStat::new(); - mem_stat.set_usage(mem_entry); - mem_stat.set_total_inactive_file(mem.stat.total_inactive_file); - metrics.set_memory(mem_stat); - } - Subsystem::Cpu(cpu_ctr) => { - let mut cpu_usage = CPUUsage::new(); - let mut throttle = Throttle::new(); - let stat = cpu_ctr.cpu().stat; - for line in stat.lines() { - let parts = line.split(' ').collect::>(); - if parts.len() != 2 { - Err(Error::Others(format!("invalid cpu stat line: {}", line)))?; - } - - // https://github.com/opencontainers/runc/blob/dbe8434359ca35af1c1e10df42b1f4391c1e1010/libcontainer/cgroups/fs2/cpu.go#L70 - match parts[0] { - "usage_usec" => { - cpu_usage.set_total(parts[1].parse::().unwrap()); - } - "user_usec" => { - cpu_usage.set_user(parts[1].parse::().unwrap()); - } - "system_usec" => { - cpu_usage.set_kernel(parts[1].parse::().unwrap()); - } - "nr_periods" => { - throttle.set_periods(parts[1].parse::().unwrap()); - } - "nr_throttled" => { - throttle - .set_throttled_periods(parts[1].parse::().unwrap()); - } - "throttled_usec" => { - throttle.set_throttled_time(parts[1].parse::().unwrap()); - } - _ => {} - } - } - let mut cpu_stats = CPUStat::new(); - cpu_stats.set_throttling(throttle); - cpu_stats.set_usage(cpu_usage); - metrics.set_cpu(cpu_stats); - } - Subsystem::Pid(pid_ctr) => { - let mut pid_stats = PidsStat::new(); - pid_stats.set_current(pid_ctr.get_pid_current().map_err(|err| { - Error::Others(format!("failed to get current pid: {}", err)) - })?); - pid_stats.set_limit( - pid_ctr - .get_pid_max() - .map(|val| match val { - // See https://github.com/opencontainers/runc/blob/dbe8434359ca35af1c1e10df42b1f4391c1e1010/libcontainer/cgroups/fs/pids.go#L55 - cgroups_rs::MaxValue::Max => 0, - cgroups_rs::MaxValue::Value(val) => val as u64, - }) - .map_err(|err| { - Error::Others(format!("failed to get max pid: {}", err)) - })?, - ); - metrics.set_pids(pid_stats) - } - _ => { - // TODO: add other subsystems - } - } - } - - let mut stats = StatsResponse { - ..Default::default() - }; - stats.set_stats(convert_to_any(Box::new(metrics))?); - Ok(stats) - } - - #[cfg(windows)] - { - let mut stats = StatsResponse { - ..Default::default() - }; - Ok(stats) - } + let mut stats = StatsResponse { + ..Default::default() + }; + stats.set_stats(metrics); + Ok(stats) } }