jannie

jannie (mirror)
Log | Files | Refs | README | LICENSE

state.rs (6825B)


      1 use std::path::{Path, PathBuf};
      2 
      3 use tokio::runtime::Runtime;
      4 
      5 use crate::{
      6     config::{Config, Filter, InventoryFormat},
      7     filetree::{self, Filetree, node::Node},
      8     inventory::{self, Inventory},
      9     path_processing,
     10 };
     11 
     12 pub struct State {
     13     pub config_dir: PathBuf,
     14     pub config: Config,
     15     pub runtime: Runtime,
     16     pub inventory: Inventory,
     17     /// Paths are absolute and processed
     18     pub filters: Vec<Filter>,
     19     /// Absolute processed
     20     pub root: PathBuf,
     21     pub blacklist_tree: Filetree<()>,
     22     pub whitelist_tree: Filetree<()>,
     23     pub inventory_tree: Filetree<Option<inventory::Check>>,
     24 }
     25 
     26 impl State {
     27     pub fn new(config_dir: &Path, config: Config) -> Result<Self, Error> {
     28         let runtime = tokio::runtime::Builder::new_current_thread()
     29             .enable_all()
     30             .build()
     31             .map_err(Error::Runtime)?;
     32 
     33         let inventory_path = match config.inventory_format {
     34             InventoryFormat::Yaml => config_dir.join("inventory.yaml"),
     35             InventoryFormat::Json => config_dir.join("inventory.json"),
     36         };
     37 
     38         tracing::trace!("Reading inventory from {inventory_path:?}");
     39 
     40         let inventory = runtime
     41             .block_on(tokio::fs::read(inventory_path))
     42             .map_err(Error::ReadInventoryFile)?;
     43 
     44         tracing::trace!("Parsing inventory file contents");
     45 
     46         let inventory: Inventory =
     47             match config.inventory_format {
     48                 InventoryFormat::Yaml => serde_yaml::from_slice(inventory.as_slice())
     49                     .map_err(Error::ReadInventoryYaml)?,
     50                 InventoryFormat::Json => serde_json::from_slice(inventory.as_slice())
     51                     .map_err(Error::ReadInventoryJson)?,
     52             };
     53 
     54         tracing::trace!("Processing root path");
     55 
     56         let root = path_processing::process_path(&config.root).map_err(Error::ProcessRootPath)?;
     57 
     58         let mut filters = Vec::new();
     59 
     60         tracing::debug!("Preprocessing filters");
     61 
     62         for filter in &config.filters {
     63             tracing::trace!("Preprocessing filter {filter:?}");
     64             let mut path = config.root.clone();
     65             path.push(&filter.path);
     66             filters.push(Filter {
     67                 path: match path_processing::process_path(&path) {
     68                     Ok(path) => path,
     69                     Err(error) if error.is_file_not_found() => {
     70                         tracing::warn!("Filter path was not found: {filter:?}");
     71                         continue;
     72                     }
     73                     Err(error) => Err(Error::ProcessPath(error))?,
     74                 },
     75                 filter_type: filter.filter_type.clone(),
     76             });
     77         }
     78 
     79         tracing::debug!("Building trees from filters");
     80 
     81         let mut blacklist_tree = Filetree::new(Node::new("/".into(), ()));
     82         let mut whitelist_tree = Filetree::new(Node::new("/".into(), ()));
     83 
     84         for filter in &filters {
     85             let path = &filter.path;
     86             match filter.filter_type {
     87                 crate::config::FilterType::Whitelist => {
     88                     tracing::debug!("Adding {:?} to whitelist", path);
     89                     add_to_tree(&mut whitelist_tree, &path)?
     90                 }
     91                 crate::config::FilterType::Blacklist => {
     92                     if filters
     93                         .iter()
     94                         .filter(|filter| filter.is_whitelist())
     95                         .find(|filter| &filter.path == path)
     96                         .is_some()
     97                     {
     98                         tracing::debug!("Skipping {:?} blacklist", path);
     99                     } else {
    100                         tracing::debug!("Adding {:?} to blacklist", path);
    101                         add_to_tree(&mut blacklist_tree, &path)?
    102                     }
    103                 }
    104             }
    105         }
    106 
    107         tracing::debug!("Building inventory tree");
    108 
    109         let mut inventory_tree = Filetree::new(Node::new("/".into(), None));
    110         for item in &inventory.items {
    111             let path = match path_processing::process_path(&item.path) {
    112                 Ok(path) => path,
    113                 Err(error) if error.is_file_not_found() => {
    114                     tracing::warn!("Inventory item was not found: {item:?}");
    115                     continue;
    116                 }
    117                 Err(error) => Err(Error::ProcessPath(error))?,
    118             };
    119             let mut components = path.components();
    120             let mut path_buf = PathBuf::new();
    121             loop {
    122                 let component = components.next();
    123                 match component {
    124                     Some(component) => {
    125                         path_buf.push(component);
    126                         if inventory_tree.node_by_path(&path_buf).is_none() {
    127                             inventory_tree.insert(Node::new(path_buf.clone(), None))?;
    128                         }
    129                     }
    130                     None => {
    131                         inventory_tree
    132                             .node_by_path(&path)
    133                             .expect("Should have added inventory item")
    134                             .borrow_mut()
    135                             .meta_mut()
    136                             .replace(item.check.clone());
    137                         break;
    138                     }
    139                 }
    140             }
    141         }
    142 
    143         Ok(Self {
    144             config_dir: config_dir.into(),
    145             config,
    146             runtime,
    147             inventory,
    148             filters,
    149             root,
    150             blacklist_tree,
    151             whitelist_tree,
    152             inventory_tree,
    153         })
    154     }
    155 }
    156 
    157 fn add_to_tree(tree: &mut Filetree<()>, path: &Path) -> Result<(), Error> {
    158     let mut components = path.components();
    159     let mut path_buf = PathBuf::new();
    160     loop {
    161         let component = components.next();
    162         match component {
    163             Some(component) => {
    164                 path_buf.push(component);
    165                 if tree.node_by_path(&path_buf).is_none() {
    166                     tree.insert(Node::new(path_buf.clone(), ()))?;
    167                 }
    168             }
    169             None => {
    170                 assert!(tree.node_by_path(path).is_some());
    171                 break;
    172             }
    173         }
    174     }
    175     Ok(())
    176 }
    177 
    178 #[derive(thiserror::Error, Debug)]
    179 pub enum Error {
    180     #[error("Error building runtime: {0}")]
    181     Runtime(tokio::io::Error),
    182     #[error("Error reading inventory file: {0}")]
    183     ReadInventoryFile(std::io::Error),
    184     #[error("Error processing path: {0}")]
    185     ProcessPath(path_processing::Error),
    186     #[error("Error processing root path: {0}")]
    187     ProcessRootPath(path_processing::Error),
    188     #[error("Error parsing yaml inventory: {0}")]
    189     ReadInventoryYaml(serde_yaml::Error),
    190     #[error("Error parsing json inventory: {0}")]
    191     ReadInventoryJson(serde_json::Error),
    192     #[error("Error building filetree: {0}")]
    193     Filetree(#[from] filetree::Error),
    194 }