use std::collections::HashMap;
use crate::util::yaml::blend_variables;
use std::sync::Arc;
use crate::inventory::groups::Group;
use std::sync::RwLock;
use std::collections::HashSet;
use serde_yaml;
#[derive(Clone,Copy,Debug)]
pub enum HostOSType {
Linux,
MacOS,
}
#[derive(Clone,Copy,Debug)]
pub enum PackagePreference {
Dnf,
Yum,
}
pub struct Host {
pub name : String,
pub groups : HashMap<String, Arc<RwLock<Group>>>,
pub variables : serde_yaml::Mapping,
pub os_type : Option<HostOSType>,
checksum_cache : HashMap<String,String>,
checksum_cache_task_id : usize,
facts : serde_yaml::Value,
dyn_variables : serde_yaml::Value,
pub package_preference : Option<PackagePreference>,
notified_handlers : HashMap<usize, HashSet<String>>
}
impl Host {
pub fn new(name: &String) -> Self {
Self {
name: name.clone(),
variables : serde_yaml::Mapping::new(),
groups: HashMap::new(),
os_type: None,
checksum_cache: HashMap::new(),
checksum_cache_task_id: 0,
facts: serde_yaml::Value::from(serde_yaml::Mapping::new()),
dyn_variables: serde_yaml::Value::from(serde_yaml::Mapping::new()),
notified_handlers: HashMap::new(),
package_preference: None
}
}
pub fn notify(&mut self, play_number: usize, signal: &String) {
if ! self.notified_handlers.contains_key(&play_number) {
self.notified_handlers.insert(play_number, HashSet::new());
}
let entry = self.notified_handlers.get_mut(&play_number).unwrap();
entry.insert(signal.clone());
}
pub fn is_notified(&self, play_number: usize, signal: &String) -> bool {
let entry = self.notified_handlers.get(&play_number);
if entry.is_none() {
return false;
} else {
return entry.unwrap().contains(&signal.clone());
}
}
pub fn set_checksum_cache(&mut self, path: &String, checksum: &String) {
self.checksum_cache.insert(path.clone(), checksum.clone());
}
pub fn get_checksum_cache(&mut self, task_id: usize, path: &String) -> Option<String> {
if task_id > self.checksum_cache_task_id {
self.checksum_cache_task_id = task_id;
self.checksum_cache.clear();
}
if self.checksum_cache.contains_key(path) {
let result = self.checksum_cache.get(path).unwrap();
return Some(result.clone());
}
else {
return None;
}
}
pub fn set_os_info(&mut self, uname_output: &String) -> Result<(),String> {
if uname_output.starts_with("Linux") {
self.os_type = Some(HostOSType::Linux);
} else if uname_output.starts_with("Darwin") {
self.os_type = Some(HostOSType::MacOS);
} else {
return Err(format!("OS Type could not be detected from uname -a: {}", uname_output));
}
return Ok(());
}
pub fn get_groups(&self) -> HashMap<String, Arc<RwLock<Group>>> {
let mut results : HashMap<String, Arc<RwLock<Group>>> = HashMap::new();
for (k,v) in self.groups.iter() {
results.insert(k.clone(), Arc::clone(&v));
}
return results;
}
pub fn has_group(&self, group_name: &String) -> bool {
for (k,_v) in self.groups.iter() {
if k == group_name {
return true;
}
}
return false;
}
pub fn get_group_names(&self) -> Vec<String> {
return self.get_groups().iter().map(|(k,_v)| k.clone()).collect();
}
pub fn add_group(&mut self, name: &String, group: Arc<RwLock<Group>>) {
self.groups.insert(name.clone(), Arc::clone(&group));
}
pub fn get_ancestor_groups(&self, depth_limit: usize) -> HashMap<String, Arc<RwLock<Group>>> {
let mut results : HashMap<String, Arc<RwLock<Group>>> = HashMap::new();
for (k,v) in self.get_groups().into_iter() {
results.insert(k, Arc::clone(&v));
for (k2,v2) in v.read().expect("group read").get_ancestor_groups(depth_limit).into_iter() {
results.insert(k2, Arc::clone(&v2));
}
}
return results;
}
pub fn get_ancestor_group_names(&self) -> Vec<String> {
return self.get_ancestor_groups(20usize).iter().map(|(k,_v)| k.clone()).collect();
}
pub fn get_variables(&self) -> serde_yaml::Mapping {
return self.variables.clone();
}
pub fn set_variables(&mut self, variables: serde_yaml::Mapping) {
self.variables = variables.clone();
}
pub fn update_variables(&mut self, mapping: serde_yaml::Mapping) {
let map = mapping.clone();
blend_variables(&mut self.dyn_variables, serde_yaml::Value::Mapping(map));
}
pub fn get_blended_variables(&self) -> serde_yaml::Mapping {
let mut blended : serde_yaml::Value = serde_yaml::Value::from(serde_yaml::Mapping::new());
let ancestors = self.get_ancestor_groups(20);
for (_k,v) in ancestors.iter() {
let theirs : serde_yaml::Value = serde_yaml::Value::from(v.read().unwrap().get_variables());
blend_variables(&mut blended, theirs);
}
blend_variables(&mut blended, self.dyn_variables.clone());
let mine = serde_yaml::Value::from(self.get_variables());
blend_variables(&mut blended, mine);
blend_variables(&mut blended, self.facts.clone());
return match blended {
serde_yaml::Value::Mapping(x) => x,
_ => panic!("get_blended_variables produced a non-mapping (1)")
}
}
pub fn update_facts(&mut self, mapping: &Arc<RwLock<serde_yaml::Mapping>>) {
let map = mapping.read().unwrap().clone();
blend_variables(&mut self.facts, serde_yaml::Value::Mapping(map));
}
pub fn update_facts2(&mut self, mapping: serde_yaml::Mapping) {
blend_variables(&mut self.facts, serde_yaml::Value::Mapping(mapping));
}
pub fn get_variables_yaml(&self) -> Result<String, String> {
let result = serde_yaml::to_string(&self.get_variables());
return match result {
Ok(x) => Ok(x),
Err(_y) => Err(String::from("error loading variables"))
}
}
pub fn get_blended_variables_yaml(&self) -> Result<String,String> {
let result = serde_yaml::to_string(&self.get_blended_variables());
return match result {
Ok(x) => Ok(x),
Err(_y) => Err(String::from("error loading blended variables"))
}
}
}