// Code to handle the nebula worker use crate::config::{load_cdata, NebulaConfig, TFClientConfig}; use crate::daemon::ThreadMessageSender; use crate::dirs::get_nebulaconfig_file; use crate::embedded_nebula::run_embedded_nebula; use log::{debug, error, info}; use std::error::Error; use std::fs; use std::sync::mpsc::Receiver; use std::time::{Duration, SystemTime}; pub enum NebulaWorkerMessage { Shutdown, ConfigUpdated, WakeUp, } fn insert_private_key(instance: &str) -> Result<(), Box> { if !get_nebulaconfig_file(instance) .ok_or("Could not get config file location")? .exists() { return Ok(()); // cant insert private key into a file that does not exist - BUT. we can gracefully handle nebula crashing - we cannot gracefully handle this fn failing } let cdata = load_cdata(instance)?; let key = cdata.dh_privkey.ok_or("Missing private key")?; let config_str = fs::read_to_string( get_nebulaconfig_file(instance).ok_or("Could not get config file location")?, )?; let mut config: NebulaConfig = serde_yaml::from_str(&config_str)?; config.pki.key = Some(String::from_utf8(key)?); debug!("inserted private key into config: {:?}", config); let config_str = serde_yaml::to_string(&config)?; fs::write( get_nebulaconfig_file(instance).ok_or("Could not get config file location")?, config_str, )?; Ok(()) } pub fn nebulaworker_main( _config: TFClientConfig, instance: String, _transmitter: ThreadMessageSender, rx: Receiver, ) { let _cdata = match load_cdata(&instance) { Ok(data) => data, Err(e) => { error!("unable to load cdata: {}", e); error!("nebula thread exiting with error"); return; } }; info!("fixing config..."); match insert_private_key(&instance) { Ok(_) => { info!("config fixed (private-key embedded)"); } Err(e) => { error!("unable to fix config: {}", e); error!("nebula thread exiting with error"); return; } } info!("starting nebula child..."); let mut child = match run_embedded_nebula(&[ "-config".to_string(), get_nebulaconfig_file(&instance) .unwrap() .to_str() .unwrap() .to_string(), ]) { Ok(c) => c, Err(e) => { error!("unable to start embedded nebula binary: {}", e); error!("nebula thread exiting with error"); return; } }; info!("nebula process started"); let mut last_restart_time = SystemTime::now(); // dont need to save it, because we do not, in any circumstance, write to it loop { if let Ok(e) = child.try_wait() { if e.is_some() && SystemTime::now() > last_restart_time + Duration::from_secs(5) { info!("nebula process has exited, restarting"); child = match run_embedded_nebula(&[ "-config".to_string(), get_nebulaconfig_file(&instance) .unwrap() .to_str() .unwrap() .to_string(), ]) { Ok(c) => c, Err(e) => { error!("unable to start embedded nebula binary: {}", e); error!("nebula thread exiting with error"); return; } }; info!("nebula process started"); last_restart_time = SystemTime::now(); } } match rx.recv() { Ok(msg) => match msg { NebulaWorkerMessage::WakeUp => { continue; } NebulaWorkerMessage::Shutdown => { info!("recv on command socket: shutdown, stopping"); info!("shutting down nebula binary"); match child.kill() { Ok(_) => { debug!("nebula process exited"); } Err(e) => { error!("nebula process already exited: {}", e); } } info!("nebula shut down"); break; } NebulaWorkerMessage::ConfigUpdated => { info!("our configuration has been updated - restarting"); debug!("killing existing process"); match child.kill() { Ok(_) => { debug!("nebula process exited"); } Err(e) => { error!("nebula process already exited: {}", e); } } debug!("fixing config..."); match insert_private_key(&instance) { Ok(_) => { debug!("config fixed (private-key embedded)"); } Err(e) => { error!("unable to fix config: {}", e); error!("nebula thread exiting with error"); return; } } debug!("restarting nebula process"); child = match run_embedded_nebula(&[ "-config".to_string(), get_nebulaconfig_file(&instance) .unwrap() .to_str() .unwrap() .to_string(), ]) { Ok(c) => c, Err(e) => { error!("unable to start embedded nebula binary: {}", e); error!("nebula thread exiting with error"); return; } }; last_restart_time = SystemTime::now(); debug!("nebula process restarted"); } }, Err(e) => { error!("nebulaworker command socket errored: {}", e); return; } } } }