Skip to content

Commit

Permalink
Merge pull request #26 from navidys/develop
Browse files Browse the repository at this point in the history
added /proc/<pid>/ns
  • Loading branch information
navidys authored Aug 18, 2024
2 parents f24dba0 + c9d8502 commit cfaaee5
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 0 deletions.
1 change: 1 addition & 0 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Supported Features
* io
* limits
* root
* ns

*`/proc/buddyinfo`

Expand Down
14 changes: 14 additions & 0 deletions examples/process_ns.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use procsys::process;

fn main() {
let sys_proc = process::collect(2).expect("system proc 2");
let sys_proc_ns = sys_proc.namespaces().expect("system proc 2 namespaces");

match serde_json::to_string_pretty(&sys_proc_ns) {
Ok(output) => println!("{}", output),
Err(err) => {
log::error!("{}", err);
std::process::exit(1);
}
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod process;
pub mod process_cgroup;
pub mod process_io;
pub mod process_limits;
pub mod process_ns;
pub mod swaps;
pub mod sysfs;
pub mod utils;
102 changes: 102 additions & 0 deletions src/process_ns.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use std::{collections::HashMap, fs::read_link};

use serde::Serialize;

use crate::{
error::{CollectResult, MetricError},
process::Process,
utils,
};

/// ProcessNamespace represents a single namespace of a process
#[derive(Debug, Serialize, Clone, Default)]
pub struct ProcessNamespace {
pub ns_type: String,
pub inode: u32,
}

impl ProcessNamespace {
pub fn new() -> Self {
Default::default()
}
}

impl Process {
/// Namespaces reads from /proc/\<pid\>/ns/* to get the namespaces of which the process is a member
pub fn namespaces(&self) -> CollectResult<HashMap<String, ProcessNamespace>> {
let mut proc_namespaces: HashMap<String, ProcessNamespace> = HashMap::new();

let mut proc_ns_path = self.path();
proc_ns_path.push("ns");

for ns_item in utils::list_dir_content(&proc_ns_path, "", "ns") {
let mut ns_item_path = proc_ns_path.clone();
ns_item_path.push(&ns_item);

match read_link(&ns_item_path) {
Ok(c) => {
let item_fields: Vec<&str> = c
.to_str()
.unwrap_or_default()
.trim()
.split(':')
.filter(|s| !s.is_empty())
.collect();

if item_fields.len() != 2 {
return Err(MetricError::InvalidFieldNumberError(
"process ns item".to_string(),
item_fields.len(),
c.to_str().unwrap_or_default().to_string(),
));
}

let mut proc_ns = ProcessNamespace::new();
let proc_ns_inode = item_fields[1].trim().trim_matches('[').trim_matches(']');

proc_ns.ns_type = item_fields[0].trim().to_string();
proc_ns.inode = proc_ns_inode.parse::<u32>().unwrap_or_default();

proc_namespaces.insert(ns_item, proc_ns);
}
Err(e) => return Err(MetricError::IOError(ns_item_path, e)),
}
}

Ok(proc_namespaces)
}
}

#[cfg(test)]
mod tests {
use std::path::Path;

use crate::process::*;

#[test]
fn proc_ns() {
let proc_path = Path::new("test_data/fixtures/proc");
let sys_proc = collect_from(proc_path, 26231).expect("running proc 26231");
let sys_proc_ns = sys_proc
.namespaces()
.expect("running proc 26231 namespaces");

assert_eq!(sys_proc_ns.len(), 2);
assert_eq!(sys_proc_ns.contains_key("mnt"), true);
assert_eq!(sys_proc_ns.contains_key("net"), true);

for (key, proc_ns) in &sys_proc_ns {
match key.as_str() {
"mnt" => {
assert_eq!(proc_ns.ns_type, "mnt");
assert_eq!(proc_ns.inode, 4026531840);
}
"net" => {
assert_eq!(proc_ns.ns_type, "net");
assert_eq!(proc_ns.inode, 4026531993);
}
_ => panic!("invalid namespace key: {}", key),
}
}
}
}

0 comments on commit cfaaee5

Please sign in to comment.