files restoring mechanism
parent
262b739c0c
commit
d7f39d8a99
|
|
@ -11,4 +11,6 @@ NOXIS_REMOTE_SERVER_URL = "ip.ip.ip.ip:port"
|
|||
NOXIS_CONFIG_PATH = "./settings.json"
|
||||
NOXIS_METRICS_MODE = "full"
|
||||
NOXIS_SOCKET_PATH = "/path/to/noxis.sock"
|
||||
NOXIS_BACKUP_FOLDER = "/path/to/backups/folder"
|
||||
|
||||
NOXIS_MAX_LOG_LEVEL = "TRACE"
|
||||
|
|
@ -22,3 +22,4 @@ futures = "0.3.31"
|
|||
async-trait = "0.1.88"
|
||||
crossbeam = { version = "0.8.4", features = ["crossbeam-channel"] }
|
||||
lazy_static = "1.5.0"
|
||||
ulid = "1.2.1"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,35 @@
|
|||
"src": "./tests/examples/",
|
||||
"triggers": {
|
||||
"onDelete": "stop",
|
||||
"onChange": "restart"
|
||||
"onChange": "restart",
|
||||
"doRestore" : true
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "none.json",
|
||||
"src": "./tests/examples/",
|
||||
"triggers": {
|
||||
"onDelete": "stop",
|
||||
"onChange": "restart",
|
||||
"doRestore" : false
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "invalid_config.json",
|
||||
"src": "./tests/examples/",
|
||||
"triggers": {
|
||||
"onDelete": "stop",
|
||||
"onChange": "restart",
|
||||
"doRestore" : false
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "save-conf.json",
|
||||
"src": "./tests/examples/",
|
||||
"triggers": {
|
||||
"onDelete": "stop",
|
||||
"onChange": "restart",
|
||||
"doRestore" : true
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
@ -23,6 +51,14 @@
|
|||
"wait": 2,
|
||||
"onLost": "stop"
|
||||
}
|
||||
},
|
||||
{
|
||||
"hostname": "8.8.8.8",
|
||||
"port": 443,
|
||||
"triggers": {
|
||||
"wait": 2,
|
||||
"onLost": "stop"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ async fn main() -> anyhow::Result<()> {
|
|||
handler.push(ctrlc);
|
||||
|
||||
let tx_bus = tx_to_bus.clone();
|
||||
let preboot_cli = preboot.clone();
|
||||
let monitoring = tokio::spawn(async move {
|
||||
let config = {
|
||||
let mut tick = tokio::time::interval(Duration::from_millis(500));
|
||||
|
|
@ -119,7 +120,7 @@ async fn main() -> anyhow::Result<()> {
|
|||
};
|
||||
}
|
||||
};
|
||||
if let Err(er) = init_monitoring(config, rx_to_supervisor, tx_bus).await {
|
||||
if let Err(er) = init_monitoring(config, preboot_cli, rx_to_supervisor, tx_bus).await {
|
||||
error!("Monitoring mod failed due to {}", er);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ pub struct PrebootParams {
|
|||
pub config: PathBuf,
|
||||
pub metrics: MetricsPrebootParams,
|
||||
pub self_socket: PathBuf,
|
||||
pub backup_folder: PathBuf,
|
||||
}
|
||||
|
||||
/// # implementation for `MetricsPrebootParams`
|
||||
|
|
@ -267,6 +268,29 @@ impl PrebootParams {
|
|||
}
|
||||
}
|
||||
},
|
||||
backup_folder: {
|
||||
match var("NOXIS_BACKUP_FOLDER") {
|
||||
Ok(val) => {
|
||||
let path = PathBuf::from(val);
|
||||
if path.exists() && path.is_dir() {
|
||||
path
|
||||
} else {
|
||||
PathBuf::from(std::env::current_dir()
|
||||
.expect("Crushed on getting current_dir path. Check fs state!")
|
||||
)
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
let default = std::env::current_dir()
|
||||
.expect("Crushed on getting current_dir path. Check fs state!");
|
||||
warn!(
|
||||
"$NOXIS_BACKUP_FOLDER wans't set. Default value - {}",
|
||||
default.display()
|
||||
);
|
||||
PathBuf::from(default)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -470,6 +470,8 @@ pub struct FileTriggers {
|
|||
pub on_delete: String,
|
||||
#[serde(rename = "onChange")]
|
||||
pub on_change: String,
|
||||
#[serde(rename = "doRestore")]
|
||||
pub do_restore: bool,
|
||||
}
|
||||
|
||||
/// # Metrics struct
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ lazy_static! {
|
|||
|
||||
pub mod v2 {
|
||||
use super::*;
|
||||
use crate::options::preboot::PrebootParams;
|
||||
use crate::utils::metrics::processes::{ProcessesAll, ProcessesQuery};
|
||||
use crate::{
|
||||
options::structs::{
|
||||
|
|
@ -65,10 +66,14 @@ pub mod v2 {
|
|||
bus: (bus_reciever, bus_sender),
|
||||
}
|
||||
}
|
||||
pub async fn with_config(mut self, config: Processes) -> Supervisor {
|
||||
pub async fn with_config(
|
||||
mut self,
|
||||
config: Processes,
|
||||
preboot : Arc<PrebootParams>
|
||||
) -> Supervisor {
|
||||
self.config = Arc::from(config);
|
||||
let _ = self.config.processes.iter().for_each(|prc| {
|
||||
let (rx, tx) = mpsc::channel::<Events>(10);
|
||||
let (rx, tx) = mpsc::channel::<Events>(100);
|
||||
let temp = ProcessesController::new(&prc.name, tx).with_exe(&prc.path);
|
||||
if !self.prcs.contains(&temp) {
|
||||
self.prcs.push_back(temp);
|
||||
|
|
@ -84,8 +89,21 @@ pub mod v2 {
|
|||
};
|
||||
hm.insert(proc_name.clone(), (triggers, rx.clone()));
|
||||
|
||||
let backup_file = {
|
||||
if file.triggers.do_restore {
|
||||
use ulid::Ulid;
|
||||
format!("{}{}.bak", {
|
||||
let path = preboot.backup_folder.to_string_lossy();
|
||||
if path.ends_with("/") { path.to_string() }
|
||||
else { format!("{}/", path) }
|
||||
}, Ulid::new())
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
};
|
||||
|
||||
let tempfile =
|
||||
FilesController::new(&file.filename.as_str(), hm).with_path(&file.src);
|
||||
FilesController::new(&file.filename.as_str(), hm).with_path(&file.src, backup_file);
|
||||
|
||||
if let Ok(file) = tempfile {
|
||||
if let Some(current_file) = self.files.iter_mut().find(|a| &&file == a) {
|
||||
|
|
@ -164,6 +182,7 @@ pub mod v2 {
|
|||
name: file.filename.to_string(),
|
||||
path: file.src.to_string(),
|
||||
status: file_cont.get_state(),
|
||||
backup_file : file_cont.get_backup_file(),
|
||||
triggers: file.triggers.to_owned(),
|
||||
});
|
||||
}
|
||||
|
|
@ -351,11 +370,12 @@ pub mod v2 {
|
|||
|
||||
pub async fn init_monitoring(
|
||||
config: Processes,
|
||||
preboot : Arc<PrebootParams>,
|
||||
bus_reciever: BusReciever,
|
||||
bus_sender: BusSender,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut supervisor = Supervisor::new(bus_reciever, bus_sender)
|
||||
.with_config(config)
|
||||
.with_config(config, preboot)
|
||||
.await;
|
||||
info!("Monitoring: {} ", &supervisor.get_stats());
|
||||
supervisor.process().await;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ pub mod v2 {
|
|||
name: Arc<str>,
|
||||
path: String,
|
||||
code_name: Arc<str>,
|
||||
backup_file : String,
|
||||
state: FileState,
|
||||
watcher: Option<Inotify>,
|
||||
triggers: EventHandlers,
|
||||
|
|
@ -51,10 +52,11 @@ pub mod v2 {
|
|||
watcher: None,
|
||||
triggers,
|
||||
code_name: name.clone(),
|
||||
backup_file: String::new(),
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn with_path(mut self, path: impl AsRef<Path>) -> anyhow::Result<FilesController> {
|
||||
pub fn with_path(mut self, path: impl AsRef<Path>, backup : String) -> anyhow::Result<FilesController> {
|
||||
self.path = path.as_ref().to_string_lossy().into_owned();
|
||||
self.watcher = {
|
||||
match create_watcher(&self.name, &self.path) {
|
||||
|
|
@ -69,6 +71,11 @@ pub mod v2 {
|
|||
}
|
||||
};
|
||||
self.code_name = Arc::from(format!("{}{}", &self.path, &self.code_name));
|
||||
self.backup_file = backup;
|
||||
match create_backup(&self.code_name, &self.backup_file) {
|
||||
Ok(_) => info!("Backup file for {} was created ({})", &self.code_name, &self.backup_file),
|
||||
Err(er) => warn!("{}. Ignoring ...", er),
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
pub fn add_event(&mut self, file_controller: FilesController) {
|
||||
|
|
@ -97,6 +104,9 @@ pub mod v2 {
|
|||
pub fn get_code_name(&self) -> Arc<str> {
|
||||
self.code_name.clone()
|
||||
}
|
||||
pub fn get_backup_file(&self) -> String {
|
||||
self.backup_file.to_string()
|
||||
}
|
||||
}
|
||||
#[async_trait]
|
||||
impl ProcessUnit for FilesController {
|
||||
|
|
@ -120,9 +130,24 @@ pub mod v2 {
|
|||
a || mask.mask == EventMask::DELETE_SELF,
|
||||
b || mask.mask == EventMask::MODIFY,
|
||||
)
|
||||
});
|
||||
if let (recreate_watcher, true) = (need_to_recreate, was_modifired) {
|
||||
}
|
||||
);
|
||||
if self.backup_file.is_empty() {
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
if let (mut recreate_watcher, true) = (need_to_recreate, was_modifired) {
|
||||
if self.backup_file.is_empty() {
|
||||
warn!("File {} ({}) was changed", self.name, &self.path);
|
||||
self.trigger_on(Some(FileTriggerType::OnChange)).await;
|
||||
} else {
|
||||
recreate_watcher = true;
|
||||
match restore_file(&self.code_name, &self.backup_file).await {
|
||||
Ok(_) => info!("File {} was successfully restored", &self.code_name),
|
||||
Err(er) => error!("Cannot restore file {} : {}", &self.code_name, er),
|
||||
}
|
||||
}
|
||||
if recreate_watcher {
|
||||
self.watcher = match create_watcher(&self.name, &self.path) {
|
||||
Ok(notifier) => Some(notifier),
|
||||
|
|
@ -135,21 +160,42 @@ pub mod v2 {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.trigger_on(Some(FileTriggerType::OnChange)).await;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
None => { /* DEAD END */ }
|
||||
None => return,
|
||||
}
|
||||
} else {
|
||||
if let FileState::Ok = self.state {
|
||||
if self.backup_file.is_empty() {
|
||||
warn!(
|
||||
"File {} ({}) was not found in determined scope",
|
||||
self.name, &self.path
|
||||
);
|
||||
self.state = FileState::NotFound;
|
||||
self.trigger_on(Some(FileTriggerType::OnDelete)).await;
|
||||
} else {
|
||||
warn!(
|
||||
"File {} ({}) was not found in determined scope. Restoring from backup-file ...",
|
||||
self.name, &self.path
|
||||
);
|
||||
match restore_file(&self.code_name, &self.backup_file).await {
|
||||
Err(er) => error!("Cannot restore file {} : {}", &self.code_name, er),
|
||||
Ok(_) => {
|
||||
info!("File {} was successfully restored", &self.code_name);
|
||||
self.watcher = match create_watcher(&self.name, &self.path) {
|
||||
Ok(notifier) => Some(notifier),
|
||||
Err(er) => {
|
||||
error!(
|
||||
"Failed to recreate watcher for {} ({}) : {}",
|
||||
self.name, &self.path, er
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -158,6 +204,18 @@ pub mod v2 {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_backup(target: &str, backup: &str) -> anyhow::Result<u64> {
|
||||
return if !backup.is_empty() {
|
||||
Ok(std::fs::copy(target, backup)?)
|
||||
} else {
|
||||
Err(anyhow::Error::msg(format!("No need to create backup-file for {}", target)))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn restore_file(target: &str, backup: &str) -> anyhow::Result<u64> {
|
||||
Ok(tokio::fs::copy(backup, target).await?)
|
||||
}
|
||||
|
||||
/// # Fn `create_watcher`
|
||||
/// ## for creating watcher on file's delete | update events
|
||||
///
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ use crate::{
|
|||
options::structs::ProcessState,
|
||||
utils::metrics::processes::{ProcessesGeneral, ProcessesQuery},
|
||||
};
|
||||
use chrono::Datelike;
|
||||
use log::warn;
|
||||
use noxis_cli::metrics_models::MetricsMode;
|
||||
use std::{any::Any, collections::BTreeMap, sync::Arc};
|
||||
|
|
@ -327,6 +326,7 @@ pub mod processes {
|
|||
pub name: String,
|
||||
pub path: String,
|
||||
pub status: FileState,
|
||||
pub backup_file : String,
|
||||
pub triggers: FileTriggers,
|
||||
}
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
|
|
|
|||
Loading…
Reference in New Issue