Skip to content

Commit

Permalink
factor out metrics
Browse files Browse the repository at this point in the history
Signed-off-by: James Sturtevant <[email protected]>
Signed-off-by: James Sturtevant <[email protected]>
  • Loading branch information
jsturtevant committed Aug 18, 2023
1 parent 801977f commit 5c51fd0
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 119 deletions.
114 changes: 114 additions & 0 deletions crates/containerd-shim-wasm/src/sandbox/metrics_unix.rs
Original file line number Diff line number Diff line change
@@ -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<Any> {
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::<Vec<&str>>();
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::<u64>().unwrap());
}
"user_usec" => {
cpu_usage.set_user(parts[1].parse::<u64>().unwrap());
}
"system_usec" => {
cpu_usage.set_kernel(parts[1].parse::<u64>().unwrap());
}
"nr_periods" => {
throttle.set_periods(parts[1].parse::<u64>().unwrap());
}
"nr_throttled" => {
throttle.set_throttled_periods(parts[1].parse::<u64>().unwrap());
}
"throttled_usec" => {
throttle.set_throttled_time(parts[1].parse::<u64>().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)
}
14 changes: 14 additions & 0 deletions crates/containerd-shim-wasm/src/sandbox/metrics_windows.rs
Original file line number Diff line number Diff line change
@@ -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<Any> {
// 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)
}
4 changes: 4 additions & 0 deletions crates/containerd-shim-wasm/src/sandbox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
126 changes: 7 additions & 119 deletions crates/containerd-shim-wasm/src/sandbox/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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;

Expand Down Expand Up @@ -1221,119 +1215,13 @@ impl<T: Instance + Send + Sync> Local<T> {
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::<Vec<&str>>();
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::<u64>().unwrap());
}
"user_usec" => {
cpu_usage.set_user(parts[1].parse::<u64>().unwrap());
}
"system_usec" => {
cpu_usage.set_kernel(parts[1].parse::<u64>().unwrap());
}
"nr_periods" => {
throttle.set_periods(parts[1].parse::<u64>().unwrap());
}
"nr_throttled" => {
throttle
.set_throttled_periods(parts[1].parse::<u64>().unwrap());
}
"throttled_usec" => {
throttle.set_throttled_time(parts[1].parse::<u64>().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)
}
}

Expand Down

0 comments on commit 5c51fd0

Please sign in to comment.