use crate::tasks::*;
use crate::handle::handle::TaskHandle;
use crate::inventory::hosts::{HostOSType};
use serde::Deserialize;
use std::sync::{Arc,RwLock};
const MODULE: &str = "facts";
#[derive(Deserialize,Debug)]
#[serde(deny_unknown_fields)]
pub struct FactsTask {
pub name: Option<String>,
pub with: Option<PreLogicInput>,
pub and: Option<PostLogicInput>
}
struct FactsAction {
}
impl IsTask for FactsTask {
fn get_module(&self) -> String { String::from(MODULE) }
fn get_name(&self) -> Option<String> { self.name.clone() }
fn get_with(&self) -> Option<PreLogicInput> { self.with.clone() }
fn evaluate(&self, handle: &Arc<TaskHandle>, request: &Arc<TaskRequest>, tm: TemplateMode) -> Result<EvaluatedTask, Arc<TaskResponse>> {
return Ok(
EvaluatedTask {
action: Arc::new(FactsAction {
}),
with: Arc::new(PreLogicInput::template(handle, request, tm, &self.with)?),
and: Arc::new(PostLogicInput::template(handle, request, tm, &self.and)?),
}
);
}
}
impl IsAction for FactsAction {
fn dispatch(&self, handle: &Arc<TaskHandle>, request: &Arc<TaskRequest>) -> Result<Arc<TaskResponse>, Arc<TaskResponse>> {
match request.request_type {
TaskRequestType::Query => {
return Ok(handle.response.needs_passive(request));
},
TaskRequestType::Passive => {
self.do_facts(handle, request)?;
return Ok(handle.response.is_passive(request));
},
_ => { return Err(handle.response.not_supported(request)); }
}
}
}
impl FactsAction {
fn do_facts(&self, handle: &Arc<TaskHandle>, request: &Arc<TaskRequest>) -> Result<(), Arc<TaskResponse>> {
let os_type = handle.host.read().unwrap().os_type;
let facts = Arc::new(RwLock::new(serde_yaml::Mapping::new()));
match os_type {
Some(HostOSType::Linux) => { self.do_linux_facts(handle, request, &facts)?; },
Some(HostOSType::MacOS) => { self.do_mac_facts(handle, request, &facts)?; }
None => { return Err(handle.response.is_failed(request, &String::from("facts not implemented for OS Type"))); }
};
handle.host.write().unwrap().update_facts(&facts);
return Ok(());
}
fn insert_string(&self, mapping: &Arc<RwLock<serde_yaml::Mapping>>, key: &String, value: &String) {
mapping.write().unwrap().insert(serde_yaml::Value::String(key.clone()), serde_yaml::Value::String(value.clone()));
}
fn do_mac_facts(&self, _handle: &Arc<TaskHandle>, _request: &Arc<TaskRequest>, mapping: &Arc<RwLock<serde_yaml::Mapping>>) -> Result<(), Arc<TaskResponse>> {
self.insert_string(mapping, &String::from("jet_os_type"), &String::from("MacOS"));
self.insert_string(mapping, &String::from("jet_os_flavor"), &String::from("OSX"));
return Ok(());
}
fn do_linux_facts(&self, handle: &Arc<TaskHandle>, request: &Arc<TaskRequest>, mapping: &Arc<RwLock<serde_yaml::Mapping>>) -> Result<(), Arc<TaskResponse>> {
self.insert_string(mapping, &String::from("jet_os_type"), &String::from("Linux"));
self.do_linux_os_release(handle, request, mapping)?;
return Ok(());
}
fn do_linux_os_release(&self, handle: &Arc<TaskHandle>, request: &Arc<TaskRequest>, mapping: &Arc<RwLock<serde_yaml::Mapping>>) -> Result<(), Arc<TaskResponse>> {
let cmd = String::from("cat /etc/os-release");
let result = handle.remote.run(request, &cmd, CheckRc::Checked)?;
let (_rc, out) = cmd_info(&result);
for line in out.lines() {
let mut tokens = line.split("=");
let key = tokens.nth(0);
let value = tokens.nth(0);
if key.is_some() && value.is_some() {
let mut k1 = key.unwrap().trim().to_string();
k1.make_ascii_lowercase();
let v1 = value.unwrap().trim().to_string().replace("\"","");
self.insert_string(mapping, &format!("jet_os_release_{}", k1.to_string()), &v1.clone());
if k1.eq("id_like") {
if v1.find("rhel").is_some() {
self.insert_string(mapping, &String::from("jet_os_flavor"), &String::from("EL"));
} else if v1.find("debian").is_some() {
self.insert_string(mapping, &String::from("jet_os_flavor"), &String::from("Debian"))
}
}
}
}
return Ok(());
}
}