pot-rs 0.5.0

Utility modules and functions useful to interact with the pot framework
Documentation
use crate::error::PotError;
use crate::Result;
use ipnet::IpNet;
use std::convert::TryFrom;
use std::net::IpAddr;
use std::str::FromStr;

use crate::PotSystemConfig;
use std::path::PathBuf;

pub fn get_bridges_list(conf: &PotSystemConfig) -> Result<Vec<BridgeConf>> {
    let path_list = get_bridges_path_list(conf);
    let mut result = Vec::new();
    for f in path_list {
        if let Ok(conf_str) = std::fs::read_to_string(f.as_path()) {
            if let Ok(bridge_conf) = conf_str.parse() {
                result.push(bridge_conf);
            }
        }
    }
    Ok(result)
}

fn get_bridges_path_list(conf: &PotSystemConfig) -> Vec<PathBuf> {
    let mut result = Vec::new();
    let bridges_path = std::path::Path::new(&conf.fs_root).join("bridges");
    walkdir::WalkDir::new(bridges_path)
        .max_depth(1)
        .min_depth(1)
        .into_iter()
        .filter_map(std::result::Result::ok)
        .filter(|x| x.file_type().is_file())
        .for_each(|x| result.push(x.into_path()));
    result
}
#[derive(Debug)]
pub struct BridgeConf {
    pub name: String,
    pub network: IpNet,
    pub gateway: IpAddr,
}

impl FromStr for BridgeConf {
    type Err = crate::error::PotError;
    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        let partial = PartialBridgeConf::from_str(s).unwrap();
        BridgeConf::try_from(partial)
    }
}

impl TryFrom<PartialBridgeConf> for BridgeConf {
    type Error = PotError;

    fn try_from(value: PartialBridgeConf) -> std::result::Result<Self, Self::Error> {
        if !value.is_valid() {
            Err(PotError::BridgeConfError)
        } else {
            let network = value.network.unwrap();
            let gateway = value.gateway.unwrap();
            if !network.contains(&gateway) {
                Err(PotError::BridgeConfError)
            } else {
                Ok(BridgeConf {
                    name: value.name.unwrap(),
                    network: value.network.unwrap(),
                    gateway: value.gateway.unwrap(),
                })
            }
        }
    }
}

#[derive(Default, Debug)]
struct PartialBridgeConf {
    name: Option<String>,
    network: Option<IpNet>,
    gateway: Option<IpAddr>,
}

impl FromStr for PartialBridgeConf {
    type Err = std::convert::Infallible;
    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        use crate::util::get_value;
        let lines: Vec<String> = s
            .to_string()
            .lines()
            .map(|x| x.trim().to_string())
            .filter(|x| !x.starts_with('#'))
            .collect();
        let mut result = PartialBridgeConf::default();
        for linestr in &lines {
            if linestr.starts_with("name=") {
                result.name = get_value(linestr);
            }
            if linestr.starts_with("net=") {
                result.network = get_value(linestr);
            }
            if linestr.starts_with("gateway=") {
                result.gateway = get_value(linestr);
            }
        }
        Ok(result)
    }
}

impl PartialBridgeConf {
    fn is_valid(&self) -> bool {
        self.name.is_some() && self.network.is_some() && self.gateway.is_some()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn bridge_conf_fromstr_001() {
        let uut = BridgeConf::from_str("");
        assert_eq!(uut.is_ok(), false);
    }

    #[test]
    fn bridge_conf_fromstr_002() {
        let uut = BridgeConf::from_str("net=10.192.0.24/29");
        assert_eq!(uut.is_ok(), false);
    }

    #[test]
    fn bridge_conf_fromstr_003() {
        let uut = BridgeConf::from_str("gateway=10.192.0.24");
        assert_eq!(uut.is_ok(), false);
    }

    #[test]
    fn bridge_conf_fromstr_004() {
        let uut = BridgeConf::from_str("name=test-bridge");
        assert_eq!(uut.is_ok(), false);
    }

    #[test]
    fn bridge_conf_fromstr_005() {
        let uut = BridgeConf::from_str("net=10.192.0.24/29\ngateway=10.192.1.25\nname=test-bridge");
        assert_eq!(uut.is_ok(), false);
    }

    #[test]
    fn bridge_conf_fromstr_020() {
        let uut = BridgeConf::from_str("net=10.192.0.24/29\ngateway=10.192.0.25\nname=test-bridge");
        assert_eq!(uut.is_ok(), true);
    }
}