use crate::components::Collector;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use serde_json::{to_value};
use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::process::Command;
#[derive(Debug, Deserialize)]
struct IPDevice {
ifname: String,
mtu: u32,
operstate: String,
link_type: String,
address: String,
addr_info: Vec<IPDeviceAddr>,
}
#[derive(Debug, Deserialize)]
struct IPDeviceAddr {
family: String,
local: String,
broadcast: Option<String>,
prefixlen: u32,
scope: String,
label: Option<String>,
}
#[derive(Debug, Serialize)]
pub enum InterfaceState {
UP,
DOWN,
UNKNOWN,
}
#[derive(Serialize, Debug)]
pub struct InterfaceFields {
pub state: InterfaceState,
pub link_type: String,
pub dhcp: Option<Ipv4Addr>,
pub ip: Option<Ipv4Addr>,
pub ip6: Option<Ipv6Addr>,
pub mac: String,
pub mtu: u32,
pub prefix: Option<u32>,
pub prefix6: Option<u32>,
pub network: Option<Ipv4Addr>,
pub network6: Option<Ipv6Addr>,
pub scope6: String,
}
#[derive(Serialize, Debug)]
pub struct Interface {
pub bindings: Vec<Ipv4Addr>,
pub bindings6: Vec<Ipv6Addr>,
#[serde(flatten)]
pub interface_fields: InterfaceFields,
}
#[derive(Debug, Serialize)]
pub struct NetworkFacts {
pub hostname: String,
pub domain: Option<String>,
pub fqdn: String,
pub interfaces: HashMap<String, Interface>,
pub primary: String,
#[serde(flatten)]
pub interface_fields: InterfaceFields,
}
pub struct NetworkComponent;
impl NetworkComponent {
pub fn new() -> Self {
Self
}
}
impl Collector for NetworkComponent {
fn name(&self) -> &'static str {
"network"
}
fn collect(&self) -> Result<serde_json::Value> {
let hostname = "myhostname";
let domain = "mydomain.org";
let mut interfaces = HashMap::new();
interfaces.insert(
"eth0".to_string(),
Interface {
bindings: vec!["10.0.0.1".parse::<Ipv4Addr>()?],
bindings6: vec!["fe80::c468:27d4:bd86:a4f6".parse::<Ipv6Addr>()?],
interface_fields: InterfaceFields {
state: InterfaceState::UP,
link_type: "inet".to_string(),
mac: "3e:0a:ff:fd:7f:9f".to_string(),
mtu: 1500,
scope6: "scope".to_string(),
dhcp: Some("128.223.32.36".parse::<Ipv4Addr>()?),
prefix: Some(24),
network: Some("10.0.0.0".parse::<Ipv4Addr>()?),
ip: Some("10.0.0.1".parse::<Ipv4Addr>()?),
ip6: Some("fe80::c468:27d4:bd86:a4f6".parse::<Ipv6Addr>()?),
prefix6: Some(64),
network6: Some("fe80::c468:27d4:bd86".parse::<Ipv6Addr>()?),
},
},
);
let facts = NetworkFacts {
hostname: hostname.to_string(),
domain: Some(domain.to_string()),
fqdn: format!("{hostname}.{domain}"),
interfaces: interfaces,
primary: "eth0".to_string(),
interface_fields: InterfaceFields {
state: InterfaceState::UP,
link_type: "inet".to_string(),
mac: "3e:0a:ff:fd:7f:9f".to_string(),
mtu: 1500,
scope6: "scope".to_string(),
dhcp: Some("128.223.32.36".parse::<Ipv4Addr>()?),
prefix: Some(24),
network: Some("10.0.0.0".parse::<Ipv4Addr>()?),
ip: Some("10.0.0.1".parse::<Ipv4Addr>()?),
ip6: Some("fe80::c468:27d4:bd86:a4f6".parse::<Ipv6Addr>()?),
prefix6: Some(64),
network6: Some("fe80::c468:27d4:bd86".parse::<Ipv6Addr>()?),
},
};
let j = to_value(facts).context("serializing to json value")?;
Ok(j)
}
}
pub fn parse_ip_devices_output(output: &str) -> Result<Vec<Interface>> {
unimplemented!();
}
pub fn get_all_ip_devices() -> Result<String> {
let output = Command::new("ip")
.arg("-j")
.arg("addr")
.arg("show")
.output()
.with_context(|| format!("running ip -j addr show"))?
.stdout;
let output = String::from_utf8(output)?;
Ok(output.trim_end().to_string())
}