diff --git a/src/gatherers/ip.rs b/src/gatherers/ip.rs index 7d24395..2a2438a 100644 --- a/src/gatherers/ip.rs +++ b/src/gatherers/ip.rs @@ -1,6 +1,4 @@ -use std::process::Command; - -use crate::types::fact::{Fact, FactData}; +use crate::{types::fact::{Fact, FactData}, util::command::get_result_as_string}; use serde::{Deserialize, Serialize}; pub struct IPData {} @@ -41,13 +39,7 @@ impl Fact for IPData { fn gather(&self) -> Vec { let mut vfd: Vec = vec![]; let time_set = self.get_epoch_ms(); - let output = Command::new("ip") - .arg("-j") - .arg("addr") - .output() - .expect("Failed to execute ip"); - let stdout = String::from_utf8(output.stdout).unwrap(); - let ips: Vec = serde_json::from_str(stdout.as_str()).unwrap(); + let ips: Vec = serde_json::from_str(get_result_as_string("ip", vec!["-j", "addr"]).as_str()).unwrap(); for ip in ips { if ip.ifname != "lo" { for addr_info in ip.addr_info { @@ -89,3 +81,27 @@ impl Fact for IPData { return vfd; } } + +#[derive(Serialize, Deserialize)] +struct IpRoute { + dst: String, + gateway: Option, + dev: String, + protocol: Option, + metric: Option, + flags: Vec, + scope: String, + prefsrc: String, + +} + +impl Fact for IpRoute { + fn gather(&self) -> Vec { + let mut vfd: Vec = vec![]; + let time_set = self.get_epoch_ms(); + + let routes: Vec = serde_json::from_str(get_result_as_string("ip", vec!["-j", "route"]).as_str()).unwrap(); + + return vfd; + } +} \ No newline at end of file diff --git a/src/gatherers/system.rs b/src/gatherers/system.rs new file mode 100644 index 0000000..c91c9a6 --- /dev/null +++ b/src/gatherers/system.rs @@ -0,0 +1,105 @@ +use std::process::Command; + +use crate::types::fact::{Fact, FactData}; +use serde::{Deserialize, Serialize}; + +pub struct SystemData {} + +impl SystemData {} + + + +#[derive(Serialize, Deserialize)] +struct UnameData{ + kernel_name: String, + node_name: String, + kernel_release: String, + kernel_version: String, + machine: String, + processor: String, + hardware_platform: String, + operating_system: String, +} + +#[derive(Serialize, Deserialize)] +struct IpAddrInfo { + family: String, + local: String, + prefixlen: i32, + broadcast: Option, + scope: String, + dynamic: Option, + noprefixroute: Option, + label: Option, + valid_life_time: i64, + preferred_life_time: i64, +} + +#[derive(Serialize, Deserialize)] +struct IpAddr { + ifindex: i32, + ifname: String, + flags: Vec, + mtu: i32, + qdisc: String, + operstate: String, + group: String, + txqlen: i32, + link_type: String, + address: Option, + broadcast: Option, + addr_info: Vec, +} + +impl Fact for SystemData { + fn gather(&self) -> Vec { + let mut vfd: Vec = vec![]; + let time_set = self.get_epoch_ms(); + let output = Command::new("ip") + .arg("-j") + .arg("addr") + .output() + .expect("Failed to execute ip"); + let stdout = String::from_utf8(output.stdout).unwrap(); + let ips: Vec = serde_json::from_str(stdout.as_str()).unwrap(); + for ip in ips { + if ip.ifname != "lo" { + for addr_info in ip.addr_info { + let fd = FactData { + name: format!("ip_addr_{}_{}_addr", ip.ifname, addr_info.family), + value: addr_info.local, + time_set: time_set, + }; + vfd.push(fd); + vfd.push(FactData { + name: format!("ip_addr_{}_{}_prefixlen", ip.ifname, addr_info.family), + value: addr_info.prefixlen.to_string(), + time_set: time_set, + }); + if addr_info.label.is_some() { + vfd.push(FactData { + name: format!("ip_addr_{}_{}_label", ip.ifname, addr_info.family), + value: addr_info.label.unwrap(), + time_set: time_set, + }); + } + if addr_info.broadcast.is_some() { + vfd.push(FactData { + name: format!("ip_addr_{}_{}_broadcast", ip.ifname, addr_info.family), + value: addr_info.broadcast.unwrap(), + time_set: time_set, + }); + } + if ip.address.is_some() { + vfd.push(FactData { + name: format!("ip_addr_{}_macaddr", ip.ifname), + value: ip.address.clone().unwrap(), + time_set: time_set, + }) + } + } + } + } + return vfd; + } +} diff --git a/src/main.rs b/src/main.rs index bee2a91..f6eba3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod types; mod gatherers; +mod util; use std::collections::HashSet; use crate::types::fact::{Fact, FactData}; diff --git a/src/util/command.rs b/src/util/command.rs new file mode 100644 index 0000000..6b5fc88 --- /dev/null +++ b/src/util/command.rs @@ -0,0 +1,42 @@ +use std::process::{Command, Output}; + +fn get_output_from_command(cmd: &str, args: Vec<&str>) -> Output { + return Command::new(&cmd) + .args(args) + .output() + .expect(format!("Failed to execute command: {}", &cmd).as_str()); +} + +fn get_stdout_as_string(output: Output) -> String { + return match String::from_utf8(output.stdout) { + Ok(x) => x.strip_suffix("\n").unwrap().to_string(), + Err(e) => e.to_string() + } +} + +fn get_stderr_as_string(output: Output) -> String { + return match String::from_utf8(output.stderr) { + Ok(x) => x.strip_suffix("\n").unwrap().to_string(), + Err(e) => e.to_string() + } +} + +pub fn get_result_as_string(cmd: &str, args:Vec<&str>) -> String { + let output = get_output_from_command(cmd, args); + match output.status.code() { + Some(0) => get_stdout_as_string(output), + _ => get_stderr_as_string(output) + } +} + +#[cfg(test)] +mod tests { + use crate::util::command::{get_result_as_string}; + + #[test] + fn test_get_output_from_command() { + assert_eq!("Linux", get_result_as_string("uname", vec![])); + assert_eq!("ls: cannot access '/dev/mouse': No such file or directory", + get_result_as_string("ls", vec!["/dev/mouse",])) + } +} diff --git a/src/util/mod.rs b/src/util/mod.rs new file mode 100644 index 0000000..ab8b7ed --- /dev/null +++ b/src/util/mod.rs @@ -0,0 +1 @@ +pub mod command; \ No newline at end of file