lib_clds/src/utils.rs

146 lines
5.0 KiB
Rust

use anyhow::{anyhow,Result};
use std::str;
use std::fs; //, io};
use std::fs::OpenOptions;
use std::io::{Write};
// use std::io::prelude::*;
use std::net::TcpStream;
use std::path::Path;
use std::process::{Command};
use crate::defs::{SSHAccess,Cntrllr};
use crate::clouds::defs::{Cloud};
pub fn parse_yaml_value(value: serde_yaml::Value, key: String, ctx: &mut tera::Context ) {
if let Some(v) = value.as_str() {
ctx.insert(key.to_owned(),&v);
} else if let Some(v) = value.as_bool() {
ctx.insert(key.to_owned(),&v);
} else if value.is_mapping() {
if let Some(map) = value.as_mapping() {
ctx.insert(key.to_owned(),&map);
}
} else if value.is_sequence() {
if let Some(seq) = value.as_sequence() {
// let mut data_seq: Vec<String> = Vec::new();
// for (line, elem) in seq.iter().enumerate() {
// if let Some(s) = elem.as_str() {
// data_seq.push(s.to_owned());
// } else {
// println!("Error {} line {}",&key,&line);
// }
// }
// ctx.insert(key.to_owned(),&data_seq);
ctx.insert(key.to_owned(),&seq);
}
} else {
ctx.insert(key.to_owned(),&value);
}
}
pub async fn write_log(output_path: &str, hostname: &str, name: &str, msg: &str) -> Result<()> {
let now = chrono::Utc::now().timestamp();
let out = format!("{}: [{}] {} -> {}\n",&now,&hostname, &name,&msg);
if Path::new(&output_path).exists() {
let mut file = OpenOptions::new().append(true).open(&output_path)?;
// out = out.replace("&#x2F;", "/");
file.write(out.as_bytes())?;
} else {
if Path::new(&output_path).exists() {
fs::remove_file(&output_path)?;
}
let mut file = OpenOptions::new().write(true).create(true).open(&output_path)?;
file.write_all(out.as_bytes())?;
}
Ok(())
}
pub fn source_host() -> String {
// TODO a better way by finding cntrllr in config definition
let running_host = envmnt::get_or("HOSTNAME", "localhost");
let cntrllr_host = envmnt::get_or("CNTRLLR_HOST", "");
if running_host == cntrllr_host {
running_host.to_owned()
} else {
cntrllr_host.to_owned()
}
}
pub async fn liveness_check(source: &str,cntrllrs: &Vec<Cntrllr>,serverstring: &str,tsk_name: &str) -> Result<()> {
let debug=envmnt::get_isize("DEBUG",0);
// let serverstring = format!("{}:22",&hostname);
let mut check_cntrllr = Cntrllr::default();
for cntrllr in cntrllrs {
let serverstring = format!("{}:{}",&cntrllr.sshaccess.host,&cntrllr.sshaccess.port);
match TcpStream::connect(&serverstring) {
Ok(_serverstream) => {
check_cntrllr = cntrllr.to_owned();
break;
// handle_input(serverstream);
},
Err(e) => {
println!("Error: {}:{} -> {}",&cntrllr.sshaccess.host,&cntrllr.sshaccess.port,e);
}
}
}
// Some Ips in serverstring can be private so we need to know from where are we checking ...
if !check_cntrllr.sshaccess.host.is_empty() && envmnt::get_or("HOSTNAME", "localhost") == check_cntrllr.sshaccess.host {
if debug > 1 {
println!("Checking connection to {} for {} -> {}",&serverstring,&source,&tsk_name);
}
match TcpStream::connect(&serverstring) {
Ok(_serverstream) => {
Ok(())
// handle_input(serverstream);
},
Err(e) => {
Err(anyhow!("Source {}: Connection to '{}' for tsksrvc '{}' failed: {}",&source,&serverstring,&tsk_name,&e))
}
}
} else {
if debug > 1 {
println!("Remote checking connection from {} to {} for {} -> {}",&check_cntrllr.sshaccess.host,&serverstring,&source,&tsk_name);
}
let vec_serverstring: Vec<&str> = serverstring.split(':').collect();
let output = Command::new("ssh")
.arg("-o")
.arg("StrictHostKeyChecking=accept-new")
.arg("-p")
.arg(format!("{}",check_cntrllr.sshaccess.port))
.arg(format!("{}@{}",check_cntrllr.sshaccess.user,&check_cntrllr.sshaccess.host))
.arg("nc")
.arg("-zv")
.arg(format!("{}",vec_serverstring[0]))
.arg(format!("{}",vec_serverstring[1]))
.output()?;
match &output.status.code() {
Some(code) =>
if format!("{}",code) == "0" {
Ok(())
} else {
let err = str::from_utf8(&output.stderr).unwrap_or_else(|_| "");
Err(anyhow!("Source {}: Connection to '{}' ({}) for tsksrvc '{}' failed:\n {}",&source,serverstring,&check_cntrllr.sshaccess.host,&tsk_name,&err))
}
None => Ok(())
}
}
}
pub async fn host_ssh_is_alive(cloud: &Cloud, cmd: &str, hostname: &str,tsk_name: &str, ssh_access: &SSHAccess) -> Result<()> {
let debug=envmnt::get_isize("DEBUG",0);
if debug > 1 {
println!("Checking ssh connection to {}@{} on {} for {} -> {}",ssh_access.user,ssh_access.host,ssh_access.port,&cloud.env.source,&tsk_name);
}
let output = Command::new("ssh")
.arg("-o")
.arg("StrictHostKeyChecking=accept-new")
.arg("-p")
.arg(format!("{}",ssh_access.port))
.arg(format!("{}@{}",ssh_access.user,ssh_access.host))
.arg("ls")
.output()?;
// dbg!(&output);
if !&output.status.success() {
let err = str::from_utf8(&output.stderr).unwrap_or_else(|_| "");
return Err(anyhow!("Source {}: Connection to '{}' for tsksrvc '{}' cmd '{}' failed: {}",&cloud.env.source,&hostname,&tsk_name,&cmd,&err));
}
Ok(())
}