commit
2d8f270c54
|
|
@ -1,4 +1,5 @@
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
use metrics_models::MetricsMode;
|
||||||
|
|
||||||
#[derive(Debug, Parser, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Parser, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
|
|
@ -8,45 +9,35 @@ pub struct Cli {
|
||||||
help = "explicit specify of NOXIS Socket file"
|
help = "explicit specify of NOXIS Socket file"
|
||||||
)]
|
)]
|
||||||
pub socket: String,
|
pub socket: String,
|
||||||
#[command(
|
#[command(subcommand, help = "to manage Noxis work")]
|
||||||
subcommand,
|
|
||||||
help = "to manage Noxis work",
|
|
||||||
)]
|
|
||||||
pub command: Commands,
|
pub command: Commands,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Subcommand, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Subcommand, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum Commands {
|
pub enum Commands {
|
||||||
#[command(
|
#[command(about = "To get info about current Noxis status")]
|
||||||
about = "To get info about current Noxis status",
|
|
||||||
)]
|
|
||||||
Status,
|
Status,
|
||||||
#[command(
|
#[command(about = "To start Noxis process")]
|
||||||
about = "To start Noxis process",
|
|
||||||
)]
|
|
||||||
Start(StartAction),
|
Start(StartAction),
|
||||||
#[command(
|
#[command(about = "To stop Noxis process")]
|
||||||
about = "To stop Noxis process",
|
|
||||||
)]
|
|
||||||
Stop,
|
Stop,
|
||||||
#[command(
|
#[command(about = "To restart Noxis process")]
|
||||||
about = "To restart Noxis process",
|
|
||||||
)]
|
|
||||||
Restart(StartAction),
|
Restart(StartAction),
|
||||||
#[command(
|
#[command(about = "To get list of processes that are being monitoring")]
|
||||||
about = "To get list of processes that are being monitoring",
|
|
||||||
)]
|
|
||||||
Processes,
|
Processes,
|
||||||
// process command
|
// process command
|
||||||
#[command(
|
#[command(about = "To manage current process that is being monitoring")]
|
||||||
about = "To manage current process that is being monitoring",
|
|
||||||
)]
|
|
||||||
Process(ProcessCommand),
|
Process(ProcessCommand),
|
||||||
// config command =
|
#[command(about = "To manage config settings")]
|
||||||
#[command(
|
|
||||||
about = "To manage config settings",
|
|
||||||
)]
|
|
||||||
Config(ConfigCommand),
|
Config(ConfigCommand),
|
||||||
|
#[command(about = "To inspect system metrics in restricted mode")]
|
||||||
|
Inspect(MetricsCommand),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Parser, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct MetricsCommand {
|
||||||
|
#[command(subcommand)]
|
||||||
|
pub mode: MetricsMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Parser, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Parser, serde::Serialize, serde::Deserialize)]
|
||||||
|
|
@ -67,117 +58,81 @@ pub struct ConfigCommand {
|
||||||
|
|
||||||
#[derive(Debug, Subcommand, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Subcommand, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum ConfigAction {
|
pub enum ConfigAction {
|
||||||
#[command(
|
#[command(about = "To change current Noxis configuration")]
|
||||||
about = "To change current Noxis configuration",
|
|
||||||
)]
|
|
||||||
Local(LocalConfig),
|
Local(LocalConfig),
|
||||||
#[command(
|
#[command(about = "To change credentials of the remote config server")]
|
||||||
about = "To change credentials of the remote config server",
|
|
||||||
)]
|
|
||||||
Remote,
|
Remote,
|
||||||
#[command(
|
#[command(about = "To reset all config settings")]
|
||||||
about = "To reset all config settings",
|
|
||||||
)]
|
|
||||||
Reset,
|
Reset,
|
||||||
#[command(
|
#[command(about = "To get current Noxis configuration", name = "ls")]
|
||||||
about = "To get current Noxis configuration",
|
|
||||||
name = "ls"
|
|
||||||
)]
|
|
||||||
Show(EnvConfig),
|
Show(EnvConfig),
|
||||||
}
|
}
|
||||||
#[derive(Debug, Parser, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Parser, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct EnvConfig {
|
pub struct EnvConfig {
|
||||||
// flag
|
// flag
|
||||||
#[arg(
|
#[arg(long = "env", action, help = "to read environment vars configuration")]
|
||||||
long = "env",
|
|
||||||
action,
|
|
||||||
help = "to read environment vars configuration",
|
|
||||||
)]
|
|
||||||
pub is_env: bool,
|
pub is_env: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Parser, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Parser, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct LocalConfig {
|
pub struct LocalConfig {
|
||||||
// flag
|
// flag
|
||||||
#[arg(
|
#[arg(long = "json", action, help = "to read following input as JSON")]
|
||||||
long = "json",
|
|
||||||
action,
|
|
||||||
help = "to read following input as JSON",
|
|
||||||
)]
|
|
||||||
pub is_json: bool,
|
pub is_json: bool,
|
||||||
// value
|
// value
|
||||||
#[arg(
|
#[arg(help = "path to config file or config String (with --json flag)")]
|
||||||
help = "path to config file or config String (with --json flag)",
|
|
||||||
)]
|
|
||||||
pub config: String,
|
pub config: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Parser, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Parser, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct ProcessCommand {
|
pub struct ProcessCommand {
|
||||||
#[arg(
|
#[arg(help = "name of needed process")]
|
||||||
help = "name of needed process",
|
|
||||||
)]
|
|
||||||
pub process: String,
|
pub process: String,
|
||||||
#[command(
|
#[command(subcommand, help = "To get current process's status")]
|
||||||
subcommand,
|
|
||||||
help = "To get current process's status",
|
|
||||||
)]
|
|
||||||
pub action: ProcessAction,
|
pub action: ProcessAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Subcommand, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Subcommand, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum ProcessAction {
|
pub enum ProcessAction {
|
||||||
#[command(
|
#[command(about = "To get info about current process status")]
|
||||||
about = "To get info about current process status",
|
|
||||||
)]
|
|
||||||
Status,
|
Status,
|
||||||
#[command(
|
#[command(about = "To start current process")]
|
||||||
about = "To start current process",
|
|
||||||
)]
|
|
||||||
Start,
|
Start,
|
||||||
#[command(
|
#[command(about = "To stop current process")]
|
||||||
about = "To stop current process",
|
|
||||||
)]
|
|
||||||
Stop,
|
Stop,
|
||||||
#[command(
|
#[command(about = "To freeze (hybernaze) current process")]
|
||||||
about = "To freeze (hybernaze) current process",
|
|
||||||
)]
|
|
||||||
Freeze,
|
Freeze,
|
||||||
#[command(
|
#[command(about = "To unfreeze (unhybernaze) current process")]
|
||||||
about = "To unfreeze (unhybernaze) current process",
|
|
||||||
)]
|
|
||||||
Unfreeze,
|
Unfreeze,
|
||||||
#[command(
|
#[command(about = "To restart current process")]
|
||||||
about = "To restart current process",
|
|
||||||
)]
|
|
||||||
Restart,
|
Restart,
|
||||||
#[command(
|
#[command(about = "To get info about current process's dependencies")]
|
||||||
about = "To get info about current process's dependencies",
|
|
||||||
)]
|
|
||||||
Deps,
|
Deps,
|
||||||
#[command(
|
#[command(about = "To get info about current process's files-dependencies")]
|
||||||
about = "To get info about current process's files-dependencies",
|
|
||||||
)]
|
|
||||||
Files,
|
Files,
|
||||||
#[command(
|
#[command(about = "To get info about current process's services-dependencies")]
|
||||||
about = "To get info about current process's services-dependencies",
|
|
||||||
)]
|
|
||||||
Services,
|
Services,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod metrics_models {
|
pub mod metrics_models {
|
||||||
|
#[derive(Debug, clap::Parser, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum MetricsMode {
|
pub enum MetricsMode {
|
||||||
|
#[command(about = "To capture all metrics about undercontrolled system")]
|
||||||
Full,
|
Full,
|
||||||
// system
|
// system
|
||||||
|
#[command(about = "To capture general host info")]
|
||||||
|
Host,
|
||||||
|
#[command(about = "To capture detailed CPU metrics")]
|
||||||
Cpu,
|
Cpu,
|
||||||
Memory,
|
#[command(about = "To capture RAM metrics")]
|
||||||
Ram,
|
Ram,
|
||||||
|
#[command(about = "To capture disk environment metrics")]
|
||||||
Rom,
|
Rom,
|
||||||
|
#[command(about = "To capture system net interfaces metrics")]
|
||||||
Network,
|
Network,
|
||||||
// processes
|
// processes
|
||||||
Processes
|
#[command(about = "To capture monitoring processes metrics")]
|
||||||
// Config
|
Processes, // Config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub enum NoxisCliError {
|
pub enum NoxisCliError {
|
||||||
#[error("Can't find socket `{0}`. {1}")]
|
#[error("Can't find socket `{0}`. {1}")]
|
||||||
NoxisDaemonMissing(String, String),
|
NoxisDaemonMissing(String, String),
|
||||||
|
|
@ -11,5 +12,5 @@ pub enum NoxisCliError {
|
||||||
#[error("Can't parse CLI struct and send as byte stream")]
|
#[error("Can't parse CLI struct and send as byte stream")]
|
||||||
ToStringCliParsingParsing,
|
ToStringCliParsingParsing,
|
||||||
#[error("Can't read Noxis response due to {0}")]
|
#[error("Can't read Noxis response due to {0}")]
|
||||||
CliResponseReadError(String)
|
CliResponseReadError(String),
|
||||||
}
|
}
|
||||||
|
|
@ -1,30 +1,37 @@
|
||||||
use tokio::net::UnixStream;
|
|
||||||
use tokio::io::{AsyncWriteExt, AsyncReadExt};
|
|
||||||
use tokio::time::{Duration, sleep};
|
|
||||||
use anyhow::Result;
|
|
||||||
use super::Cli;
|
|
||||||
use super::cli_error::NoxisCliError;
|
use super::cli_error::NoxisCliError;
|
||||||
|
use super::Cli;
|
||||||
|
use anyhow::Result;
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
use tokio::net::UnixStream;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
async fn create_us_stream(cli: &Cli) -> Result<UnixStream> {
|
async fn create_us_stream(cli: &Cli) -> Result<UnixStream> {
|
||||||
Ok(UnixStream::connect(&cli.socket).await.map_err(|er| NoxisCliError::NoxisDaemonMissing((&cli.socket).to_string(), er.to_string()))?)
|
Ok(UnixStream::connect(&cli.socket).await.map_err(|er| {
|
||||||
|
NoxisCliError::NoxisDaemonMissing((&cli.socket).to_string(), er.to_string())
|
||||||
|
})?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub async fn try_send(cli: Cli) -> Result<()> {
|
pub async fn try_send(cli: Cli) -> Result<()> {
|
||||||
// let stream = create_us_stream(&cli).await;
|
|
||||||
let mut stream = create_us_stream(&cli).await?;
|
let mut stream = create_us_stream(&cli).await?;
|
||||||
|
|
||||||
let msg = serde_json::to_vec(&cli)
|
let msg = serde_json::to_vec(&cli).map_err(|_| NoxisCliError::ToStringCliParsingParsing)?;
|
||||||
.map_err(|_| NoxisCliError::ToStringCliParsingParsing)?;
|
|
||||||
|
|
||||||
stream.write_all(&msg)
|
stream
|
||||||
|
.write_all(&msg)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| NoxisCliError::CliPromptCanNotBeSent)?;
|
.map_err(|_| NoxisCliError::CliPromptCanNotBeSent)?;
|
||||||
|
|
||||||
let mut response = [0; 1024];
|
let mut response = Vec::new();
|
||||||
stream.read(&mut response)
|
stream
|
||||||
|
.read_to_end(&mut response)
|
||||||
.await
|
.await
|
||||||
.map_err(|er| NoxisCliError::CliResponseReadError(er.to_string()))?;
|
.map_err(|er| NoxisCliError::CliResponseReadError(er.to_string()))?;
|
||||||
|
|
||||||
println!("{}", String::from_utf8_lossy(&response));
|
let response = String::from_utf8_lossy(&response);
|
||||||
|
for line in response.lines() {
|
||||||
|
println!("{}", line);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
mod cli;
|
mod cli;
|
||||||
mod cli_net;
|
|
||||||
mod cli_error;
|
mod cli_error;
|
||||||
|
mod cli_net;
|
||||||
|
|
||||||
pub use cli::*;
|
pub use cli::*;
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
mod cli;
|
mod cli;
|
||||||
mod cli_net;
|
|
||||||
mod cli_error;
|
mod cli_error;
|
||||||
|
mod cli_net;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use cli::Cli;
|
use cli::Cli;
|
||||||
use cli_net::try_send;
|
use cli_net::try_send;
|
||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,18 @@ mod options;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use options::logger::setup_logger;
|
|
||||||
use options::signals::set_valid_destructor;
|
|
||||||
use options::structs::Processes;
|
|
||||||
use options::cli_pipeline::init_cli_pipeline;
|
use options::cli_pipeline::init_cli_pipeline;
|
||||||
|
use options::config::v2::init_config_mechanism;
|
||||||
|
use options::logger::setup_logger;
|
||||||
|
use options::preboot::PrebootParams;
|
||||||
|
use options::signals::set_valid_destructor;
|
||||||
|
use options::structs::ProcessUnit;
|
||||||
|
use options::structs::{bus::BusMessage, Processes};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use options::preboot::PrebootParams;
|
use tokio::sync::{broadcast, mpsc, oneshot};
|
||||||
use tokio::sync::{broadcast, oneshot};
|
use utils::bus::Bus;
|
||||||
use options::config::v2::init_config_mechanism;
|
use utils::metrics::init_metrics_grubber;
|
||||||
use utils::v2::init_monitoring;
|
use utils::v2::init_monitoring;
|
||||||
|
|
||||||
#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
|
#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
|
||||||
|
|
@ -27,18 +30,39 @@ async fn main() -> anyhow::Result<()>{
|
||||||
let (tx_oneshot, rx_oneshot) = oneshot::channel::<Processes>();
|
let (tx_oneshot, rx_oneshot) = oneshot::channel::<Processes>();
|
||||||
let mut handler: Vec<tokio::task::JoinHandle<()>> = vec![];
|
let mut handler: Vec<tokio::task::JoinHandle<()>> = vec![];
|
||||||
|
|
||||||
|
// to BUS channel
|
||||||
|
let (tx_to_bus, rx_to_bus) = mpsc::channel::<BusMessage>(5);
|
||||||
|
// from BUS channels
|
||||||
|
let (tx_to_cli, rx_to_cli) = mpsc::channel::<BusMessage>(5);
|
||||||
|
let (tx_to_supervisor, rx_to_supervisor) = mpsc::channel::<BusMessage>(5);
|
||||||
|
let (tx_to_metrics, rx_to_metrics) = mpsc::channel::<BusMessage>(5);
|
||||||
|
|
||||||
|
let tx_to_bus = Arc::new(tx_to_bus);
|
||||||
|
let tx_to_cli = Arc::new(tx_to_cli);
|
||||||
|
let tx_to_supervisor = Arc::new(tx_to_supervisor);
|
||||||
|
let tx_to_metrics = Arc::new(tx_to_metrics);
|
||||||
|
|
||||||
|
let bus_module = tokio::spawn(async move {
|
||||||
|
let mut bus = Bus::new(
|
||||||
|
rx_to_bus,
|
||||||
|
tx_to_cli.clone(),
|
||||||
|
tx_to_supervisor.clone(),
|
||||||
|
tx_to_metrics.clone(),
|
||||||
|
);
|
||||||
|
bus.process().await;
|
||||||
|
error!("Info Bus crushed !");
|
||||||
|
});
|
||||||
|
handler.push(bus_module);
|
||||||
|
|
||||||
// initilaizing task for config manipulations
|
// initilaizing task for config manipulations
|
||||||
let preboot_config = preboot.clone();
|
let preboot_config = preboot.clone();
|
||||||
let config_module = tokio::spawn(async move {
|
let config_module = tokio::spawn(async move {
|
||||||
let _ = init_config_mechanism(
|
let _ = init_config_mechanism(rx_oneshot, tx_brd, preboot_config).await;
|
||||||
rx_oneshot,
|
|
||||||
tx_brd,
|
|
||||||
preboot_config
|
|
||||||
).await;
|
|
||||||
});
|
});
|
||||||
handler.push(config_module);
|
handler.push(config_module);
|
||||||
|
|
||||||
// initilaizing task for cli manipulation
|
// initilaizing task for cli manipulation
|
||||||
|
let tx_bus = tx_to_bus.clone();
|
||||||
let preboot_cli = preboot.clone();
|
let preboot_cli = preboot.clone();
|
||||||
let cli_module = tokio::spawn(async move {
|
let cli_module = tokio::spawn(async move {
|
||||||
let config = {
|
let config = {
|
||||||
|
|
@ -48,19 +72,32 @@ async fn main() -> anyhow::Result<()>{
|
||||||
break match rx_cli_brd.try_recv() {
|
break match rx_cli_brd.try_recv() {
|
||||||
Ok(conf) => conf,
|
Ok(conf) => conf,
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Err(er) = init_cli_pipeline(
|
if let Err(er) = init_cli_pipeline(
|
||||||
preboot_cli,
|
preboot_cli,
|
||||||
Arc::new(config),
|
Arc::new(config),
|
||||||
tx_oneshot
|
tx_oneshot,
|
||||||
).await {
|
rx_to_cli,
|
||||||
|
tx_bus.clone(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
error!("CLI pipeline failed due to {}", er)
|
error!("CLI pipeline failed due to {}", er)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
handler.push(cli_module);
|
handler.push(cli_module);
|
||||||
|
|
||||||
|
// metrics
|
||||||
|
let tx_bus = tx_to_bus.clone();
|
||||||
|
let metrics_module = tokio::spawn(async move {
|
||||||
|
if let Err(er) = init_metrics_grubber(tx_bus.clone(), rx_to_metrics).await {
|
||||||
|
error!("Metrics module crushed : {}", er);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
handler.push(metrics_module);
|
||||||
|
|
||||||
// initilaizing task for deinitializing `Noxis`
|
// initilaizing task for deinitializing `Noxis`
|
||||||
let ctrlc = tokio::spawn(async move {
|
let ctrlc = tokio::spawn(async move {
|
||||||
if let Err(er) = set_valid_destructor(vec![].into()).await {
|
if let Err(er) = set_valid_destructor(vec![].into()).await {
|
||||||
|
|
@ -70,6 +107,7 @@ async fn main() -> anyhow::Result<()>{
|
||||||
});
|
});
|
||||||
handler.push(ctrlc);
|
handler.push(ctrlc);
|
||||||
|
|
||||||
|
let tx_bus = tx_to_bus.clone();
|
||||||
let monitoring = tokio::spawn(async move {
|
let monitoring = tokio::spawn(async move {
|
||||||
let config = {
|
let config = {
|
||||||
let mut tick = tokio::time::interval(Duration::from_millis(500));
|
let mut tick = tokio::time::interval(Duration::from_millis(500));
|
||||||
|
|
@ -78,10 +116,10 @@ async fn main() -> anyhow::Result<()>{
|
||||||
break match rx_brd.try_recv() {
|
break match rx_brd.try_recv() {
|
||||||
Ok(conf) => conf,
|
Ok(conf) => conf,
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Err(er) = init_monitoring(config).await {
|
if let Err(er) = init_monitoring(config, rx_to_supervisor, tx_bus).await {
|
||||||
error!("Monitoring mod failed due to {}", er);
|
error!("Monitoring mod failed due to {}", er);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -90,80 +128,5 @@ async fn main() -> anyhow::Result<()>{
|
||||||
for i in handler {
|
for i in handler {
|
||||||
let _ = i.await;
|
let _ = i.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// setting up redis connection \
|
|
||||||
// then conf checks to choose the most actual \
|
|
||||||
// let processes: Processes = get_actual_config(preboot.clone()).await.unwrap_or_else(|| {
|
|
||||||
// error!("No actual configuration for runner. Stopping...");
|
|
||||||
// std::process::exit(1);
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// info!(
|
|
||||||
// "Current runner configuration: {}",
|
|
||||||
// &processes.date_of_creation
|
|
||||||
// );
|
|
||||||
// info!("Runner is ready. Initializing...");
|
|
||||||
//
|
|
||||||
// if processes.processes.is_empty() {
|
|
||||||
// error!("Processes list is null, runner-rs initialization is stopped");
|
|
||||||
// return Err(Error::msg("Empty processes segment in config"));
|
|
||||||
// }
|
|
||||||
// let mut handler: Vec<tokio::task::JoinHandle<()>> = vec![];
|
|
||||||
// // is in need to send to the signals handler thread
|
|
||||||
// let mut senders: Vec<Arc<mpsc::Sender<u8>>> = vec![];
|
|
||||||
//
|
|
||||||
// for proc in processes.processes.iter() {
|
|
||||||
// info!(
|
|
||||||
// "Process '{}' on stage: {}. Depends on {} file(s), {} service(s)",
|
|
||||||
// proc.name,
|
|
||||||
// proc.path,
|
|
||||||
// proc.dependencies.files.len(),
|
|
||||||
// proc.dependencies.services.len()
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// // creating msg channel
|
|
||||||
// // can or should be executed in new thread
|
|
||||||
// let (tx, mut rx) = mpsc::channel::<u8>(1);
|
|
||||||
// let proc = Arc::new(proc.clone());
|
|
||||||
// let tx = Arc::new(tx.clone());
|
|
||||||
//
|
|
||||||
// senders.push(Arc::clone(&tx.clone()));
|
|
||||||
//
|
|
||||||
// let event = tokio::spawn(async move {
|
|
||||||
// run_daemons(proc.clone(), tx.clone(), &mut rx).await;
|
|
||||||
// });
|
|
||||||
// handler.push(event);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // destructor addition
|
|
||||||
// handler.push(tokio::spawn(async move {
|
|
||||||
// if set_valid_destructor(Arc::new(senders)).await.is_err() {
|
|
||||||
// error!("Linux signals handler creation failed. Terminating main thread...");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// tokio::time::sleep(Duration::from_millis(200)).await;
|
|
||||||
// info!("End of job. Terminating main thread...");
|
|
||||||
// std::process::exit(0);
|
|
||||||
// }));
|
|
||||||
//
|
|
||||||
// // remote config update subscription
|
|
||||||
// handler.push(tokio::spawn(async move {
|
|
||||||
// let _ = subscribe_config_stream(Arc::new(processes), preboot.clone()).await;
|
|
||||||
// }));
|
|
||||||
//
|
|
||||||
// // cli pipeline
|
|
||||||
// handler.push(tokio::spawn(async move {
|
|
||||||
// let _ = init_cli_pipeline().await;
|
|
||||||
// }));
|
|
||||||
//
|
|
||||||
// for i in handler {
|
|
||||||
// let _ = i.await;
|
|
||||||
// }
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: integration tests
|
|
||||||
// todo: config pulling mechanism rework (socket)
|
|
||||||
// todo: tasks management after killing all processes
|
|
||||||
// todo:
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// ! gathering optional items module
|
// ! gathering optional items module
|
||||||
|
|
||||||
|
pub mod cli_pipeline;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
|
pub mod preboot;
|
||||||
pub mod signals;
|
pub mod signals;
|
||||||
pub mod structs;
|
pub mod structs;
|
||||||
pub mod preboot;
|
|
||||||
pub mod cli_pipeline;
|
|
||||||
|
|
@ -1,17 +1,23 @@
|
||||||
|
use super::structs::bus::BusMessage;
|
||||||
|
use super::structs::Processes;
|
||||||
|
use crate::options::structs::bus::InternalCli;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use tokio::net::{ UnixStream, UnixListener };
|
use noxis_cli::{Cli, ProcessAction};
|
||||||
use tokio::sync::{Mutex, OnceCell};
|
use std::any::Any;
|
||||||
use tokio::time::{sleep, Duration};
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::io::{ AsyncWriteExt, AsyncReadExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use noxis_cli::Cli;
|
use tokio::net::{UnixListener, UnixStream};
|
||||||
use super::structs::Processes;
|
use tokio::sync::{Mutex, OnceCell};
|
||||||
|
use tokio::time::{sleep, Duration};
|
||||||
|
|
||||||
use super::preboot::PrebootParams;
|
use super::preboot::PrebootParams;
|
||||||
|
|
||||||
type ConfigGateway = tokio::sync::oneshot::Sender<Processes>;
|
type ConfigGateway = tokio::sync::oneshot::Sender<Processes>;
|
||||||
type ProcessedConfigGateway = Arc<Mutex<OnceCell<ConfigGateway>>>;
|
type ProcessedConfigGateway = Arc<Mutex<OnceCell<ConfigGateway>>>;
|
||||||
|
type BusReciever = tokio::sync::mpsc::Receiver<BusMessage>;
|
||||||
|
type BusSender = Arc<tokio::sync::mpsc::Sender<BusMessage>>;
|
||||||
|
type ReadyBusReciever = Arc<Mutex<tokio::sync::mpsc::Receiver<BusMessage>>>;
|
||||||
|
|
||||||
/// # Fn `init_cli_pipeline`
|
/// # Fn `init_cli_pipeline`
|
||||||
/// ## for catching all input requests from CLI
|
/// ## for catching all input requests from CLI
|
||||||
|
|
@ -30,15 +36,14 @@ pub async fn init_cli_pipeline(
|
||||||
params: Arc<PrebootParams>,
|
params: Arc<PrebootParams>,
|
||||||
config: Arc<Processes>,
|
config: Arc<Processes>,
|
||||||
config_gateway: ConfigGateway,
|
config_gateway: ConfigGateway,
|
||||||
|
bus_reciever: BusReciever,
|
||||||
|
bus_sender: BusSender,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let socket_path = ¶ms.self_socket;
|
let socket_path = ¶ms.self_socket;
|
||||||
let _ = fs::remove_file(socket_path);
|
let _ = fs::remove_file(socket_path);
|
||||||
|
|
||||||
let config_gateway = Arc::new(
|
let config_gateway = Arc::new(Mutex::new(OnceCell::new_with(Some(config_gateway))));
|
||||||
Mutex::new(
|
let bus_reciever = Arc::new(Mutex::new(bus_reciever));
|
||||||
OnceCell::new_with(Some(config_gateway))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
match UnixListener::bind(socket_path) {
|
match UnixListener::bind(socket_path) {
|
||||||
Ok(list) => {
|
Ok(list) => {
|
||||||
|
|
@ -52,22 +57,32 @@ pub async fn init_cli_pipeline(
|
||||||
let params = params.clone();
|
let params = params.clone();
|
||||||
let config = config.clone();
|
let config = config.clone();
|
||||||
let config_gateway = config_gateway.clone();
|
let config_gateway = config_gateway.clone();
|
||||||
|
let bus_reciever = bus_reciever.clone();
|
||||||
|
let bus_sender = bus_sender.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
process_connection(socket, params.clone(), config.clone(), config_gateway.clone()).await;
|
process_connection(
|
||||||
|
socket,
|
||||||
|
params.clone(),
|
||||||
|
config.clone(),
|
||||||
|
config_gateway.clone(),
|
||||||
|
bus_reciever,
|
||||||
|
bus_sender,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
Err(er) => {
|
Err(er) => {
|
||||||
error!("Cannot poll connection to CLI due to {}", er);
|
error!("Cannot poll connection to CLI due to {}", er);
|
||||||
sleep(Duration::from_millis(300)).await;
|
sleep(Duration::from_millis(300)).await;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ok(())
|
// Ok(())
|
||||||
},
|
}
|
||||||
Err(er) => {
|
Err(er) => {
|
||||||
error!("Failed to open UnixListener for CLI");
|
error!("Failed to open UnixListener for CLI");
|
||||||
Err(er.into())
|
Err(er.into())
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,44 +99,66 @@ pub async fn init_cli_pipeline(
|
||||||
///
|
///
|
||||||
/// *depends on* : `tokio::net::TcpStream`
|
/// *depends on* : `tokio::net::TcpStream`
|
||||||
///
|
///
|
||||||
async fn process_connection(mut stream: UnixStream, params: Arc<PrebootParams>, config : Arc<Processes>, cfg_gateway : ProcessedConfigGateway) {
|
async fn process_connection(
|
||||||
|
mut stream: UnixStream,
|
||||||
|
params: Arc<PrebootParams>,
|
||||||
|
config: Arc<Processes>,
|
||||||
|
cfg_gateway: ProcessedConfigGateway,
|
||||||
|
bus_reciever: ReadyBusReciever,
|
||||||
|
bus_sender: BusSender,
|
||||||
|
) {
|
||||||
let mut buf = vec![0; 1024];
|
let mut buf = vec![0; 1024];
|
||||||
match stream.read(&mut buf).await {
|
match stream.read(&mut buf).await {
|
||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
info!("Client disconnected ");
|
info!("Client disconnected ");
|
||||||
},
|
}
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
buf.truncate(n);
|
buf.truncate(n);
|
||||||
info!("CLI have sent {} bytes", n);
|
info!("CLI have sent {} bytes", n);
|
||||||
match serde_json::from_slice::<Cli>(&buf) {
|
match serde_json::from_slice::<Cli>(&buf) {
|
||||||
Ok(cli) => {
|
Ok(cli) => {
|
||||||
info!("Received CLI request: {:?}", cli);
|
info!("Received CLI request: {:?}", cli);
|
||||||
let response = match process_cli_cmd(cli, params.clone(), config, cfg_gateway.clone()).await {
|
let response = match process_cli_cmd(
|
||||||
Ok(response) => {
|
cli,
|
||||||
response
|
params.clone(),
|
||||||
},
|
config,
|
||||||
|
cfg_gateway.clone(),
|
||||||
|
bus_reciever.clone(),
|
||||||
|
bus_sender.clone(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => response,
|
||||||
Err(er) => {
|
Err(er) => {
|
||||||
let error_msg = format!("Error: {}", er);
|
let error_msg = format!("Error: {}", er);
|
||||||
error!("{}", &error_msg);
|
error!("{}", &error_msg);
|
||||||
error_msg
|
error_msg
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
if let Err(e) = stream.write_all(response.as_bytes()).await {
|
for line in response.lines() {
|
||||||
error!("Failed to send response: {}", e);
|
if let Err(er) = stream.write_all(line.as_bytes()).await {
|
||||||
|
error!("Failed to send response: {}", er);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to parse CLI request: {}", e);
|
error!("Failed to parse CLI request: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(e) => error!("Failed to read from socket: {}", e),
|
Err(e) => error!("Failed to read from socket: {}", e),
|
||||||
}
|
}
|
||||||
let _ = stream.shutdown().await;
|
let _ = stream.shutdown().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn process_cli_cmd(
|
||||||
async fn process_cli_cmd(cli : Cli, params: Arc<PrebootParams>, global_config : Arc<Processes>, cfg_gateway: ProcessedConfigGateway) -> anyhow::Result<String> {
|
cli: Cli,
|
||||||
|
params: Arc<PrebootParams>,
|
||||||
|
global_config: Arc<Processes>,
|
||||||
|
cfg_gateway: ProcessedConfigGateway,
|
||||||
|
bus_reciever: ReadyBusReciever,
|
||||||
|
bus_sender: BusSender,
|
||||||
|
) -> anyhow::Result<String> {
|
||||||
use noxis_cli::{Commands, ConfigAction};
|
use noxis_cli::{Commands, ConfigAction};
|
||||||
return match cli.command {
|
return match cli.command {
|
||||||
Commands::Config(config) => {
|
Commands::Config(config) => {
|
||||||
|
|
@ -133,10 +170,10 @@ async fn process_cli_cmd(cli : Cli, params: Arc<PrebootParams>, global_config :
|
||||||
/* */
|
/* */
|
||||||
Ok(serde_json::to_string_pretty(global_config.as_ref())?)
|
Ok(serde_json::to_string_pretty(global_config.as_ref())?)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
ConfigAction::Reset => {
|
ConfigAction::Reset => Err(anyhow::Error::msg(
|
||||||
Err(anyhow::Error::msg("It's temporarly forbidden to reset current config using CLI-util"))
|
"It's temporarly forbidden to reset current config using CLI-util",
|
||||||
},
|
)),
|
||||||
ConfigAction::Local(cfg) => {
|
ConfigAction::Local(cfg) => {
|
||||||
if cfg.is_json {
|
if cfg.is_json {
|
||||||
/* */
|
/* */
|
||||||
|
|
@ -153,25 +190,161 @@ async fn process_cli_cmd(cli : Cli, params: Arc<PrebootParams>, global_config :
|
||||||
match lock.take() {
|
match lock.take() {
|
||||||
Some(channel) => {
|
Some(channel) => {
|
||||||
let _ = channel.send(new_config);
|
let _ = channel.send(new_config);
|
||||||
},
|
}
|
||||||
None => error!("Cannot update confif due to channel sender loss"),
|
None => error!(
|
||||||
|
"Cannot update confif due to channel sender loss"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Ok(format!("Ok. Saving and reloading with version {}", new_version))
|
Ok(format!(
|
||||||
},
|
"Ok. Saving and reloading with version {}",
|
||||||
_ => Err(anyhow::Error::msg(format!("Local config (version: {}) is more actual", global_config.get_version()))),
|
new_version
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
_ => Err(anyhow::Error::msg(format!(
|
||||||
|
"Local config (version: {}) is more actual",
|
||||||
|
global_config.get_version()
|
||||||
|
))),
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow::Error::msg("It's temporarly forbidden to set config in non-json mode"))
|
Err(anyhow::Error::msg(
|
||||||
|
"It's temporarly forbidden to set config in non-json mode",
|
||||||
|
))
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
ConfigAction::Remote => {Ok(params.remote_server_url.clone())},
|
ConfigAction::Remote => Ok(params.remote_server_url.clone()),
|
||||||
/* */
|
/* */
|
||||||
// _ => Err(anyhow::Error::msg("Unrecognized command from CLI"))
|
// _ => Err(anyhow::Error::msg("Unrecognized command from CLI"))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Commands::Processes => {
|
||||||
|
use crate::options::structs::bus::{BusMessageContentType, BusMessageDirection};
|
||||||
|
use crate::utils::metrics::processes::ProcessesQuery;
|
||||||
|
|
||||||
|
let _ = bus_sender
|
||||||
|
.send(BusMessage::Request(
|
||||||
|
BusMessageDirection::ToSupervisor,
|
||||||
|
BusMessageContentType::ProcessQuery,
|
||||||
|
Box::new(ProcessesQuery::QueryAll),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let mut bus = bus_reciever.lock().await;
|
||||||
|
let resp = tokio::time::timeout(std::time::Duration::from_secs(5), async move {
|
||||||
|
loop {
|
||||||
|
if let Ok(cont) = bus.try_recv() {
|
||||||
|
return cont;
|
||||||
|
}
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let BusMessage::Response(_, _, content) = resp {
|
||||||
|
let content: Box<dyn Any> = content;
|
||||||
|
if let Ok(resp) = content.downcast::<anyhow::Result<String>>() {
|
||||||
|
return Ok((*resp)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(anyhow::Error::msg(format!(
|
||||||
|
"Unknown type of response from the Supervisor"
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
Commands::Process(prc) => {
|
||||||
|
use crate::options::structs::bus::{
|
||||||
|
BusMessageContentType, BusMessageDirection, CLiCommand,
|
||||||
|
};
|
||||||
|
|
||||||
|
let proc_name = prc.process;
|
||||||
|
let req = BusMessage::Request(
|
||||||
|
BusMessageDirection::ToSupervisor,
|
||||||
|
BusMessageContentType::Cli,
|
||||||
|
Box::new(match prc.action {
|
||||||
|
ProcessAction::Start => InternalCli {
|
||||||
|
prc: proc_name,
|
||||||
|
cmd: CLiCommand::Start,
|
||||||
},
|
},
|
||||||
/* */
|
ProcessAction::Stop => InternalCli {
|
||||||
|
prc: proc_name,
|
||||||
|
cmd: CLiCommand::Stop,
|
||||||
|
},
|
||||||
|
ProcessAction::Restart => InternalCli {
|
||||||
|
prc: proc_name,
|
||||||
|
cmd: CLiCommand::Restart,
|
||||||
|
},
|
||||||
|
ProcessAction::Freeze => InternalCli {
|
||||||
|
prc: proc_name,
|
||||||
|
cmd: CLiCommand::Freeze,
|
||||||
|
},
|
||||||
|
ProcessAction::Unfreeze => InternalCli {
|
||||||
|
prc: proc_name,
|
||||||
|
cmd: CLiCommand::Unfreeze,
|
||||||
|
},
|
||||||
|
/* TODO: ALL CMDS */
|
||||||
|
_ => InternalCli {
|
||||||
|
prc: proc_name,
|
||||||
|
cmd: CLiCommand::Restart,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
let mut bus = bus_reciever.lock().await;
|
||||||
|
bus_sender.send(req).await?;
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
||||||
|
let resp = tokio::time::timeout(std::time::Duration::from_secs(5), async move {
|
||||||
|
loop {
|
||||||
|
if let Ok(cont) = bus.try_recv() {
|
||||||
|
return cont;
|
||||||
|
}
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let BusMessage::Response(_, _, content) = resp {
|
||||||
|
let content: Box<dyn Any> = content;
|
||||||
|
if let Ok(resp) = content.downcast::<anyhow::Result<String>>() {
|
||||||
|
return Ok((*resp)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(anyhow::Error::msg(format!(
|
||||||
|
"Unknown type of response from the Supervisor"
|
||||||
|
)))
|
||||||
|
}
|
||||||
Commands::Status => Ok(String::from("Ok")),
|
Commands::Status => Ok(String::from("Ok")),
|
||||||
_ => Ok(String::from("Ok"))
|
Commands::Inspect(mode) => {
|
||||||
|
use crate::options::structs::bus::{BusMessageContentType, BusMessageDirection};
|
||||||
|
let mode = mode.mode;
|
||||||
|
if let Ok(()) = bus_sender
|
||||||
|
.send(BusMessage::Request(
|
||||||
|
BusMessageDirection::ToMetrics,
|
||||||
|
BusMessageContentType::MetricsModeTransfered,
|
||||||
|
Box::new(mode),
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
let mut bus_reciever = bus_reciever.lock().await;
|
||||||
|
sleep(Duration::from_millis(300)).await;
|
||||||
|
let resp = tokio::time::timeout(std::time::Duration::from_secs(5), async move {
|
||||||
|
loop {
|
||||||
|
if let Ok(cont) = bus_reciever.try_recv() {
|
||||||
|
return cont;
|
||||||
|
}
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
if let BusMessage::Response(_, _, content) = resp {
|
||||||
|
let content: Box<dyn Any> = content;
|
||||||
|
if let Ok(resp) = content.downcast::<anyhow::Result<String>>() {
|
||||||
|
return Ok((*resp)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return Err(anyhow::Error::msg(format!(
|
||||||
|
"Unknown type of response from CLI"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Ok(String::from("Ok"))
|
||||||
|
}
|
||||||
|
_ => Ok(String::from("Ok")),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,29 @@
|
||||||
|
use super::preboot::PrebootParams;
|
||||||
use super::structs::*;
|
use super::structs::*;
|
||||||
|
use crate::utils::files::create_watcher;
|
||||||
|
use inotify::EventMask;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use redis::{Client, Connection};
|
use redis::{Client, Connection};
|
||||||
|
use std::fs::File;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::os::unix::process::CommandExt;
|
use std::os::unix::process::CommandExt;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
use super::preboot::PrebootParams;
|
|
||||||
use tokio::time::{Duration, sleep};
|
|
||||||
// use redis::PubSub;
|
|
||||||
use tokio::sync::{
|
use tokio::sync::{
|
||||||
|
broadcast::Receiver as BroadcastReceiver,
|
||||||
|
broadcast::Sender as BroadcastSender,
|
||||||
oneshot,
|
oneshot,
|
||||||
oneshot::{Receiver as OneShotReciever, Sender as OneShotSender},
|
oneshot::{Receiver as OneShotReciever, Sender as OneShotSender},
|
||||||
broadcast::Sender as BroadcastSender, broadcast::Receiver as BroadcastReceiver };
|
};
|
||||||
use crate::utils::files::create_watcher;
|
use tokio::time::{sleep, Duration};
|
||||||
use std::fs::File;
|
|
||||||
use inotify::EventMask;
|
|
||||||
|
|
||||||
// const CONFIG_PATH: &str = "settings.json";
|
// const CONFIG_PATH: &str = "settings.json";
|
||||||
|
|
||||||
pub mod v2 {
|
pub mod v2 {
|
||||||
use std::path::PathBuf;
|
|
||||||
use crate::utils::get_container_id;
|
use crate::utils::get_container_id;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
@ -32,8 +33,7 @@ pub mod v2 {
|
||||||
// to share local config with PRCS, CLI_PIPELINE and CONFIG modules
|
// to share local config with PRCS, CLI_PIPELINE and CONFIG modules
|
||||||
brd_tx: BroadcastSender<Processes>,
|
brd_tx: BroadcastSender<Processes>,
|
||||||
// preboot params (args)
|
// preboot params (args)
|
||||||
params : Arc<PrebootParams>
|
params: Arc<PrebootParams>, /*...*/
|
||||||
/*...*/
|
|
||||||
) {
|
) {
|
||||||
// channel for pubsub to handle local config pulling
|
// channel for pubsub to handle local config pulling
|
||||||
let local_config_brd_reciever = brd_tx.subscribe();
|
let local_config_brd_reciever = brd_tx.subscribe();
|
||||||
|
|
@ -45,40 +45,24 @@ pub mod v2 {
|
||||||
// dbg!("before lc");
|
// dbg!("before lc");
|
||||||
let params_clone = params.clone();
|
let params_clone = params.clone();
|
||||||
let for_lc_path = params.clone();
|
let for_lc_path = params.clone();
|
||||||
let lc_path = for_lc_path
|
let lc_path = for_lc_path.config.to_str().unwrap_or("settings.json");
|
||||||
.config
|
|
||||||
.to_str()
|
|
||||||
.unwrap_or("settings.json");
|
|
||||||
|
|
||||||
// future to init work with local config
|
// future to init work with local config
|
||||||
let lc_future = tokio::spawn(
|
let lc_future = tokio::spawn(
|
||||||
// let params = params.clone();
|
// let params = params.clone();
|
||||||
local_config_reciever(
|
local_config_reciever(params_clone, rx_pb_lc, rx_cli_lc, Arc::new(brd_tx)),
|
||||||
params_clone,
|
|
||||||
rx_pb_lc,
|
|
||||||
rx_cli_lc,
|
|
||||||
Arc::new(brd_tx)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
// dbg!("before pb");
|
// dbg!("before pb");
|
||||||
// future to init work with pub sub mechanism
|
// future to init work with pub sub mechanism
|
||||||
let pubsub_future = tokio::spawn(
|
let pubsub_future = tokio::spawn(pubsub_config_reciever(
|
||||||
pubsub_config_reciever(
|
|
||||||
tx_pb_lc,
|
tx_pb_lc,
|
||||||
params.clone(),
|
params.clone(),
|
||||||
local_config_brd_reciever
|
local_config_brd_reciever,
|
||||||
)
|
));
|
||||||
);
|
|
||||||
|
|
||||||
// dbg!("before cli");
|
// dbg!("before cli");
|
||||||
// future to catch new configs from cli pipeline
|
// future to catch new configs from cli pipeline
|
||||||
let cli_future = tokio::spawn(
|
let cli_future = tokio::spawn(from_cli_config_reciever(cli_oneshot, tx_cli_lc));
|
||||||
from_cli_config_reciever(
|
|
||||||
cli_oneshot,
|
|
||||||
tx_cli_lc
|
|
||||||
)
|
|
||||||
|
|
||||||
);
|
|
||||||
// let _ = lc_future.await;
|
// let _ = lc_future.await;
|
||||||
// dbg!("before select");
|
// dbg!("before select");
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
|
@ -141,7 +125,10 @@ pub mod v2 {
|
||||||
pub async fn get_redis_connection(params: &str) -> Option<Connection> {
|
pub async fn get_redis_connection(params: &str) -> Option<Connection> {
|
||||||
for i in 1..=3 {
|
for i in 1..=3 {
|
||||||
let redis_url = format!("redis://{}/", params);
|
let redis_url = format!("redis://{}/", params);
|
||||||
info!("Trying to connect Redis pubsub `{}`. Attempt {}", &redis_url, i);
|
info!(
|
||||||
|
"Trying to connect Redis pubsub `{}`. Attempt {}",
|
||||||
|
&redis_url, i
|
||||||
|
);
|
||||||
if let Ok(client) = Client::open(redis_url) {
|
if let Ok(client) = Client::open(redis_url) {
|
||||||
if let Ok(conn) = client.get_connection() {
|
if let Ok(conn) = client.get_connection() {
|
||||||
info!("Successfully opened Redis connection");
|
info!("Successfully opened Redis connection");
|
||||||
|
|
@ -181,14 +168,19 @@ pub mod v2 {
|
||||||
Some(mut conn) => {
|
Some(mut conn) => {
|
||||||
let mut pub_sub = conn.as_pubsub();
|
let mut pub_sub = conn.as_pubsub();
|
||||||
let channel_name = get_container_id().unwrap_or(String::from("default"));
|
let channel_name = get_container_id().unwrap_or(String::from("default"));
|
||||||
let channel_name = channel_name.trim();
|
match pub_sub.subscribe(&channel_name) {
|
||||||
match pub_sub.subscribe(channel_name) {
|
|
||||||
Err(er) => {
|
Err(er) => {
|
||||||
error!("Cannot subscribe pubsub channel due to {}", &er);
|
error!("Cannot subscribe pubsub channel due to {}", &er);
|
||||||
return Err(anyhow::Error::msg(format!("Cannot subscribe pubsub channel due to {}", er)))
|
return Err(anyhow::Error::msg(format!(
|
||||||
},
|
"Cannot subscribe pubsub channel due to {}",
|
||||||
|
er
|
||||||
|
)));
|
||||||
|
}
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
info!("Successfully subscribed to {} pubsub channel", channel_name);
|
info!(
|
||||||
|
"Successfully subscribed to {} pubsub channel",
|
||||||
|
&channel_name
|
||||||
|
);
|
||||||
let _ = pub_sub.set_read_timeout(Some(Duration::from_secs(1)));
|
let _ = pub_sub.set_read_timeout(Some(Duration::from_secs(1)));
|
||||||
loop {
|
loop {
|
||||||
if let Ok(msg) = pub_sub.get_message() {
|
if let Ok(msg) = pub_sub.get_message() {
|
||||||
|
|
@ -227,9 +219,9 @@ pub mod v2 {
|
||||||
// delay
|
// delay
|
||||||
tokio::task::yield_now().await;
|
tokio::task::yield_now().await;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
sleep(Duration::from_secs(20)).await;
|
sleep(Duration::from_secs(20)).await;
|
||||||
}
|
}
|
||||||
|
|
@ -252,10 +244,7 @@ pub mod v2 {
|
||||||
// fill with default empty config, mut to change later
|
// fill with default empty config, mut to change later
|
||||||
let mut _current_config = Processes::default();
|
let mut _current_config = Processes::default();
|
||||||
// PathBuf to &str to work with local config path as slice
|
// PathBuf to &str to work with local config path as slice
|
||||||
let local_config_path = params
|
let local_config_path = params.config.to_str().unwrap_or("settings.json");
|
||||||
.config
|
|
||||||
.to_str()
|
|
||||||
.unwrap_or("settings.json");
|
|
||||||
|
|
||||||
match load_processes(local_config_path) {
|
match load_processes(local_config_path) {
|
||||||
// if local exists
|
// if local exists
|
||||||
|
|
@ -265,13 +254,13 @@ pub mod v2 {
|
||||||
if let Err(er) = brd_tx.send(_current_config.clone()) {
|
if let Err(er) = brd_tx.send(_current_config.clone()) {
|
||||||
error!("Cannot share local config with broadcast due to {}", er);
|
error!("Cannot share local config with broadcast due to {}", er);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
// if local is not exist
|
// if local is not exist
|
||||||
None => {
|
None => {
|
||||||
warn!("Local config wasn't found. Waiting for new ...");
|
warn!("Local config wasn't found. Waiting for new ...");
|
||||||
return Err(anyhow::Error::msg("No local config"));
|
return Err(anyhow::Error::msg("No local config"));
|
||||||
// ...
|
// ...
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 100% local exists here
|
// 100% local exists here
|
||||||
|
|
@ -330,7 +319,9 @@ pub mod v2 {
|
||||||
}
|
}
|
||||||
// exporting data
|
// exporting data
|
||||||
if need_to_export_config {
|
if need_to_export_config {
|
||||||
if let Err(er) = export_saved_config_data_locally(¶ms.config, &_current_config).await {
|
if let Err(er) =
|
||||||
|
export_saved_config_data_locally(¶ms.config, &_current_config).await
|
||||||
|
{
|
||||||
error!("Cannot save actual imported config due to {}", er);
|
error!("Cannot save actual imported config due to {}", er);
|
||||||
} else {
|
} else {
|
||||||
// recreation watcher (draining activity buffer mechanism)
|
// recreation watcher (draining activity buffer mechanism)
|
||||||
|
|
@ -345,19 +336,20 @@ pub mod v2 {
|
||||||
sleep(Duration::from_millis(300)).await;
|
sleep(Duration::from_millis(300)).await;
|
||||||
// tokio::task::yield_now().await;
|
// tokio::task::yield_now().await;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
error!("Cannot create watcher on local config file `{}`. Deinitializing warding local config mechanism...", local_config_path);
|
error!("Cannot create watcher on local config file `{}`. Deinitializing warding local config mechanism...", local_config_path);
|
||||||
return Err(anyhow::Error::msg("Cannot create watcher on local config file"));
|
return Err(anyhow::Error::msg(
|
||||||
},
|
"Cannot create watcher on local config file",
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// [:IN-TEST]
|
// [:IN-TEST]
|
||||||
async fn from_cli_config_reciever(
|
async fn from_cli_config_reciever(
|
||||||
cli_oneshot: OneShotReciever<Processes>,
|
cli_oneshot: OneShotReciever<Processes>,
|
||||||
to_local_tx: OneShotSender<bool>
|
to_local_tx: OneShotSender<bool>,
|
||||||
) -> Option<Processes> {
|
) -> Option<Processes> {
|
||||||
/* match awaits til channel*/
|
/* match awaits til channel*/
|
||||||
// dbg!("start of cli");
|
// dbg!("start of cli");
|
||||||
|
|
@ -365,33 +357,31 @@ pub mod v2 {
|
||||||
if !cli_oneshot.is_empty() {
|
if !cli_oneshot.is_empty() {
|
||||||
match cli_oneshot.await {
|
match cli_oneshot.await {
|
||||||
Ok(config_from_cli) => {
|
Ok(config_from_cli) => {
|
||||||
info!("New actual config `{}` from CLI was pulled. Saving and restaring ...", &config_from_cli.date_of_creation);
|
info!(
|
||||||
|
"New actual config `{}` from CLI was pulled. Saving and restaring ...",
|
||||||
|
&config_from_cli.date_of_creation
|
||||||
|
);
|
||||||
let _ = to_local_tx.send(true);
|
let _ = to_local_tx.send(true);
|
||||||
return Some(config_from_cli)
|
return Some(config_from_cli);
|
||||||
},
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sleep(Duration::from_millis(300)).await;
|
sleep(Duration::from_millis(300)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn export_saved_config_data_locally(
|
async fn export_saved_config_data_locally(
|
||||||
config_file_path: &PathBuf,
|
config_file_path: &PathBuf,
|
||||||
current_config: &Processes
|
current_config: &Processes,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
|
||||||
let mut file = File::create(config_file_path)?;
|
let mut file = File::create(config_file_path)?;
|
||||||
file.write_all(
|
file.write_all(serde_json::to_string_pretty(current_config)?.as_bytes())?;
|
||||||
serde_json::to_string_pretty(current_config)?.as_bytes()
|
|
||||||
)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
// Ok(())
|
// Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// # Fn `load_processes`
|
/// # Fn `load_processes`
|
||||||
/// ## for reading and parsing *local* storing config
|
/// ## for reading and parsing *local* storing config
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,7 @@ trait FromEnv {
|
||||||
impl FromEnv for LevelFilter {
|
impl FromEnv for LevelFilter {
|
||||||
fn from_env() -> LevelFilter {
|
fn from_env() -> LevelFilter {
|
||||||
return match std::env::var("NOXIS_MAX_LOG_LEVEL") {
|
return match std::env::var("NOXIS_MAX_LOG_LEVEL") {
|
||||||
Ok(var) => {
|
Ok(var) => match var.to_ascii_lowercase().trim().as_ref() {
|
||||||
match var.to_ascii_lowercase().trim().as_ref() {
|
|
||||||
"trace" => LevelFilter::Trace,
|
"trace" => LevelFilter::Trace,
|
||||||
"debug" => LevelFilter::Debug,
|
"debug" => LevelFilter::Debug,
|
||||||
"info" => LevelFilter::Info,
|
"info" => LevelFilter::Info,
|
||||||
|
|
@ -74,10 +73,9 @@ impl FromEnv for LevelFilter {
|
||||||
"warn" => LevelFilter::Warn,
|
"warn" => LevelFilter::Warn,
|
||||||
"off" => LevelFilter::Off,
|
"off" => LevelFilter::Off,
|
||||||
_ => LevelFilter::Info,
|
_ => LevelFilter::Info,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Err(_) => LevelFilter::Info,
|
Err(_) => LevelFilter::Info,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
//! Module to handle `pre-boot params` of the monitor (calling also as `settings`)
|
//! Module to handle `pre-boot params` of the monitor (calling also as `settings`)
|
||||||
//!
|
//!
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use anyhow::{Result, Error};
|
use anyhow::{Error, Result};
|
||||||
use log::warn;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::env::var;
|
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
|
use log::warn;
|
||||||
|
use std::env::var;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// # Enum `MetricsPrebootParams`
|
/// # Enum `MetricsPrebootParams`
|
||||||
/// ## for setting up metrics mode as preboot param from command prompt
|
/// ## for setting up metrics mode as preboot param from command prompt
|
||||||
|
|
@ -257,17 +257,20 @@ impl PrebootParams {
|
||||||
match var("NOXIS_SOCKET_PATH") {
|
match var("NOXIS_SOCKET_PATH") {
|
||||||
Ok(val) => PathBuf::from(val),
|
Ok(val) => PathBuf::from(val),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let default = std::env::current_dir().expect("Crushed on getting current_dir path. Check fs state!");
|
let default = std::env::current_dir()
|
||||||
warn!("$NOXIS_SOCKET_PATH wans't set. Default value - {}", default.display());
|
.expect("Crushed on getting current_dir path. Check fs state!");
|
||||||
|
warn!(
|
||||||
|
"$NOXIS_SOCKET_PATH wans't set. Default value - {}",
|
||||||
|
default.display()
|
||||||
|
);
|
||||||
PathBuf::from(default)
|
PathBuf::from(default)
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// unit tests of preboot params parsing mech
|
// unit tests of preboot params parsing mech
|
||||||
// #[cfg(test)]
|
// #[cfg(test)]
|
||||||
// mod preboot_unitests{
|
// mod preboot_unitests{
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,110 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::any::Any;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub mod bus {
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::utils::metrics::processes::ProcessesQuery;
|
||||||
|
use crate::utils::metrics::MetricsExportable;
|
||||||
|
use noxis_cli::{metrics_models::MetricsMode, Cli};
|
||||||
|
pub type BusMessageContent = Box<dyn BusContent>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum BusMessage {
|
||||||
|
Request(
|
||||||
|
BusMessageDirection,
|
||||||
|
BusMessageContentType,
|
||||||
|
BusMessageContent,
|
||||||
|
),
|
||||||
|
Response(
|
||||||
|
BusMessageDirection,
|
||||||
|
BusMessageContentType,
|
||||||
|
BusMessageContent,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum BusMessageDirection {
|
||||||
|
ToCli,
|
||||||
|
ToSupervisor,
|
||||||
|
ToMetrics,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum BusMessageContentType {
|
||||||
|
RawString,
|
||||||
|
Cli,
|
||||||
|
MetricsObj,
|
||||||
|
Result,
|
||||||
|
MetricsModeTransfered,
|
||||||
|
ProcessQuery,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum CLiCommand {
|
||||||
|
Start,
|
||||||
|
Stop,
|
||||||
|
Restart,
|
||||||
|
Freeze,
|
||||||
|
Unfreeze,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InternalCli {
|
||||||
|
pub prc: String,
|
||||||
|
pub cmd: CLiCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait BusContent: Send + Sync + 'static + Debug + Any {
|
||||||
|
fn get_bus_type(&self) -> BusMessageContentType;
|
||||||
|
}
|
||||||
|
impl BusContent for anyhow::Result<String> {
|
||||||
|
fn get_bus_type(&self) -> BusMessageContentType {
|
||||||
|
BusMessageContentType::Result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl BusContent for String {
|
||||||
|
fn get_bus_type(&self) -> BusMessageContentType {
|
||||||
|
BusMessageContentType::RawString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl BusContent for Cli {
|
||||||
|
fn get_bus_type(&self) -> BusMessageContentType {
|
||||||
|
BusMessageContentType::Cli
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl BusContent for InternalCli {
|
||||||
|
fn get_bus_type(&self) -> BusMessageContentType {
|
||||||
|
BusMessageContentType::Cli
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl BusContent for dyn MetricsExportable {
|
||||||
|
fn get_bus_type(&self) -> BusMessageContentType {
|
||||||
|
BusMessageContentType::MetricsObj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl BusContent for Box<dyn MetricsExportable> {
|
||||||
|
fn get_bus_type(&self) -> BusMessageContentType {
|
||||||
|
BusMessageContentType::MetricsObj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl BusContent for MetricsMode {
|
||||||
|
fn get_bus_type(&self) -> BusMessageContentType {
|
||||||
|
BusMessageContentType::MetricsModeTransfered
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl BusContent for ProcessesQuery {
|
||||||
|
fn get_bus_type(&self) -> BusMessageContentType {
|
||||||
|
BusMessageContentType::ProcessQuery
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DependencyType {
|
pub enum DependencyType {
|
||||||
|
|
@ -12,11 +112,20 @@ pub enum DependencyType {
|
||||||
Service,
|
Service,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Clone, Copy)]
|
||||||
pub enum ServiceState {
|
pub enum ServiceState {
|
||||||
Ok,
|
Ok,
|
||||||
Unavailable
|
Unavailable,
|
||||||
}
|
}
|
||||||
|
impl std::fmt::Display for ServiceState {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
return match self {
|
||||||
|
ServiceState::Ok => write!(f, "Ok"),
|
||||||
|
ServiceState::Unavailable => write!(f, "Unavailable"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ServiceWaitConfig(u32);
|
pub struct ServiceWaitConfig(u32);
|
||||||
|
|
||||||
impl Default for ServiceWaitConfig {
|
impl Default for ServiceWaitConfig {
|
||||||
|
|
@ -35,48 +144,87 @@ impl std::fmt::Display for FileTriggerType {
|
||||||
return match self {
|
return match self {
|
||||||
FileTriggerType::OnChange => write!(f, "File was changed"),
|
FileTriggerType::OnChange => write!(f, "File was changed"),
|
||||||
FileTriggerType::OnDelete => write!(f, "File was moved or deleted"),
|
FileTriggerType::OnDelete => write!(f, "File was moved or deleted"),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FileTriggerType {
|
impl<'a> FileTriggerType {
|
||||||
pub fn event(&self, file_name: Arc<str>, trigger: Arc<str>) -> Events {
|
pub fn event(&self, file_name: Arc<str>, trigger: Arc<str>) -> Events {
|
||||||
return match self {
|
return match self {
|
||||||
FileTriggerType::OnChange => Events::Negative(NegativeOutcomes::FileWasChanged(file_name, DependencyType::File, trigger)),
|
FileTriggerType::OnChange => Events::Negative(NegativeOutcomes::FileWasChanged(
|
||||||
FileTriggerType::OnDelete => Events::Negative(NegativeOutcomes::FileWasMovedOrDeleted(file_name, DependencyType::File, trigger)),
|
file_name,
|
||||||
|
DependencyType::File,
|
||||||
|
trigger,
|
||||||
|
)),
|
||||||
|
FileTriggerType::OnDelete => Events::Negative(NegativeOutcomes::FileWasMovedOrDeleted(
|
||||||
|
file_name,
|
||||||
|
DependencyType::File,
|
||||||
|
trigger,
|
||||||
|
)),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
pub fn event_from_file_trigger_controller(
|
||||||
pub fn event_from_file_trigger_controller(&self, file_name: Arc<str>, trigger: &FileTriggersForController) -> Events {
|
&self,
|
||||||
|
file_name: Arc<str>,
|
||||||
|
trigger: &FileTriggersForController,
|
||||||
|
) -> Events {
|
||||||
return match self {
|
return match self {
|
||||||
FileTriggerType::OnChange => Events::Negative(NegativeOutcomes::FileWasChanged(file_name, DependencyType::File, trigger.on_change.clone())),
|
FileTriggerType::OnChange => Events::Negative(NegativeOutcomes::FileWasChanged(
|
||||||
FileTriggerType::OnDelete => Events::Negative(NegativeOutcomes::FileWasMovedOrDeleted(file_name, DependencyType::File, trigger.on_delete.clone())),
|
file_name,
|
||||||
}
|
DependencyType::File,
|
||||||
|
trigger.on_change.clone(),
|
||||||
|
)),
|
||||||
|
FileTriggerType::OnDelete => Events::Negative(NegativeOutcomes::FileWasMovedOrDeleted(
|
||||||
|
file_name,
|
||||||
|
DependencyType::File,
|
||||||
|
trigger.on_delete.clone(),
|
||||||
|
)),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Triggers {
|
pub enum Triggers {
|
||||||
File { on_change: Arc<str>, on_delete: Arc<str> },
|
File {
|
||||||
Service {on_lost: Arc<str>, wait: u32},
|
on_change: Arc<str>,
|
||||||
|
on_delete: Arc<str>,
|
||||||
|
},
|
||||||
|
Service {
|
||||||
|
on_lost: Arc<str>,
|
||||||
|
wait: u32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Triggers {
|
impl Triggers {
|
||||||
pub fn new_file(on_change: Arc<str>, on_delete: Arc<str>) -> Triggers {
|
pub fn new_file(on_change: Arc<str>, on_delete: Arc<str>) -> Triggers {
|
||||||
Triggers::File { on_change, on_delete }
|
Triggers::File {
|
||||||
|
on_change,
|
||||||
|
on_delete,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn new_service(on_lost: Arc<str>, wait_time: u32) -> Triggers {
|
pub fn new_service(on_lost: Arc<str>, wait_time: u32) -> Triggers {
|
||||||
Triggers::Service{on_lost, wait: wait_time}
|
Triggers::Service {
|
||||||
|
on_lost,
|
||||||
|
wait: wait_time,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn to_service_negative_event(&self, service_name: Arc<str>) -> Option<Events> {
|
pub fn to_service_negative_event(&self, service_name: Arc<str>) -> Option<Events> {
|
||||||
if let Triggers::Service { on_lost, .. } = self {
|
if let Triggers::Service { on_lost, .. } = self {
|
||||||
return Some(Events::Negative(NegativeOutcomes::ServiceIsUnreachable(service_name, DependencyType::Service, on_lost.clone())))
|
return Some(Events::Negative(NegativeOutcomes::ServiceIsUnreachable(
|
||||||
|
service_name,
|
||||||
|
DependencyType::Service,
|
||||||
|
on_lost.clone(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FileTriggersForController{ pub on_change: Arc<str>, pub on_delete: Arc<str> }
|
pub struct FileTriggersForController {
|
||||||
|
pub on_change: Arc<str>,
|
||||||
|
pub on_delete: Arc<str>,
|
||||||
|
}
|
||||||
pub struct ServiceTriggersForController(Arc<str>);
|
pub struct ServiceTriggersForController(Arc<str>);
|
||||||
|
|
||||||
impl std::fmt::Display for DependencyType {
|
impl std::fmt::Display for DependencyType {
|
||||||
|
|
@ -84,11 +232,11 @@ impl std::fmt::Display for DependencyType {
|
||||||
return match self {
|
return match self {
|
||||||
DependencyType::File => write!(f, "File"),
|
DependencyType::File => write!(f, "File"),
|
||||||
DependencyType::Service => write!(f, "Service"),
|
DependencyType::Service => write!(f, "Service"),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, serde::Serialize, Clone, Copy)]
|
||||||
pub enum ProcessState {
|
pub enum ProcessState {
|
||||||
Pending,
|
Pending,
|
||||||
Holding,
|
Holding,
|
||||||
|
|
@ -100,19 +248,18 @@ impl std::fmt::Display for ProcessState {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
return match self {
|
return match self {
|
||||||
ProcessState::Pending => write!(f, "Running"),
|
ProcessState::Pending => write!(f, "Running"),
|
||||||
ProcessState::Holding => write!(f, "Holding"),
|
ProcessState::Holding => write!(f, "Frozen"),
|
||||||
ProcessState::Stopped => write!(f, "Stopped"),
|
ProcessState::Stopped => write!(f, "Stopped"),
|
||||||
ProcessState::StoppedByCli => write!(f, "Forcibly stopped"),
|
ProcessState::StoppedByCli => write!(f, "Stopped by Admin"),
|
||||||
ProcessState::HoldingByCli => write!(f, "Forcibly holding"),
|
ProcessState::HoldingByCli => write!(f, "Frozen by Admin"),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Events {
|
pub enum Events {
|
||||||
Positive(Arc<str>),
|
Positive(Arc<str>),
|
||||||
Negative(NegativeOutcomes)
|
Negative(NegativeOutcomes),
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum NegativeOutcomes {
|
pub enum NegativeOutcomes {
|
||||||
|
|
@ -332,7 +479,7 @@ pub struct FileTriggers {
|
||||||
///
|
///
|
||||||
/// *depends on* : `ContainerMetrics`, `ProcessMetrics`
|
/// *depends on* : `ContainerMetrics`, `ProcessMetrics`
|
||||||
///
|
///
|
||||||
#[derive(Debug, Clone, Serialize,)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct Metrics {
|
pub struct Metrics {
|
||||||
pub container_metrics: ContainerMetrics,
|
pub container_metrics: ContainerMetrics,
|
||||||
pub processes_metrics: Vec<ProcessMetrics>,
|
pub processes_metrics: Vec<ProcessMetrics>,
|
||||||
|
|
@ -349,7 +496,6 @@ impl Metrics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// # Container metrics struct
|
/// # Container metrics struct
|
||||||
/// ## for gathering all container metrics
|
/// ## for gathering all container metrics
|
||||||
///
|
///
|
||||||
|
|
@ -367,7 +513,7 @@ pub struct ContainerMetrics {
|
||||||
}
|
}
|
||||||
/// ## Container struct's constructor
|
/// ## Container struct's constructor
|
||||||
impl ContainerMetrics {
|
impl ContainerMetrics {
|
||||||
pub fn new(container_id : &str, cpu: f32, ram: f32, subsystems: Vec<String>,) -> Self{
|
pub fn new(container_id: &str, cpu: f32, ram: f32, subsystems: Vec<String>) -> Self {
|
||||||
ContainerMetrics {
|
ContainerMetrics {
|
||||||
container_id: String::from(container_id),
|
container_id: String::from(container_id),
|
||||||
cpu_load: cpu,
|
cpu_load: cpu,
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,22 @@
|
||||||
|
pub mod bus;
|
||||||
pub mod files;
|
pub mod files;
|
||||||
pub mod hagent;
|
pub mod hagent;
|
||||||
pub mod metrics;
|
pub mod metrics;
|
||||||
pub mod prcs;
|
pub mod prcs;
|
||||||
pub mod services;
|
pub mod services;
|
||||||
|
|
||||||
|
use crate::options::structs::bus::{BusMessage, BusMessageContentType, InternalCli};
|
||||||
use crate::options::structs::Processes;
|
use crate::options::structs::Processes;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use files::v2::FilesController;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
|
use prcs::v2::ProcessesController;
|
||||||
|
use services::v2::ServicesController;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tokio::time::Duration;
|
use tokio::time::Duration;
|
||||||
use prcs::v2::ProcessesController;
|
|
||||||
use files::v2::FilesController;
|
|
||||||
use services::v2::ServicesController;
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref GET_ID_CMD: &'static str = "hostname";
|
static ref GET_ID_CMD: &'static str = "hostname";
|
||||||
|
|
@ -23,9 +25,19 @@ lazy_static! {
|
||||||
// const GET_ID_CMD: &str = "hostname";
|
// const GET_ID_CMD: &str = "hostname";
|
||||||
|
|
||||||
pub mod v2 {
|
pub mod v2 {
|
||||||
use std::collections::{BTreeMap, HashMap, LinkedList, VecDeque};
|
|
||||||
use crate::options::structs::{Events, FileTriggersForController, ProcessUnit, Triggers};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::utils::metrics::processes::{ProcessesAll, ProcessesQuery};
|
||||||
|
use crate::{
|
||||||
|
options::structs::{
|
||||||
|
bus::CLiCommand, Events, FileTriggersForController, ProcessUnit, Triggers,
|
||||||
|
},
|
||||||
|
utils::metrics::processes::deps::{Dependencies, FilesExtended, ServicesExtended},
|
||||||
|
};
|
||||||
|
use std::any::Any;
|
||||||
|
use std::collections::{BTreeMap, HashMap, LinkedList, VecDeque};
|
||||||
|
|
||||||
|
type BusReciever = tokio::sync::mpsc::Receiver<BusMessage>;
|
||||||
|
type BusSender = Arc<tokio::sync::mpsc::Sender<BusMessage>>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ControllerResult {
|
enum ControllerResult {
|
||||||
|
|
@ -40,16 +52,22 @@ pub mod v2 {
|
||||||
files: LinkedList<FilesController>,
|
files: LinkedList<FilesController>,
|
||||||
services: LinkedList<ServicesController>,
|
services: LinkedList<ServicesController>,
|
||||||
config: Arc<Processes>,
|
config: Arc<Processes>,
|
||||||
|
bus: (BusReciever, BusSender),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Supervisor {
|
impl Supervisor {
|
||||||
pub fn new() -> Supervisor {
|
pub fn new(bus_reciever: BusReciever, bus_sender: BusSender) -> Supervisor {
|
||||||
Supervisor { prcs: LinkedList::new(), files: LinkedList::new(), services: LinkedList::new(), config: Arc::new(Processes::default()) }
|
Supervisor {
|
||||||
|
prcs: LinkedList::new(),
|
||||||
|
files: LinkedList::new(),
|
||||||
|
services: LinkedList::new(),
|
||||||
|
config: Arc::new(Processes::default()),
|
||||||
|
bus: (bus_reciever, bus_sender),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub async fn with_config(mut self, config: Processes) -> Supervisor {
|
pub async fn with_config(mut self, config: Processes) -> Supervisor {
|
||||||
self.config = Arc::from(config);
|
self.config = Arc::from(config);
|
||||||
let _ = self.config.processes.iter()
|
let _ = self.config.processes.iter().for_each(|prc| {
|
||||||
.for_each(|prc| {
|
|
||||||
let (rx, tx) = mpsc::channel::<Events>(10);
|
let (rx, tx) = mpsc::channel::<Events>(10);
|
||||||
let temp = ProcessesController::new(&prc.name, tx).with_exe(&prc.path);
|
let temp = ProcessesController::new(&prc.name, tx).with_exe(&prc.path);
|
||||||
if !self.prcs.contains(&temp) {
|
if !self.prcs.contains(&temp) {
|
||||||
|
|
@ -58,15 +76,16 @@ pub mod v2 {
|
||||||
let rx = Arc::new(rx);
|
let rx = Arc::new(rx);
|
||||||
let proc_name: Arc<str> = Arc::from(prc.name.clone());
|
let proc_name: Arc<str> = Arc::from(prc.name.clone());
|
||||||
|
|
||||||
let _ = prc.dependencies.files.iter()
|
let _ = prc.dependencies.files.iter().for_each(|file| {
|
||||||
.for_each(|file| {
|
|
||||||
let mut hm = HashMap::new();
|
let mut hm = HashMap::new();
|
||||||
let triggers = FileTriggersForController { on_change: Arc::from(file.triggers.on_change.clone()), on_delete: Arc::from(file.triggers.on_delete.clone())};
|
let triggers = FileTriggersForController {
|
||||||
|
on_change: Arc::from(file.triggers.on_change.clone()),
|
||||||
|
on_delete: Arc::from(file.triggers.on_delete.clone()),
|
||||||
|
};
|
||||||
hm.insert(proc_name.clone(), (triggers, rx.clone()));
|
hm.insert(proc_name.clone(), (triggers, rx.clone()));
|
||||||
|
|
||||||
let tempfile = FilesController::new(&file.filename.as_str(), hm)
|
let tempfile =
|
||||||
.with_path(&file.src);
|
FilesController::new(&file.filename.as_str(), hm).with_path(&file.src);
|
||||||
|
|
||||||
|
|
||||||
if let Ok(file) = tempfile {
|
if let Ok(file) = tempfile {
|
||||||
if let Some(current_file) = self.files.iter_mut().find(|a| &&file == a) {
|
if let Some(current_file) = self.files.iter_mut().find(|a| &&file == a) {
|
||||||
|
|
@ -78,15 +97,13 @@ pub mod v2 {
|
||||||
});
|
});
|
||||||
|
|
||||||
// servs
|
// servs
|
||||||
let _ = prc.dependencies.services.iter()
|
let _ = prc.dependencies.services.iter().for_each(|serv| {
|
||||||
.for_each(|serv| {
|
let access_url =
|
||||||
let access_url = ServicesController::get_access_url(&serv.hostname, serv.port.as_ref());
|
ServicesController::get_access_url(&serv.hostname, serv.port.as_ref());
|
||||||
// preparations
|
// preparations
|
||||||
let rx = rx.clone();
|
let rx = rx.clone();
|
||||||
let serv_cont = ServicesController::new().with_access_name(
|
let serv_cont =
|
||||||
&serv.hostname,
|
ServicesController::new().with_access_name(&serv.hostname, &access_url);
|
||||||
&access_url
|
|
||||||
);
|
|
||||||
// triggers
|
// triggers
|
||||||
let arc: Arc<str> = Arc::from(serv.triggers.on_lost.clone());
|
let arc: Arc<str> = Arc::from(serv.triggers.on_lost.clone());
|
||||||
let triggers = Triggers::new_service(arc, serv.triggers.wait);
|
let triggers = Triggers::new_service(arc, serv.triggers.wait);
|
||||||
|
|
@ -98,7 +115,8 @@ pub mod v2 {
|
||||||
let mut vec: VecDeque<Arc<str>> = VecDeque::new();
|
let mut vec: VecDeque<Arc<str>> = VecDeque::new();
|
||||||
vec.push_back(proc_name.clone());
|
vec.push_back(proc_name.clone());
|
||||||
// connection_queue
|
// connection_queue
|
||||||
let mut connection_queue: BTreeMap<u32, VecDeque<Arc<str>>> = BTreeMap::new();
|
let mut connection_queue: BTreeMap<u32, VecDeque<Arc<str>>> =
|
||||||
|
BTreeMap::new();
|
||||||
connection_queue.insert(serv.triggers.wait, vec);
|
connection_queue.insert(serv.triggers.wait, vec);
|
||||||
// event_reg
|
// event_reg
|
||||||
let mut hm = HashMap::new();
|
let mut hm = HashMap::new();
|
||||||
|
|
@ -112,7 +130,84 @@ pub mod v2 {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
pub fn get_stats(&self) -> String {
|
pub fn get_stats(&self) -> String {
|
||||||
format!("processes: {}, files: {}, services: {}", self.prcs.len(),self.files.len(), self.services.len())
|
format!(
|
||||||
|
"processes: {}, files: {}, services: {}",
|
||||||
|
self.prcs.len(),
|
||||||
|
self.files.len(),
|
||||||
|
self.services.len()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub async fn extract_extended_procs(
|
||||||
|
config: Arc<Processes>,
|
||||||
|
prcs_list: &LinkedList<ProcessesController>,
|
||||||
|
files_list: &LinkedList<FilesController>,
|
||||||
|
servs_list: &LinkedList<ServicesController>,
|
||||||
|
) -> Vec<ProcessesAll> {
|
||||||
|
let mut procs = Vec::new();
|
||||||
|
for prc in config.processes.iter() {
|
||||||
|
if let Some(prc_cont) = prcs_list
|
||||||
|
.iter()
|
||||||
|
.find(|&prc_cont| prc.name == *prc_cont.name)
|
||||||
|
{
|
||||||
|
let mut vec_files = Vec::new();
|
||||||
|
let mut vec_services = Vec::new();
|
||||||
|
prc.dependencies
|
||||||
|
.files
|
||||||
|
.iter()
|
||||||
|
.map(|file| (file, format!("{}{}", file.src, file.filename)))
|
||||||
|
.for_each(|(file, code_name)| {
|
||||||
|
if let Some(file_cont) = files_list
|
||||||
|
.iter()
|
||||||
|
.find(|&file_cont| *file_cont.get_code_name() == code_name)
|
||||||
|
{
|
||||||
|
vec_files.push(FilesExtended {
|
||||||
|
name: file.filename.to_string(),
|
||||||
|
path: file.src.to_string(),
|
||||||
|
status: file_cont.get_state(),
|
||||||
|
triggers: file.triggers.to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
prc.dependencies
|
||||||
|
.services
|
||||||
|
.iter()
|
||||||
|
.map(|serv| {
|
||||||
|
(
|
||||||
|
serv,
|
||||||
|
format!("{}{}", serv.hostname, {
|
||||||
|
if let Some(port) = serv.port {
|
||||||
|
format!(":{}", port)
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.for_each(|(serv, acces_url)| {
|
||||||
|
if let Some(serv_cont) = servs_list
|
||||||
|
.iter()
|
||||||
|
.find(|&serv_cont| *serv_cont.get_arc_access_url() == acces_url)
|
||||||
|
{
|
||||||
|
vec_services.push(ServicesExtended {
|
||||||
|
name: serv.hostname.to_owned(),
|
||||||
|
access_name: (*serv_cont.get_arc_access_url()).to_owned(),
|
||||||
|
status: serv_cont.get_state(),
|
||||||
|
triggers: serv.triggers.to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
procs.push(ProcessesAll {
|
||||||
|
name: prc_cont.name.clone().to_string(),
|
||||||
|
state: prc_cont.get_state(),
|
||||||
|
pid: prc_cont.get_pid(),
|
||||||
|
dependencies: Dependencies {
|
||||||
|
files: vec_files,
|
||||||
|
services: vec_services,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
procs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,35 +217,123 @@ pub mod v2 {
|
||||||
info!("Initializing monitoring ...");
|
info!("Initializing monitoring ...");
|
||||||
loop {
|
loop {
|
||||||
//
|
//
|
||||||
// todo: CHANNEL check and reaction
|
let rec = &mut self.bus.0;
|
||||||
//
|
while let Ok(request) = rec.try_recv() {
|
||||||
// dbg!(&self);
|
if let BusMessage::Request(_, _, cont) = request {
|
||||||
|
let cont: Box<dyn Any + Send> = cont;
|
||||||
|
match cont.downcast::<InternalCli>() {
|
||||||
|
Ok(cli) => {
|
||||||
|
let mut count = 0;
|
||||||
|
let fut = (&mut self.prcs)
|
||||||
|
.into_iter()
|
||||||
|
.find(|prc| prc.name == Arc::from(cli.prc.as_ref()))
|
||||||
|
.map(|prc| async {
|
||||||
|
let count = &mut count;
|
||||||
|
*count += 1;
|
||||||
|
let res = match cli.cmd {
|
||||||
|
CLiCommand::Start => prc.start_by_user_call().await,
|
||||||
|
CLiCommand::Stop => prc.stop_by_user_call().await,
|
||||||
|
CLiCommand::Restart => prc.restart_by_user_call().await,
|
||||||
|
CLiCommand::Freeze => prc.freeze_by_user_call().await,
|
||||||
|
CLiCommand::Unfreeze => {
|
||||||
|
prc.unfreeze_by_user_call().await
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let sender = self.bus.1.clone();
|
||||||
|
let resp_content = match res {
|
||||||
|
Ok(_) => Ok(format!(
|
||||||
|
"Ok on user call abour process {}",
|
||||||
|
prc.name
|
||||||
|
)),
|
||||||
|
Err(er) => Err(anyhow::Error::msg(format!(
|
||||||
|
"Error: User call for process {} failed : {}",
|
||||||
|
prc.name, er
|
||||||
|
))),
|
||||||
|
};
|
||||||
|
let _ = sender.send(BusMessage::Response(
|
||||||
|
crate::options::structs::bus::BusMessageDirection::ToCli,
|
||||||
|
BusMessageContentType::Result,
|
||||||
|
Box::new(resp_content)
|
||||||
|
)).await;
|
||||||
|
1
|
||||||
|
});
|
||||||
|
if let Some(fut) = fut {
|
||||||
|
fut.await;
|
||||||
|
} else {
|
||||||
|
let _ = self.bus.1.clone().send(BusMessage::Response(
|
||||||
|
crate::options::structs::bus::BusMessageDirection::ToCli,
|
||||||
|
BusMessageContentType::RawString,
|
||||||
|
Box::new(
|
||||||
|
Err(anyhow::Error::msg(format!("No process named `{}` was found in controlled scope", cli.prc)))
|
||||||
|
)
|
||||||
|
)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(boxed) => {
|
||||||
|
if let Ok(query) = boxed.downcast::<ProcessesQuery>() {
|
||||||
|
match *query {
|
||||||
|
ProcessesQuery::QueryAll => {
|
||||||
|
let procs = Self::extract_extended_procs(
|
||||||
|
self.config.clone(),
|
||||||
|
&self.prcs,
|
||||||
|
&self.files,
|
||||||
|
&self.services,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let _ = self.bus.1.clone().send(BusMessage::Response(
|
||||||
|
crate::options::structs::bus::BusMessageDirection::ToMetrics,
|
||||||
|
BusMessageContentType::ProcessQuery,
|
||||||
|
Box::new(
|
||||||
|
ProcessesQuery::All(procs)
|
||||||
|
)
|
||||||
|
)).await;
|
||||||
|
}
|
||||||
|
ProcessesQuery::QueryGeneral => {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for prc in &self.prcs {
|
||||||
|
vec.push(prc.get_general_info().await);
|
||||||
|
}
|
||||||
|
let _ = self.bus.1.clone().send(BusMessage::Response(
|
||||||
|
crate::options::structs::bus::BusMessageDirection::ToMetrics,
|
||||||
|
BusMessageContentType::ProcessQuery,
|
||||||
|
Box::new(
|
||||||
|
ProcessesQuery::General(vec)
|
||||||
|
)
|
||||||
|
)).await;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let _ = self.bus.1.clone().send(BusMessage::Response(
|
||||||
|
crate::options::structs::bus::BusMessageDirection::ToCli,
|
||||||
|
BusMessageContentType::RawString,
|
||||||
|
Box::new(
|
||||||
|
Err(anyhow::Error::msg("Unknown request format was send to the Supervisor"))
|
||||||
|
)
|
||||||
|
)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let mut tasks: Vec<tokio::task::JoinHandle<ControllerResult>> = vec![];
|
let mut tasks: Vec<tokio::task::JoinHandle<ControllerResult>> = vec![];
|
||||||
// let (mut prc, mut file, mut serv) = (self.prcs.pop_front().unwrap(), self.files.pop_front().unwrap(), self.services.pop_front().unwrap());
|
|
||||||
// let res = tokio::join!(prc.process(), file.process(), serv.process());
|
|
||||||
if let Some(mut val) = self.prcs.pop_front() {
|
if let Some(mut val) = self.prcs.pop_front() {
|
||||||
tasks.push(
|
tasks.push(tokio::spawn(async move {
|
||||||
tokio::spawn( async move {
|
|
||||||
val.process().await;
|
val.process().await;
|
||||||
ControllerResult::Process(Some(val))
|
ControllerResult::Process(Some(val))
|
||||||
})
|
}));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if let Some(mut val) = self.files.pop_front() {
|
if let Some(mut val) = self.files.pop_front() {
|
||||||
tasks.push(
|
tasks.push(tokio::spawn(async move {
|
||||||
tokio::spawn( async move {
|
|
||||||
val.process().await;
|
val.process().await;
|
||||||
ControllerResult::File(Some(val))
|
ControllerResult::File(Some(val))
|
||||||
})
|
}));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if let Some(mut val) = self.services.pop_front() {
|
if let Some(mut val) = self.services.pop_front() {
|
||||||
tasks.push(
|
tasks.push(tokio::spawn(async move {
|
||||||
tokio::spawn( async move {
|
|
||||||
val.process().await;
|
val.process().await;
|
||||||
ControllerResult::Service(Some(val))
|
ControllerResult::Service(Some(val))
|
||||||
})
|
}));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
for task in tasks {
|
for task in tasks {
|
||||||
match task.await {
|
match task.await {
|
||||||
|
|
@ -166,15 +349,14 @@ pub mod v2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// spawn tasks
|
|
||||||
// spawn prc
|
|
||||||
// spawn files
|
|
||||||
// spawn services
|
|
||||||
// ## for ... i.await in loop
|
|
||||||
pub async fn init_monitoring(
|
pub async fn init_monitoring(
|
||||||
config: Processes
|
config: Processes,
|
||||||
|
bus_reciever: BusReciever,
|
||||||
|
bus_sender: BusSender,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let mut supervisor = Supervisor::new().with_config(config).await;
|
let mut supervisor = Supervisor::new(bus_reciever, bus_sender)
|
||||||
|
.with_config(config)
|
||||||
|
.await;
|
||||||
info!("Monitoring: {} ", &supervisor.get_stats());
|
info!("Monitoring: {} ", &supervisor.get_stats());
|
||||||
supervisor.process().await;
|
supervisor.process().await;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -205,7 +387,7 @@ pub fn get_container_id() -> Option<String> {
|
||||||
if id.is_empty() {
|
if id.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(String::from_utf8_lossy(&output.stdout).to_string())
|
Some(String::from_utf8_lossy(&output.stdout).trim().to_string())
|
||||||
}
|
}
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::options::structs::bus::{BusMessage, BusMessageDirection};
|
||||||
|
use crate::options::structs::ProcessUnit;
|
||||||
|
use log::{error, trace};
|
||||||
|
use tokio::sync::mpsc::{Receiver, Sender};
|
||||||
|
|
||||||
|
type Inner = Receiver<BusMessage>;
|
||||||
|
type Outter = Arc<Sender<BusMessage>>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Highway {
|
||||||
|
to_cli: Outter,
|
||||||
|
to_supervisor: Outter,
|
||||||
|
to_metrics: Outter,
|
||||||
|
}
|
||||||
|
impl Highway {
|
||||||
|
fn new(to_cli: Outter, to_supervisor: Outter, to_metrics: Outter) -> Self {
|
||||||
|
Self {
|
||||||
|
to_cli,
|
||||||
|
to_supervisor,
|
||||||
|
to_metrics,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fn send(&self, msg: BusMessage) -> anyhow::Result<()> {
|
||||||
|
let dir = match &msg {
|
||||||
|
BusMessage::Request(dir, ..) | BusMessage::Response(dir, ..) => {
|
||||||
|
trace!("redirecting message to {:?} ...", dir);
|
||||||
|
dir
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match dir {
|
||||||
|
BusMessageDirection::ToCli => self.send_cli(msg).await,
|
||||||
|
BusMessageDirection::ToSupervisor => self.send_supervisor(msg).await,
|
||||||
|
BusMessageDirection::ToMetrics => self.send_metrics(msg).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fn send_cli(&self, msg: BusMessage) -> anyhow::Result<()> {
|
||||||
|
self.to_cli.send(msg).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
async fn send_supervisor(&self, msg: BusMessage) -> anyhow::Result<()> {
|
||||||
|
self.to_supervisor.send(msg).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
async fn send_metrics(&self, msg: BusMessage) -> anyhow::Result<()> {
|
||||||
|
self.to_metrics.send(msg).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Bus {
|
||||||
|
inner: Inner,
|
||||||
|
highway: Highway,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bus {
|
||||||
|
pub fn new(inner: Inner, to_cli: Outter, to_supervisor: Outter, to_metrics: Outter) -> Self {
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
highway: Highway::new(to_cli, to_supervisor, to_metrics),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ProcessUnit for Bus {
|
||||||
|
async fn process(&mut self) {
|
||||||
|
loop {
|
||||||
|
while let Ok(content) = self.inner.try_recv() {
|
||||||
|
// debug!("new message to the Bus : {:?}", &content);
|
||||||
|
let msg = match content {
|
||||||
|
BusMessage::Request(direction, content_type, content) => {
|
||||||
|
trace!(
|
||||||
|
"bus has got a new Request with direction {:?} and type {:?}",
|
||||||
|
&direction,
|
||||||
|
&content_type
|
||||||
|
);
|
||||||
|
BusMessage::Request(direction, content_type, content)
|
||||||
|
}
|
||||||
|
BusMessage::Response(direction, content_type, content) => {
|
||||||
|
trace!(
|
||||||
|
"bus has got a new Response with direction {:?} and type {:?}",
|
||||||
|
&direction,
|
||||||
|
&content_type
|
||||||
|
);
|
||||||
|
BusMessage::Response(direction, content_type, content)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Err(er) = self.highway.send(msg).await {
|
||||||
|
error!("Cannot redirect message : {}", er);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(20)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,22 +1,25 @@
|
||||||
use crate::options::structs::CustomError;
|
use crate::options::structs::CustomError;
|
||||||
|
use crate::options::structs::Events;
|
||||||
|
use async_trait::async_trait;
|
||||||
use inotify::{EventMask, Inotify, WatchMask};
|
use inotify::{EventMask, Inotify, WatchMask};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::mpsc::Sender as Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
use crate::options::structs::Events;
|
|
||||||
use async_trait::async_trait;
|
|
||||||
|
|
||||||
pub mod v2 {
|
pub mod v2 {
|
||||||
use log::{error, info, warn};
|
|
||||||
use crate::options::structs::{FileTriggerType, FileTriggersForController as Triggers, ProcessUnit};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::options::structs::{
|
||||||
|
FileTriggerType, FileTriggersForController as Triggers, ProcessUnit,
|
||||||
|
};
|
||||||
|
use log::{error, info, warn};
|
||||||
|
use serde::Serialize;
|
||||||
use std::{collections::HashMap, path::Path};
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
type MpscSender = Arc<Sender<Events>>;
|
type MpscSender = Arc<Sender<Events>>;
|
||||||
type EventHandlers = HashMap<Arc<str>, (Triggers, MpscSender)>;
|
type EventHandlers = HashMap<Arc<str>, (Triggers, MpscSender)>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Clone, Copy)]
|
||||||
enum FileState {
|
pub enum FileState {
|
||||||
Ok,
|
Ok,
|
||||||
NotFound,
|
NotFound,
|
||||||
}
|
}
|
||||||
|
|
@ -57,8 +60,11 @@ pub mod v2 {
|
||||||
match create_watcher(&self.name, &self.path) {
|
match create_watcher(&self.name, &self.path) {
|
||||||
Ok(val) => Some(val),
|
Ok(val) => Some(val),
|
||||||
Err(er) => {
|
Err(er) => {
|
||||||
error!("Cannot create watcher for {} ({}) due to {}", self.name, &self.path, er);
|
error!(
|
||||||
return Err(er)
|
"Cannot create watcher for {} ({}) due to {}",
|
||||||
|
self.name, &self.path, er
|
||||||
|
);
|
||||||
|
return Err(er);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -73,24 +79,34 @@ pub mod v2 {
|
||||||
async fn trigger_on(&mut self, trigger_type: Option<FileTriggerType>) {
|
async fn trigger_on(&mut self, trigger_type: Option<FileTriggerType>) {
|
||||||
for (prc_name, (triggers, channel)) in &self.triggers {
|
for (prc_name, (triggers, channel)) in &self.triggers {
|
||||||
let msg = match &trigger_type {
|
let msg = match &trigger_type {
|
||||||
None => {
|
None => Events::Positive(self.code_name.clone()),
|
||||||
Events::Positive(self.code_name.clone())
|
|
||||||
},
|
|
||||||
Some(event) => {
|
Some(event) => {
|
||||||
info!("Event on file {} ({}) : {}. Notifying `{}` ...", &self.name, &self.path, event, &prc_name);
|
info!(
|
||||||
|
"Event on file {} ({}) : {}. Notifying `{}` ...",
|
||||||
|
&self.name, &self.path, event, &prc_name
|
||||||
|
);
|
||||||
event.event_from_file_trigger_controller(self.code_name.clone(), &triggers)
|
event.event_from_file_trigger_controller(self.code_name.clone(), &triggers)
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
let _ = channel.send(msg).await;
|
let _ = channel.send(msg).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn get_state(&self) -> FileState {
|
||||||
|
self.state
|
||||||
|
}
|
||||||
|
pub fn get_code_name(&self) -> Arc<str> {
|
||||||
|
self.code_name.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl ProcessUnit for FilesController {
|
impl ProcessUnit for FilesController {
|
||||||
async fn process(&mut self) {
|
async fn process(&mut self) {
|
||||||
if let Ok(_) = check_file(&self.name, &self.path).await {
|
if let Ok(_) = check_file(&self.name, &self.path).await {
|
||||||
if let FileState::NotFound = self.state {
|
if let FileState::NotFound = self.state {
|
||||||
info!("File {} ({}) was found in determined scope. Notifying ...", self.name, self.code_name);
|
info!(
|
||||||
|
"File {} ({}) was found in determined scope. Notifying ...",
|
||||||
|
self.name, self.code_name
|
||||||
|
);
|
||||||
self.state = FileState::Ok;
|
self.state = FileState::Ok;
|
||||||
self.trigger_on(None).await;
|
self.trigger_on(None).await;
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +114,8 @@ pub mod v2 {
|
||||||
Some(notify) => {
|
Some(notify) => {
|
||||||
let mut buffer = [0; 128];
|
let mut buffer = [0; 128];
|
||||||
if let Ok(notif_events) = notify.read_events(&mut buffer) {
|
if let Ok(notif_events) = notify.read_events(&mut buffer) {
|
||||||
let (need_to_recreate, was_modifired) = notif_events.fold((false, false), |(a, b), mask| {
|
let (need_to_recreate, was_modifired) =
|
||||||
|
notif_events.fold((false, false), |(a, b), mask| {
|
||||||
(
|
(
|
||||||
a || mask.mask == EventMask::DELETE_SELF,
|
a || mask.mask == EventMask::DELETE_SELF,
|
||||||
b || mask.mask == EventMask::MODIFY,
|
b || mask.mask == EventMask::MODIFY,
|
||||||
|
|
@ -110,25 +127,27 @@ pub mod v2 {
|
||||||
self.watcher = match create_watcher(&self.name, &self.path) {
|
self.watcher = match create_watcher(&self.name, &self.path) {
|
||||||
Ok(notifier) => Some(notifier),
|
Ok(notifier) => Some(notifier),
|
||||||
Err(er) => {
|
Err(er) => {
|
||||||
error!("Failed to recreate watcher for {} ({}) due to {}",
|
error!(
|
||||||
self.name,
|
"Failed to recreate watcher for {} ({}) due to {}",
|
||||||
&self.path,
|
self.name, &self.path, er
|
||||||
er
|
|
||||||
);
|
);
|
||||||
None
|
None
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.trigger_on(Some(FileTriggerType::OnChange)).await;
|
self.trigger_on(Some(FileTriggerType::OnChange)).await;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
None => { /* DEAD END */},
|
None => { /* DEAD END */ }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let FileState::Ok = self.state {
|
if let FileState::Ok = self.state {
|
||||||
warn!("File {} ({}) was not found in determined scope", self.name, &self.path);
|
warn!(
|
||||||
|
"File {} ({}) was not found in determined scope",
|
||||||
|
self.name, &self.path
|
||||||
|
);
|
||||||
self.state = FileState::NotFound;
|
self.state = FileState::NotFound;
|
||||||
self.trigger_on(Some(FileTriggerType::OnDelete)).await;
|
self.trigger_on(Some(FileTriggerType::OnDelete)).await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
//
|
//
|
||||||
// module needed to check host-agent health condition and to communicate with it
|
// module needed to check host-agent health condition and to communicate with it
|
||||||
//
|
//
|
||||||
|
use anyhow::{Error, Ok, Result};
|
||||||
use tokio::{io::Interest, net::UnixStream};
|
use tokio::{io::Interest, net::UnixStream};
|
||||||
use anyhow::{Ok, Result, Error};
|
|
||||||
// to kill lint bug
|
// to kill lint bug
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use tokio::net::UnixListener;
|
use tokio::net::UnixListener;
|
||||||
|
|
@ -91,7 +91,7 @@ mod hagent_unittets {
|
||||||
// --Result<maybe Response>
|
// --Result<maybe Response>
|
||||||
// one-shot func
|
// one-shot func
|
||||||
async fn hagent_communication_test() {
|
async fn hagent_communication_test() {
|
||||||
use crate::options::structs::{ProcessMetrics, ContainerMetrics, Metrics};
|
use crate::options::structs::{ContainerMetrics, Metrics, ProcessMetrics};
|
||||||
|
|
||||||
let procm = ProcessMetrics::new("test-prc", 15.0, 5.0);
|
let procm = ProcessMetrics::new("test-prc", 15.0, 5.0);
|
||||||
let contm = ContainerMetrics::new("test", 32.0, 12.0, vec![procm.process_name.clone()]);
|
let contm = ContainerMetrics::new("test", 32.0, 12.0, vec![procm.process_name.clone()]);
|
||||||
|
|
@ -105,10 +105,11 @@ mod hagent_unittets {
|
||||||
let sock = sock.unwrap();
|
let sock = sock.unwrap();
|
||||||
assert!(ha_healthcheck(&sock).await.is_ok());
|
assert!(ha_healthcheck(&sock).await.is_ok());
|
||||||
assert!(ha_send_data(&sock, &metrics).await.is_ok());
|
assert!(ha_send_data(&sock, &metrics).await.is_ok());
|
||||||
|
|
||||||
}
|
}
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn open_unixsocket_test() {
|
async fn open_unixsocket_test() {
|
||||||
assert!(open_unix_socket("non/valid/socket/file.sock").await.is_err());
|
assert!(open_unix_socket("non/valid/socket/file.sock")
|
||||||
|
.await
|
||||||
|
.is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,24 +1,352 @@
|
||||||
// submodule needed to get metrics such as
|
///! Submodule needed to get metrics such as
|
||||||
// cpu load, ram/rom load and net activity
|
///! cpu load, ram/rom load and net activity
|
||||||
|
|
||||||
// use std::sync::Mutex;
|
use crate::{
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
options::structs::ProcessState,
|
||||||
use crate::options::structs::{ProcessState, TrackingProcess};
|
utils::metrics::processes::{ProcessesGeneral, ProcessesQuery},
|
||||||
use sysinfo::{System, Disks as DisksList, Networks};
|
};
|
||||||
use crate::options::structs::Dependencies;
|
use log::warn;
|
||||||
use serde::Serialize;
|
use noxis_cli::metrics_models::MetricsMode;
|
||||||
|
use std::{any::Any, collections::BTreeMap, sync::Arc};
|
||||||
|
// use chrono::Duration;
|
||||||
use super::prcs::v2::Pid;
|
use super::prcs::v2::Pid;
|
||||||
// use pcap::{Device, Capture, Active};
|
use crate::options::structs::bus::{BusMessage, BusMessageContentType, BusMessageDirection};
|
||||||
// use std::net::Ipv4Addr;
|
use serde::Serialize;
|
||||||
// use anyhow::{Result, Ok};
|
use std::fmt::Debug;
|
||||||
|
use sysinfo::{Disks as DisksList, Networks, System};
|
||||||
// type PacketBuffer = Arc<Mutex<Vec<PacketInfo>>>;
|
// use noxis_cli::metrics_models::MetricsMode;
|
||||||
|
|
||||||
|
pub type MetricProcesses = Vec<ProcessExtended>;
|
||||||
type CoreUsage = BTreeMap<usize, CoreInfo>;
|
type CoreUsage = BTreeMap<usize, CoreInfo>;
|
||||||
type Disks = Vec<Disk>;
|
type Disks = Vec<Disk>;
|
||||||
type Ifaces = Vec<Network>;
|
type Ifaces = Vec<Network>;
|
||||||
pub type MetricProcesses = Vec<ProcessesExtended>;
|
type BusReciever = tokio::sync::mpsc::Receiver<BusMessage>;
|
||||||
|
type BusSender = Arc<tokio::sync::mpsc::Sender<BusMessage>>;
|
||||||
|
|
||||||
|
/// # Fn `init_metrics_grubber`
|
||||||
|
/// ## for initializing process of unstoppable grubbing metrics.
|
||||||
|
///
|
||||||
|
/// *input* : `Arc<Mutex<UnixSocket>>` ??
|
||||||
|
///
|
||||||
|
/// *output* : `Err` if it cant create grubbers | `Ok` on finish
|
||||||
|
///
|
||||||
|
/// *initiator* : main thread ??
|
||||||
|
///
|
||||||
|
/// *managing* : object of unix-socket reader
|
||||||
|
///
|
||||||
|
/// *depends on* : -
|
||||||
|
///
|
||||||
|
pub async fn init_metrics_grubber(
|
||||||
|
/* BROADCSAT LISTENER TO GET `PROCESSES` OBJ */
|
||||||
|
bus_sender: BusSender,
|
||||||
|
bus_reciever: BusReciever,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let mut system = System::new();
|
||||||
|
let mut disks = DisksList::new_with_refreshed_list();
|
||||||
|
let mut networks = Networks::new_with_refreshed_list();
|
||||||
|
// get_all_metrics(&mut system).await;
|
||||||
|
/* TODO */
|
||||||
|
let mut bus_reciever = bus_reciever;
|
||||||
|
loop {
|
||||||
|
let msg = bus_reciever.try_recv();
|
||||||
|
if let Ok(BusMessage::Request(_, _, cont)) = msg {
|
||||||
|
system.refresh_all();
|
||||||
|
disks.refresh_list();
|
||||||
|
networks.refresh_list();
|
||||||
|
let cont: Box<dyn Any + Send> = cont;
|
||||||
|
match cont.downcast::<MetricsMode>() {
|
||||||
|
Err(_) => {
|
||||||
|
warn!("Unrecognized Metric mode was given");
|
||||||
|
let _ = bus_sender
|
||||||
|
.send(BusMessage::Response(
|
||||||
|
BusMessageDirection::ToCli,
|
||||||
|
BusMessageContentType::Result,
|
||||||
|
Box::new(Err(anyhow::Error::msg(format!(
|
||||||
|
"Unrecognized Metric mode was given"
|
||||||
|
)))),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
Ok(mode) => {
|
||||||
|
tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
|
||||||
|
let metric: Box<dyn MetricsExportable> = match *mode {
|
||||||
|
MetricsMode::Full => {
|
||||||
|
let mut refs =
|
||||||
|
get_all_metrics(&mut system, bus_sender.clone(), &disks, &networks)
|
||||||
|
.await;
|
||||||
|
if let Some(prcs) = bus_reciever.recv().await {
|
||||||
|
if let BusMessage::Response(_, _, cont) = prcs {
|
||||||
|
let cont: Box<dyn Any> = cont;
|
||||||
|
if let Ok(cont) = cont.downcast::<ProcessesQuery>() {
|
||||||
|
if let ProcessesQuery::General(info) = *cont {
|
||||||
|
refs.processes = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Box::new(refs)
|
||||||
|
}
|
||||||
|
MetricsMode::Host => {
|
||||||
|
Box::new(get_global_host_info(&mut system, &disks, &networks).await)
|
||||||
|
}
|
||||||
|
MetricsMode::Cpu => Box::new(get_cpu_metrics(&mut system).await),
|
||||||
|
MetricsMode::Ram => Box::new(get_ram_metrics(&mut system).await),
|
||||||
|
MetricsMode::Rom => Box::new(get_all_disks_metrics(&disks).await),
|
||||||
|
MetricsMode::Network => Box::new(get_all_ifaces_metrics(&networks).await),
|
||||||
|
// inspect processes
|
||||||
|
MetricsMode::Processes => {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// let metric: Box<dyn BusContent> = Box::new(metric);
|
||||||
|
let metric = metric.serialze_into_output();
|
||||||
|
|
||||||
|
let _ = bus_sender
|
||||||
|
.send(BusMessage::Response(
|
||||||
|
BusMessageDirection::ToCli,
|
||||||
|
BusMessageContentType::MetricsObj,
|
||||||
|
Box::new(metric),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Ok(BusMessage::Response(_, _, cont)) = msg {
|
||||||
|
let cont: Box<dyn Any + Send> = cont;
|
||||||
|
if let Ok(info) = cont.downcast::<ProcessesQuery>() {
|
||||||
|
if let ProcessesQuery::All(info) = *info {
|
||||||
|
let procs: Vec<_> = info
|
||||||
|
.into_iter()
|
||||||
|
.map(|prc| ProcessExtended::from_process_query_all(&mut system, prc))
|
||||||
|
.collect();
|
||||||
|
let _ = bus_sender
|
||||||
|
.send(BusMessage::Response(
|
||||||
|
BusMessageDirection::ToCli,
|
||||||
|
BusMessageContentType::Result,
|
||||||
|
Box::<anyhow::Result<String>>::new(Ok(serde_json::to_string_pretty(
|
||||||
|
&procs,
|
||||||
|
)?)),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
} else {
|
||||||
|
let _ = bus_sender
|
||||||
|
.send(BusMessage::Response(
|
||||||
|
BusMessageDirection::ToCli,
|
||||||
|
BusMessageContentType::Result,
|
||||||
|
Box::new(Err(anyhow::Error::msg(format!(
|
||||||
|
"Unknown type was send by the Supervisor"
|
||||||
|
)))),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let _ = bus_sender
|
||||||
|
.send(BusMessage::Response(
|
||||||
|
BusMessageDirection::ToCli,
|
||||||
|
BusMessageContentType::Result,
|
||||||
|
Box::new(Err(anyhow::Error::msg(format!(
|
||||||
|
"Unknown type was send by the Supervisor"
|
||||||
|
)))),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_all_metrics(
|
||||||
|
system: &mut System,
|
||||||
|
sender: BusSender,
|
||||||
|
disks: &DisksList,
|
||||||
|
networks: &Networks,
|
||||||
|
) -> FullMetrics {
|
||||||
|
let host = get_host_info().await;
|
||||||
|
let cpu = get_cpu_metrics(system).await;
|
||||||
|
let ram = get_ram_metrics(system).await;
|
||||||
|
let disks = get_all_disks_metrics(&disks).await;
|
||||||
|
let ifaces = get_all_ifaces_metrics(&networks).await;
|
||||||
|
let prcs: Vec<ProcessesGeneral> = Vec::new();
|
||||||
|
let _ = sender
|
||||||
|
.send(BusMessage::Request(
|
||||||
|
BusMessageDirection::ToSupervisor,
|
||||||
|
BusMessageContentType::ProcessQuery,
|
||||||
|
Box::new(ProcessesQuery::QueryGeneral),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
FullMetrics::create(host, cpu, ram, disks, ifaces, prcs)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_global_host_info(
|
||||||
|
system: &mut System,
|
||||||
|
disks: &DisksList,
|
||||||
|
networks: &Networks,
|
||||||
|
) -> HostGeneral {
|
||||||
|
HostGeneral {
|
||||||
|
hostname: System::host_name().unwrap_or_default(),
|
||||||
|
os: System::long_os_version().unwrap_or_default(),
|
||||||
|
kernel: System::kernel_version().unwrap_or_default(),
|
||||||
|
cpu_percentage: system.global_cpu_usage(),
|
||||||
|
ram_available: system.total_memory() - system.free_memory(),
|
||||||
|
disk_percentage: {
|
||||||
|
let total = disks
|
||||||
|
.iter()
|
||||||
|
.map(|disk| disk.available_space() * 100 / disk.total_space())
|
||||||
|
.collect::<Vec<u64>>();
|
||||||
|
total.iter().sum::<u64>() / (total.len() as u64)
|
||||||
|
},
|
||||||
|
net_stat: {
|
||||||
|
let total = networks
|
||||||
|
.iter()
|
||||||
|
.map(|(_, iface_data)| iface_data.received() + iface_data.transmitted())
|
||||||
|
.collect::<Vec<u64>>();
|
||||||
|
total.iter().sum::<u64>() / ((total.len() * 2) as u64)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_host_info() -> HostInfo {
|
||||||
|
HostInfo {
|
||||||
|
hostname: System::host_name().unwrap_or_default(),
|
||||||
|
os: System::long_os_version().unwrap_or_default(),
|
||||||
|
kernel: System::kernel_version().unwrap_or_default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_cpu_metrics(system: &mut System) -> Cpu {
|
||||||
|
let mut buffer = CoreUsage::new();
|
||||||
|
let global_usage = system.global_cpu_usage();
|
||||||
|
|
||||||
|
system.cpus().iter().enumerate().for_each(|(id, cpu)| {
|
||||||
|
let core_info = CoreInfo {
|
||||||
|
// id,
|
||||||
|
brand: cpu.brand().to_string(),
|
||||||
|
name: cpu.name().to_string(),
|
||||||
|
frequency: cpu.frequency(),
|
||||||
|
vendor_id: cpu.vendor_id().to_string(),
|
||||||
|
usage: cpu.cpu_usage(),
|
||||||
|
};
|
||||||
|
buffer.entry(id).or_insert(core_info);
|
||||||
|
});
|
||||||
|
|
||||||
|
Cpu {
|
||||||
|
global_usage,
|
||||||
|
usage: buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_ram_metrics(system: &mut System) -> Ram {
|
||||||
|
Ram {
|
||||||
|
free_mem: system.free_memory(),
|
||||||
|
free_swap: system.free_swap(),
|
||||||
|
total_mem: system.total_memory(),
|
||||||
|
total_swap: system.total_swap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_all_disks_metrics(disks: &DisksList) -> Disks {
|
||||||
|
// let disks = DisksList::new_with_refreshed_list();
|
||||||
|
let mut buffer = Disks::new();
|
||||||
|
disks.list().iter().for_each(|disk| {
|
||||||
|
let disk = Disk {
|
||||||
|
name: disk.name().to_string_lossy().into_owned(),
|
||||||
|
kind: disk.kind().to_string(),
|
||||||
|
fs: disk.file_system().to_string_lossy().into_owned(),
|
||||||
|
mount_point: disk.mount_point().to_string_lossy().into_owned(),
|
||||||
|
total_space: disk.total_space(),
|
||||||
|
available_space: disk.available_space(),
|
||||||
|
is_removable: disk.is_removable(),
|
||||||
|
is_readonly: disk.is_read_only(),
|
||||||
|
};
|
||||||
|
buffer.push(disk);
|
||||||
|
});
|
||||||
|
buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_all_ifaces_metrics(networks: &Networks) -> Ifaces {
|
||||||
|
let mut ifaces = Ifaces::new();
|
||||||
|
networks.iter().for_each(|(iface_name, data)| {
|
||||||
|
let mac = data.mac_address().to_string();
|
||||||
|
let ip_addrs = data
|
||||||
|
.ip_networks()
|
||||||
|
.iter()
|
||||||
|
.map(|ipaddr| format!("{}/{}", ipaddr.addr, ipaddr.prefix))
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let iface = Network {
|
||||||
|
iname: iface_name.to_owned(),
|
||||||
|
mac: mac,
|
||||||
|
ip_addresses: ip_addrs,
|
||||||
|
recieved: data.received(),
|
||||||
|
transmitted: data.transmitted(),
|
||||||
|
total_recieved_bytes: data.total_received(),
|
||||||
|
total_transmitted_bytes: data.total_transmitted(),
|
||||||
|
total_recieved_packets: data.total_packets_received(),
|
||||||
|
total_transmitted_packets: data.total_packets_transmitted(),
|
||||||
|
errors_on_recieved: data.errors_on_received(),
|
||||||
|
errors_on_transmitted: data.errors_on_transmitted(),
|
||||||
|
};
|
||||||
|
ifaces.push(iface);
|
||||||
|
});
|
||||||
|
ifaces
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod processes {
|
||||||
|
use crate::options::structs::ProcessState;
|
||||||
|
use crate::utils::prcs::v2::Pid;
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Serialize)]
|
||||||
|
pub enum ProcessesQuery {
|
||||||
|
General(Vec<ProcessesGeneral>),
|
||||||
|
All(Vec<ProcessesAll>),
|
||||||
|
QueryGeneral,
|
||||||
|
QueryAll,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Serialize)]
|
||||||
|
pub struct ProcessesGeneral {
|
||||||
|
pub name: String,
|
||||||
|
pub state: ProcessState,
|
||||||
|
pub pid: Pid,
|
||||||
|
}
|
||||||
|
#[derive(Debug, serde::Serialize)]
|
||||||
|
pub struct ProcessesAll {
|
||||||
|
pub name: String,
|
||||||
|
pub state: ProcessState,
|
||||||
|
pub pid: Pid,
|
||||||
|
pub dependencies: deps::Dependencies,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod deps {
|
||||||
|
use crate::options::structs::{FileTriggers, ServiceState, ServiceTriggers};
|
||||||
|
use crate::utils::files::v2::FileState;
|
||||||
|
|
||||||
|
// use super::*;
|
||||||
|
#[derive(Debug, serde::Serialize)]
|
||||||
|
pub struct FilesExtended {
|
||||||
|
pub name: String,
|
||||||
|
pub path: String,
|
||||||
|
pub status: FileState,
|
||||||
|
pub triggers: FileTriggers,
|
||||||
|
}
|
||||||
|
#[derive(Debug, serde::Serialize)]
|
||||||
|
pub struct ServicesExtended {
|
||||||
|
pub name: String,
|
||||||
|
pub access_name: String,
|
||||||
|
pub status: ServiceState,
|
||||||
|
pub triggers: ServiceTriggers,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Serialize)]
|
||||||
|
pub struct Dependencies {
|
||||||
|
pub files: Vec<FilesExtended>,
|
||||||
|
pub services: Vec<ServicesExtended>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MetricsExportable: Send + Sync + 'static + Debug + Any {
|
||||||
|
fn serialze_into_output(&self) -> anyhow::Result<String>;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
struct FullMetrics {
|
struct FullMetrics {
|
||||||
|
|
@ -29,16 +357,64 @@ struct FullMetrics {
|
||||||
ram: Ram,
|
ram: Ram,
|
||||||
disks: Disks,
|
disks: Disks,
|
||||||
networks: Ifaces,
|
networks: Ifaces,
|
||||||
processes : MetricProcesses,
|
pub processes: Vec<ProcessesGeneral>,
|
||||||
|
}
|
||||||
|
impl FullMetrics {
|
||||||
|
fn create(
|
||||||
|
host: HostInfo,
|
||||||
|
cpu: Cpu,
|
||||||
|
ram: Ram,
|
||||||
|
disks: Disks,
|
||||||
|
ifaces: Ifaces,
|
||||||
|
processes: Vec<ProcessesGeneral>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
hostname: host.hostname,
|
||||||
|
os: host.os,
|
||||||
|
kernel: host.kernel,
|
||||||
|
cpu,
|
||||||
|
ram,
|
||||||
|
disks,
|
||||||
|
networks: ifaces,
|
||||||
|
processes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl MetricsExportable for FullMetrics {
|
||||||
|
fn serialze_into_output(&self) -> anyhow::Result<String> {
|
||||||
|
Ok(serde_json::to_string_pretty(self)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize)]
|
||||||
struct HostInfo {
|
struct HostInfo {
|
||||||
hostname: String,
|
hostname: String,
|
||||||
os: String,
|
os: String,
|
||||||
kernel: String,
|
kernel: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MetricsExportable for HostInfo {
|
||||||
|
fn serialze_into_output(&self) -> anyhow::Result<String> {
|
||||||
|
Ok(serde_json::to_string_pretty(self)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct HostGeneral {
|
||||||
|
hostname: String,
|
||||||
|
os: String,
|
||||||
|
kernel: String,
|
||||||
|
cpu_percentage: f32,
|
||||||
|
ram_available: u64,
|
||||||
|
disk_percentage: u64,
|
||||||
|
net_stat: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetricsExportable for HostGeneral {
|
||||||
|
fn serialze_into_output(&self) -> anyhow::Result<String> {
|
||||||
|
Ok(serde_json::to_string_pretty(self)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
struct Cpu {
|
struct Cpu {
|
||||||
|
|
@ -46,6 +422,12 @@ struct Cpu {
|
||||||
usage: CoreUsage,
|
usage: CoreUsage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MetricsExportable for Cpu {
|
||||||
|
fn serialze_into_output(&self) -> anyhow::Result<String> {
|
||||||
|
Ok(serde_json::to_string_pretty(self)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
struct CoreInfo {
|
struct CoreInfo {
|
||||||
name: String,
|
name: String,
|
||||||
|
|
@ -60,7 +442,13 @@ struct Ram {
|
||||||
free_mem: u64,
|
free_mem: u64,
|
||||||
free_swap: u64,
|
free_swap: u64,
|
||||||
total_mem: u64,
|
total_mem: u64,
|
||||||
total_swap : u64
|
total_swap: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetricsExportable for Ram {
|
||||||
|
fn serialze_into_output(&self) -> anyhow::Result<String> {
|
||||||
|
Ok(serde_json::to_string_pretty(self)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
|
|
@ -75,11 +463,18 @@ struct Disk {
|
||||||
is_readonly: bool,
|
is_readonly: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MetricsExportable for Disks {
|
||||||
|
fn serialze_into_output(&self) -> anyhow::Result<String> {
|
||||||
|
Ok(serde_json::to_string_pretty(self)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// vec<Network>
|
// vec<Network>
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
struct Network {
|
struct Network {
|
||||||
iname: String,
|
iname: String,
|
||||||
mac: String,
|
mac: String,
|
||||||
|
ip_addresses: Vec<String>,
|
||||||
recieved: u64,
|
recieved: u64,
|
||||||
transmitted: u64,
|
transmitted: u64,
|
||||||
total_recieved_bytes: u64,
|
total_recieved_bytes: u64,
|
||||||
|
|
@ -90,174 +485,63 @@ struct Network {
|
||||||
errors_on_transmitted: u64,
|
errors_on_transmitted: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MetricsExportable for Ifaces {
|
||||||
|
fn serialze_into_output(&self) -> anyhow::Result<String> {
|
||||||
|
Ok(serde_json::to_string_pretty(self)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
pub struct ProcessesExtended {
|
pub struct ProcessExtended {
|
||||||
name: String,
|
name: String,
|
||||||
status : String,
|
status: ProcessState,
|
||||||
pid: Pid,
|
pid: Pid,
|
||||||
dependencies : Dependencies,
|
dependencies: processes::deps::Dependencies,
|
||||||
cpu_usage: f32,
|
cpu_usage: f32,
|
||||||
ram_usage : f32,
|
ram_usage: u64,
|
||||||
virtual_mem_usage: u64,
|
virtual_mem_usage: u64,
|
||||||
disks_usage_read_bytes: u64,
|
disks_usage_read_bytes: u64,
|
||||||
disks_usage_write_bytes: u64,
|
disks_usage_write_bytes: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessesExtended {
|
impl ProcessExtended {
|
||||||
pub fn from_old_with_params(
|
pub fn from_process_query_all(system: &mut System, proc: processes::ProcessesAll) -> Self {
|
||||||
old : Arc<TrackingProcess>,
|
system.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
|
||||||
pid : Pid,
|
return if let Some(prc) = system.process(proc.pid.new_sysinfo_pid()) {
|
||||||
status : ProcessState,
|
let disk_usage = prc.disk_usage();
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
name : old.name.clone(),
|
name: proc.name,
|
||||||
status : status.to_string(),
|
status: proc.state,
|
||||||
pid,
|
pid: proc.pid,
|
||||||
dependencies : old.dependencies.clone(),
|
dependencies: proc.dependencies,
|
||||||
|
cpu_usage: prc.cpu_usage(),
|
||||||
|
ram_usage: prc.memory(),
|
||||||
|
virtual_mem_usage: prc.virtual_memory(),
|
||||||
|
disks_usage_read_bytes: disk_usage.read_bytes,
|
||||||
|
disks_usage_write_bytes: disk_usage.written_bytes,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Self {
|
||||||
|
name: proc.name,
|
||||||
|
status: proc.state,
|
||||||
|
pid: proc.pid,
|
||||||
|
dependencies: proc.dependencies,
|
||||||
cpu_usage: 0.0,
|
cpu_usage: 0.0,
|
||||||
ram_usage : 0.0,
|
ram_usage: 0,
|
||||||
virtual_mem_usage: 0,
|
virtual_mem_usage: 0,
|
||||||
disks_usage_read_bytes: 0,
|
disks_usage_read_bytes: 0,
|
||||||
disks_usage_write_bytes: 0,
|
disks_usage_write_bytes: 0,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
fn add_metrics(&mut self, system : &mut System) {
|
|
||||||
if let Some(prc) = system.process(self.pid.new_sysinfo_pid()) {
|
|
||||||
self.cpu_usage = prc.cpu_usage() / system.cpus().len() as f32;
|
|
||||||
self.ram_usage = (system.total_memory() as f32) / (prc.memory() as f32);
|
|
||||||
self.disks_usage_read_bytes = prc.disk_usage().total_read_bytes;
|
|
||||||
self.disks_usage_write_bytes = prc.disk_usage().total_written_bytes;
|
|
||||||
self.virtual_mem_usage = prc.virtual_memory();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Fn `init_metrics_grubber`
|
|
||||||
/// ## for initializing process of unstoppable grubbing metrics.
|
|
||||||
///
|
|
||||||
/// *input* : `Arc<Mutex<UnixSocket>>` ??
|
|
||||||
///
|
|
||||||
/// *output* : `Err` if it cant create grubbers | `Ok` on finish
|
|
||||||
///
|
|
||||||
/// *initiator* : main thread ??
|
|
||||||
///
|
|
||||||
/// *managing* : object of unix-socket reader
|
|
||||||
///
|
|
||||||
/// *depends on* : -
|
|
||||||
///
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub async fn init_metrics_grubber(
|
|
||||||
/* BROADCSAT LISTENER TO GET `PROCESSES` OBJ */
|
|
||||||
) {
|
|
||||||
let mut system = System::new();
|
|
||||||
get_all_metrics(&mut system).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_all_metrics(system: &mut System) {
|
|
||||||
system.refresh_all();
|
|
||||||
tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
|
|
||||||
dbg!(get_host_info().await);
|
|
||||||
dbg!(get_cpu_metrics(system).await);
|
|
||||||
dbg!(get_ram_metrics(system).await);
|
|
||||||
dbg!(get_all_disks_metrics().await);
|
|
||||||
dbg!(get_all_ifaces_metrics().await);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_host_info() -> HostInfo {
|
|
||||||
HostInfo {
|
|
||||||
hostname : System::host_name().unwrap_or_default(),
|
|
||||||
os : System::long_os_version().unwrap_or_default(),
|
|
||||||
kernel : System::kernel_version().unwrap_or_default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_cpu_metrics(system: &mut System) -> Cpu {
|
|
||||||
system.refresh_cpu_all();
|
|
||||||
tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
|
|
||||||
|
|
||||||
let mut buffer = CoreUsage::new();
|
|
||||||
let global_usage = system.global_cpu_usage();
|
|
||||||
|
|
||||||
system.cpus()
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.for_each(|(id, cpu)| {
|
|
||||||
let core_info = CoreInfo {
|
|
||||||
// id,
|
|
||||||
brand : cpu.brand().to_string(),
|
|
||||||
name : cpu.name().to_string(),
|
|
||||||
frequency : cpu.frequency(),
|
|
||||||
vendor_id : cpu.vendor_id().to_string(),
|
|
||||||
usage : cpu.cpu_usage(),
|
|
||||||
};
|
};
|
||||||
// buffer.push(core_info);
|
|
||||||
buffer.entry(id).or_insert(core_info);
|
|
||||||
});
|
|
||||||
|
|
||||||
Cpu {
|
|
||||||
global_usage,
|
|
||||||
usage: buffer
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_ram_metrics(system: &mut System) -> Ram {
|
impl MetricsExportable for MetricProcesses {
|
||||||
system.refresh_memory();
|
fn serialze_into_output(&self) -> anyhow::Result<String> {
|
||||||
tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
|
Ok(serde_json::to_string_pretty(self)?)
|
||||||
|
|
||||||
Ram {
|
|
||||||
free_mem : system.free_memory(),
|
|
||||||
free_swap : system.free_swap(),
|
|
||||||
total_mem : system.total_memory(),
|
|
||||||
total_swap : system.total_swap(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_all_disks_metrics() -> Disks {
|
|
||||||
let disks = DisksList::new_with_refreshed_list();
|
|
||||||
let mut buffer = Disks::new();
|
|
||||||
disks.list()
|
|
||||||
.iter()
|
|
||||||
.for_each(|disk| {
|
|
||||||
let disk = Disk {
|
|
||||||
name : disk.name().to_string_lossy().into_owned(),
|
|
||||||
kind: disk.kind().to_string(),
|
|
||||||
fs : disk.file_system().to_string_lossy().into_owned(),
|
|
||||||
mount_point : disk.mount_point().to_string_lossy().into_owned(),
|
|
||||||
total_space : disk.total_space(),
|
|
||||||
available_space : disk.available_space(),
|
|
||||||
is_removable : disk.is_removable(),
|
|
||||||
is_readonly : disk.is_read_only()
|
|
||||||
};
|
|
||||||
buffer.push(disk);
|
|
||||||
});
|
|
||||||
buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_all_ifaces_metrics() -> Ifaces {
|
|
||||||
let mut ifaces = Ifaces::new();
|
|
||||||
let networks = Networks::new_with_refreshed_list();
|
|
||||||
networks.iter()
|
|
||||||
.for_each(|(iface_name, data)| {
|
|
||||||
let mac = data.mac_address().to_string();
|
|
||||||
let iface = Network {
|
|
||||||
iname : iface_name.to_owned(),
|
|
||||||
mac : mac,
|
|
||||||
recieved : data.received(),
|
|
||||||
transmitted : data.transmitted(),
|
|
||||||
total_recieved_bytes : data.total_received(),
|
|
||||||
total_transmitted_bytes : data.total_transmitted(),
|
|
||||||
total_recieved_packets : data.total_packets_received(),
|
|
||||||
total_transmitted_packets : data.total_packets_transmitted(),
|
|
||||||
errors_on_recieved : data.errors_on_received(),
|
|
||||||
errors_on_transmitted : data.errors_on_transmitted(),
|
|
||||||
};
|
|
||||||
ifaces.push(iface);
|
|
||||||
});
|
|
||||||
ifaces
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_all_processes_metrics(system: &mut System) {}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod metrics_unittets {
|
mod metrics_unittets {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
|
use crate::options::structs::{Events, NegativeOutcomes, ProcessState, ProcessUnit};
|
||||||
|
use async_trait::async_trait;
|
||||||
use log::{error, warn};
|
use log::{error, warn};
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::process::{Command, Output};
|
use std::process::{Command, Output};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::time::Duration;
|
|
||||||
use crate::options::structs::{ProcessState, Events, NegativeOutcomes, ProcessUnit};
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use tokio::sync::mpsc::Receiver as MpscReciever;
|
use tokio::sync::mpsc::Receiver as MpscReciever;
|
||||||
use async_trait::async_trait;
|
use tokio::time::Duration;
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
pub mod v2 {
|
pub mod v2 {
|
||||||
use log::info;
|
|
||||||
use tokio::time::sleep;
|
|
||||||
use crate::options::structs::DependencyType;
|
use crate::options::structs::DependencyType;
|
||||||
|
use crate::utils::metrics::processes::ProcessesGeneral;
|
||||||
|
use log::info;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use tokio::time::sleep;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
@ -38,9 +39,8 @@ pub mod v2 {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ProcessesController {
|
pub struct ProcessesController {
|
||||||
pub name: Arc<str>,
|
pub name: Arc<str>,
|
||||||
pub pid : Pid,
|
pid: Pid,
|
||||||
bin: String,
|
bin: String,
|
||||||
// obj: Arc<TrackingProcess>,
|
|
||||||
state: ProcessState,
|
state: ProcessState,
|
||||||
event_reader: MpscReciever<Events>,
|
event_reader: MpscReciever<Events>,
|
||||||
negative_events: HashSet<Arc<str>>,
|
negative_events: HashSet<Arc<str>>,
|
||||||
|
|
@ -69,91 +69,113 @@ pub mod v2 {
|
||||||
self.bin = bin.as_ref().to_string_lossy().into_owned();
|
self.bin = bin.as_ref().to_string_lossy().into_owned();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
|
||||||
pub fn get_pid(&self) -> Pid {
|
pub fn get_pid(&self) -> Pid {
|
||||||
self.pid
|
self.pid
|
||||||
}
|
}
|
||||||
|
pub fn get_state(&self) -> ProcessState {
|
||||||
|
self.state
|
||||||
|
}
|
||||||
async fn trigger_on(&mut self, dep_name: &str, trigger: &str, dep_type: DependencyType) {
|
async fn trigger_on(&mut self, dep_name: &str, trigger: &str, dep_type: DependencyType) {
|
||||||
match trigger {
|
match trigger {
|
||||||
"stay" => {
|
"stay" => {
|
||||||
info!("Event on {} `{}` for {}. Ignoring ...", dep_type, dep_name, self.name);
|
info!(
|
||||||
},
|
"Event on {} `{}` for {}. Ignoring ...",
|
||||||
|
dep_type, dep_name, self.name
|
||||||
|
);
|
||||||
|
}
|
||||||
"stop" => {
|
"stop" => {
|
||||||
if is_active(&self.name).await {
|
if is_active(&self.name).await {
|
||||||
info!("Event on {} `{}` for {}. Stopping ...", dep_type, dep_name, self.name);
|
info!(
|
||||||
|
"Event on {} `{}` for {}. Stopping ...",
|
||||||
|
dep_type, dep_name, self.name
|
||||||
|
);
|
||||||
match terminate_process(&self.name).await {
|
match terminate_process(&self.name).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
info!("Process {} was stopped ...", &self.name);
|
info!("Process {} was stopped ...", &self.name);
|
||||||
self.state = ProcessState::Stopped;
|
self.state = ProcessState::Stopped;
|
||||||
self.pid = Pid::new();
|
self.pid = Pid::new();
|
||||||
},
|
}
|
||||||
Err(er) => {
|
Err(er) => {
|
||||||
error!("Cannot stop process {} : {}", self.name, er);
|
error!("Cannot stop process {} : {}", self.name, er);
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
"user-stop" => {
|
"user-stop" => {
|
||||||
if is_active(&self.name).await {
|
if is_active(&self.name).await {
|
||||||
info!("Event on {} `{}` for {}. Stopping ...", dep_type, "User Stop Call", self.name);
|
info!(
|
||||||
|
"Event on {} `{}` for {}. Stopping ...",
|
||||||
|
dep_type, "User Stop Call", self.name
|
||||||
|
);
|
||||||
match terminate_process(&self.name).await {
|
match terminate_process(&self.name).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
info!("Process {} was forcefully stopped ...", &self.name);
|
info!("Process {} was forcefully stopped ...", &self.name);
|
||||||
self.state = ProcessState::StoppedByCli;
|
self.state = ProcessState::StoppedByCli;
|
||||||
self.pid = Pid::new();
|
self.pid = Pid::new();
|
||||||
},
|
}
|
||||||
Err(er) => {
|
Err(er) => {
|
||||||
error!("Cannot forcefully stop process {} : {}", self.name, er);
|
error!("Cannot forcefully stop process {} : {}", self.name, er);
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
"user-hold" => {
|
"user-hold" => {
|
||||||
if is_active(&self.name).await {
|
if is_active(&self.name).await {
|
||||||
info!("Event on {} `{}` for {}. Stopping ...", dep_type, "User Hold Call", self.name);
|
info!(
|
||||||
|
"Event on {} `{}` for {}. Stopping ...",
|
||||||
|
dep_type, "User Hold Call", self.name
|
||||||
|
);
|
||||||
match freeze_process(&self.name).await {
|
match freeze_process(&self.name).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
info!("Process {} was forcefully frozen ...", &self.name);
|
info!("Process {} was forcefully frozen ...", &self.name);
|
||||||
self.state = ProcessState::HoldingByCli;
|
self.state = ProcessState::HoldingByCli;
|
||||||
// self.pid = Pid::new();
|
}
|
||||||
},
|
|
||||||
Err(er) => {
|
Err(er) => {
|
||||||
error!("Cannot forcefully freeze process {} : {}", self.name, er);
|
error!("Cannot forcefully freeze process {} : {}", self.name, er);
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
"hold" => {
|
"hold" => {
|
||||||
if !is_frozen(&self.name).await {
|
if !is_frozen(&self.name).await {
|
||||||
info!("Event on {} `{}` for {}. Freezing ...", dep_type, dep_name, self.name);
|
info!(
|
||||||
|
"Event on {} `{}` for {}. Freezing ...",
|
||||||
|
dep_type, dep_name, self.name
|
||||||
|
);
|
||||||
match freeze_process(&self.name).await {
|
match freeze_process(&self.name).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
info!("Process {} was frozen ...", &self.name);
|
info!("Process {} was frozen ...", &self.name);
|
||||||
self.state = ProcessState::Holding;
|
self.state = ProcessState::Holding;
|
||||||
},
|
}
|
||||||
Err(er) => {
|
Err(er) => {
|
||||||
error!("Cannot freeze process {} : {}", self.name, er);
|
error!("Cannot freeze process {} : {}", self.name, er);
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
"restart" => {
|
"restart" => {
|
||||||
info!("Event on {} `{}` for {}. Restarting ...", dep_type, dep_name, self.name);
|
info!(
|
||||||
|
"Event on {} `{}` for {}. Restarting ...",
|
||||||
|
dep_type, dep_name, self.name
|
||||||
|
);
|
||||||
let pid = restart_process(&self.name, &self.bin).await;
|
let pid = restart_process(&self.name, &self.bin).await;
|
||||||
sleep(Duration::from_millis(100)).await;
|
sleep(Duration::from_millis(100)).await;
|
||||||
if let Ok(pid) = pid {
|
if let Ok(pid) = pid {
|
||||||
self.pid = Pid(pid);
|
self.pid = Pid(pid);
|
||||||
info!("{}: New PID - {}", self.name, self.pid);
|
info!("{}: New PID - {}", self.name, self.pid);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => error!("Impermissible trigger in file-trigger for {}. Ignoring event ...", self.name),
|
_ => error!(
|
||||||
|
"Impermissible trigger in file-trigger for {}. Ignoring event ...",
|
||||||
|
self.name
|
||||||
|
),
|
||||||
}
|
}
|
||||||
tokio::time::sleep(Duration::from_micros(100)).await;
|
tokio::time::sleep(Duration::from_micros(100)).await;
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub async fn stop_by_user_call(&mut self) -> anyhow::Result<()> {
|
pub async fn stop_by_user_call(&mut self) -> anyhow::Result<()> {
|
||||||
terminate_process(&self.name).await?;
|
terminate_process(&self.name).await?;
|
||||||
|
warn!("Process {} was stopped by user call ...", self.name);
|
||||||
self.state = ProcessState::StoppedByCli;
|
self.state = ProcessState::StoppedByCli;
|
||||||
self.pid = Pid::new();
|
self.pid = Pid::new();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -161,28 +183,54 @@ pub mod v2 {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub async fn freeze_by_user_call(&mut self) -> anyhow::Result<()> {
|
pub async fn freeze_by_user_call(&mut self) -> anyhow::Result<()> {
|
||||||
freeze_process(&self.name).await?;
|
freeze_process(&self.name).await?;
|
||||||
|
warn!("Process {} was frozen by user call ...", self.name);
|
||||||
self.state = ProcessState::HoldingByCli;
|
self.state = ProcessState::HoldingByCli;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub async fn start_by_user_call(&mut self) -> anyhow::Result<()> {
|
pub async fn start_by_user_call(&mut self) -> anyhow::Result<()> {
|
||||||
|
if self.negative_events.is_empty() {
|
||||||
let pid = start_process(&self.name, &self.bin).await?;
|
let pid = start_process(&self.name, &self.bin).await?;
|
||||||
|
warn!("Process {} was started by user call ...", self.name);
|
||||||
self.state = ProcessState::Pending;
|
self.state = ProcessState::Pending;
|
||||||
self.pid = Pid(pid);
|
self.pid = Pid(pid);
|
||||||
Ok(())
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
warn!("Attempt to start process {} by user call was stopped due to existance of negative incidents ...", self.name);
|
||||||
|
return Err(anyhow::Error::msg(
|
||||||
|
format!("Attempt to start process {} by user call was stopped due to existance of negative incidents ...", self.name)
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub async fn unfreeze_by_user_call(&mut self) -> anyhow::Result<()> {
|
pub async fn unfreeze_by_user_call(&mut self) -> anyhow::Result<()> {
|
||||||
|
if self.negative_events.is_empty() {
|
||||||
unfreeze_process(&self.name).await?;
|
unfreeze_process(&self.name).await?;
|
||||||
|
warn!("Process {} was unfrozen by user call ...", self.name);
|
||||||
self.state = ProcessState::Pending;
|
self.state = ProcessState::Pending;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else {
|
||||||
|
warn!("Attempt to unfreeze process {} by user call was stopped due to existance of negative incidents ...", self.name);
|
||||||
|
return Err(anyhow::Error::msg(
|
||||||
|
format!("Attempt to unfreeze process {} by user call was stopped due to existance of negative incidents ...", self.name)
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub async fn restart_by_user_call(&mut self) -> anyhow::Result<()> {
|
pub async fn restart_by_user_call(&mut self) -> anyhow::Result<()> {
|
||||||
let pid = restart_process(&self.name, &self.bin).await?;
|
let pid = restart_process(&self.name, &self.bin).await?;
|
||||||
|
warn!("Process {} was restarted by user call ...", self.name);
|
||||||
self.pid = Pid(pid);
|
self.pid = Pid(pid);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_general_info(&self) -> ProcessesGeneral {
|
||||||
|
ProcessesGeneral {
|
||||||
|
name: self.name.to_string(),
|
||||||
|
state: self.state,
|
||||||
|
pid: self.pid,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|
@ -193,50 +241,62 @@ pub mod v2 {
|
||||||
let state = &self.state;
|
let state = &self.state;
|
||||||
match (state, conditions) {
|
match (state, conditions) {
|
||||||
(ProcessState::Holding, (_, _)) => {
|
(ProcessState::Holding, (_, _)) => {
|
||||||
info!("No negative dependecies events on {} frozen process. Unfreezing ...", self.name);
|
info!(
|
||||||
|
"No negative dependecies events on {} frozen process. Unfreezing ...",
|
||||||
|
self.name
|
||||||
|
);
|
||||||
if let Err(er) = unfreeze_process(&self.name).await {
|
if let Err(er) = unfreeze_process(&self.name).await {
|
||||||
error!("Cannot unfreeze process {} : {}", self.name, er);
|
error!("Cannot unfreeze process {} : {}", self.name, er);
|
||||||
} else {
|
} else {
|
||||||
self.state = ProcessState::Pending;
|
self.state = ProcessState::Pending;
|
||||||
info!("Process {} was unfreezed", &self.name);
|
info!("Process {} was unfreezed", &self.name);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
(ProcessState::Stopped, (_, _)) => {
|
(ProcessState::Stopped, (_, _)) => {
|
||||||
info!("No negative dependecies events on stopped {} process. Starting ...", self.name);
|
info!(
|
||||||
|
"No negative dependecies events on stopped {} process. Starting ...",
|
||||||
|
self.name
|
||||||
|
);
|
||||||
match start_process(&self.name, &self.bin).await {
|
match start_process(&self.name, &self.bin).await {
|
||||||
Ok(pid) => {
|
Ok(pid) => {
|
||||||
self.state = ProcessState::Pending;
|
self.state = ProcessState::Pending;
|
||||||
self.pid = Pid(pid);
|
self.pid = Pid(pid);
|
||||||
info!("{}: New PID - {}", self.name, self.pid);
|
info!("{}: New PID - {}", self.name, self.pid);
|
||||||
},
|
}
|
||||||
Err(er) => {
|
Err(er) => {
|
||||||
error!("Cannot start process {} : {}", self.name, er);
|
error!("Cannot start process {} : {}", self.name, er);
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
(ProcessState::Pending, (false, false)) => {
|
(ProcessState::Pending, (false, false)) => {
|
||||||
info!("{} process was impermissibly stopped. Starting ...", self.name);
|
info!(
|
||||||
|
"{} process was impermissibly stopped. Starting ...",
|
||||||
|
self.name
|
||||||
|
);
|
||||||
match start_process(&self.name, &self.bin).await {
|
match start_process(&self.name, &self.bin).await {
|
||||||
Ok(pid) => {
|
Ok(pid) => {
|
||||||
self.state = ProcessState::Pending;
|
self.state = ProcessState::Pending;
|
||||||
self.pid = Pid(pid);
|
self.pid = Pid(pid);
|
||||||
info!("{}: New PID - {}", self.name, self.pid);
|
info!("{}: New PID - {}", self.name, self.pid);
|
||||||
},
|
}
|
||||||
Err(er) => {
|
Err(er) => {
|
||||||
error!("Cannot start process {} : {}", self.name, er);
|
error!("Cannot start process {} : {}", self.name, er);
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
(ProcessState::Pending, (true, true)) => {
|
(ProcessState::Pending, (true, true)) => {
|
||||||
info!("No negative dependecies events on {} process. Unfreezing ...", self.name);
|
info!(
|
||||||
|
"No negative dependecies events on {} process. Unfreezing ...",
|
||||||
|
self.name
|
||||||
|
);
|
||||||
if let Err(er) = unfreeze_process(&self.name).await {
|
if let Err(er) = unfreeze_process(&self.name).await {
|
||||||
error!("Cannot unfreeze process {} : {}", self.name, er);
|
error!("Cannot unfreeze process {} : {}", self.name, er);
|
||||||
} else {
|
} else {
|
||||||
self.state = ProcessState::Pending;
|
self.state = ProcessState::Pending;
|
||||||
info!("Process {} was unfreezed", &self.name);
|
info!("Process {} was unfreezed", &self.name);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while let Ok(event) = self.event_reader.try_recv() {
|
while let Ok(event) = self.event_reader.try_recv() {
|
||||||
|
|
@ -245,22 +305,16 @@ pub mod v2 {
|
||||||
if self.negative_events.contains(&target) {
|
if self.negative_events.contains(&target) {
|
||||||
self.negative_events.remove(&target);
|
self.negative_events.remove(&target);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Events::Negative(event) => {
|
Events::Negative(event) => match event {
|
||||||
match event {
|
NegativeOutcomes::FileWasChanged(target, dep_type, trigger)
|
||||||
NegativeOutcomes::FileWasChanged(target, dep_type, trigger) |
|
| NegativeOutcomes::FileWasMovedOrDeleted(target, dep_type, trigger)
|
||||||
NegativeOutcomes::FileWasMovedOrDeleted(target, dep_type, trigger) |
|
| NegativeOutcomes::ServiceIsUnreachable(target, dep_type, trigger) => {
|
||||||
NegativeOutcomes::ServiceIsUnreachable(target, dep_type, trigger) => {
|
|
||||||
if !self.negative_events.contains(&target) {
|
if !self.negative_events.contains(&target) {
|
||||||
self.negative_events.insert(target.clone());
|
self.negative_events.insert(target.clone());
|
||||||
|
|
||||||
self.trigger_on(
|
self.trigger_on(&target, &trigger, dep_type).await;
|
||||||
&target,
|
|
||||||
&trigger,
|
|
||||||
dep_type
|
|
||||||
).await;
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -382,9 +436,13 @@ pub async fn is_frozen(name: &str) -> bool {
|
||||||
/// *depends on* : -
|
/// *depends on* : -
|
||||||
///
|
///
|
||||||
pub async fn terminate_process(name: &str) -> anyhow::Result<()> {
|
pub async fn terminate_process(name: &str) -> anyhow::Result<()> {
|
||||||
let _ = Command::new("pkill")
|
if !is_active(name).await {
|
||||||
.arg(name)
|
return Err(anyhow::Error::msg(format!(
|
||||||
.output()?;
|
"Process {} is already stopped",
|
||||||
|
name
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let _ = Command::new("pkill").arg(name).output()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -402,9 +460,7 @@ pub async fn terminate_process(name: &str) -> anyhow::Result<()> {
|
||||||
/// *depends on* : -
|
/// *depends on* : -
|
||||||
///
|
///
|
||||||
pub async fn freeze_process(name: &str) -> anyhow::Result<()> {
|
pub async fn freeze_process(name: &str) -> anyhow::Result<()> {
|
||||||
let _ = Command::new("pkill")
|
let _ = Command::new("pkill").args(["-STOP", name]).output()?;
|
||||||
.args(["-STOP", name])
|
|
||||||
.output()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,9 +478,7 @@ pub async fn freeze_process(name: &str) -> anyhow::Result<()> {
|
||||||
/// *depends on* : -
|
/// *depends on* : -
|
||||||
///
|
///
|
||||||
pub async fn unfreeze_process(name: &str) -> anyhow::Result<()> {
|
pub async fn unfreeze_process(name: &str) -> anyhow::Result<()> {
|
||||||
let _ = Command::new("pkill")
|
let _ = Command::new("pkill").args(["-CONT", name]).output()?;
|
||||||
.args(["-CONT", name])
|
|
||||||
.output()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -461,7 +515,12 @@ pub async fn restart_process(name: &str, path: &str) -> anyhow::Result<u32> {
|
||||||
/// *depends on* : -
|
/// *depends on* : -
|
||||||
///
|
///
|
||||||
pub async fn start_process(name: &str, path: &str) -> anyhow::Result<u32> {
|
pub async fn start_process(name: &str, path: &str) -> anyhow::Result<u32> {
|
||||||
// let runsh = format!("{} {}", "exec", path);
|
if is_active(name).await {
|
||||||
|
return Err(anyhow::Error::msg(format!(
|
||||||
|
"Process {} is already running",
|
||||||
|
name
|
||||||
|
)));
|
||||||
|
}
|
||||||
let mut command = Command::new(path);
|
let mut command = Command::new(path);
|
||||||
// command.arg(path);
|
// command.arg(path);
|
||||||
|
|
||||||
|
|
@ -471,9 +530,10 @@ pub async fn start_process(name: &str, path: &str) -> anyhow::Result<u32> {
|
||||||
warn!("Process {} is running now!", name);
|
warn!("Process {} is running now!", name);
|
||||||
Ok(pid)
|
Ok(pid)
|
||||||
}
|
}
|
||||||
Err(er) => {
|
Err(er) => Err(anyhow::Error::msg(format!(
|
||||||
Err(anyhow::Error::msg(format!("Cannot start process {} : {}", name, er)))
|
"Cannot start process {} : {}",
|
||||||
}
|
name, er
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -492,8 +552,7 @@ mod process_unittests {
|
||||||
// let _ = std::io::stdout().write_all(b"");
|
// let _ = std::io::stdout().write_all(b"");
|
||||||
let res1 = start_process("restart-prc", "./tests/examples/restart-prc").await;
|
let res1 = start_process("restart-prc", "./tests/examples/restart-prc").await;
|
||||||
assert!(res1.is_ok());
|
assert!(res1.is_ok());
|
||||||
let res2 =
|
let res2 = restart_process("restart-prc", "./tests/examples/restart-prc").await;
|
||||||
restart_process("restart-prc", "./tests/examples/restart-prc").await;
|
|
||||||
assert!(res2.is_ok());
|
assert!(res2.is_ok());
|
||||||
let _ = terminate_process("restart-prc").await;
|
let _ = terminate_process("restart-prc").await;
|
||||||
let res3 = is_active("restart-prc").await;
|
let res3 = is_active("restart-prc").await;
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use futures::future::Future;
|
||||||
use log::{error, warn};
|
use log::{error, warn};
|
||||||
use std::net::ToSocketAddrs;
|
use std::net::ToSocketAddrs;
|
||||||
use std::sync::Arc;
|
|
||||||
use tokio::time::Duration;
|
|
||||||
use tokio::sync::mpsc::Sender as Sender;
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use futures::future::Future;
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::mpsc::Sender;
|
||||||
|
use tokio::time::Duration;
|
||||||
|
|
||||||
pub mod v2 {
|
pub mod v2 {
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
use crate::options::structs::{Triggers, ProcessUnit, Events, ServiceState};
|
use crate::options::structs::{Events, ProcessUnit, ServiceState, Triggers};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::collections::{HashMap, BTreeMap, VecDeque};
|
use std::collections::{BTreeMap, HashMap, VecDeque};
|
||||||
|
|
||||||
type MpscSender = Arc<Sender<Events>>;
|
type MpscSender = Arc<Sender<Events>>;
|
||||||
// type EventHandlers<'a> = Vec<MpscSender<Events<'a>>>;
|
// type EventHandlers<'a> = Vec<MpscSender<Events<'a>>>;
|
||||||
|
|
@ -55,11 +55,7 @@ pub mod v2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn with_access_name(
|
pub fn with_access_name(mut self, hostname: &str, access_url: &str) -> ServicesController {
|
||||||
mut self,
|
|
||||||
hostname: &str,
|
|
||||||
access_url: &str,
|
|
||||||
) -> ServicesController {
|
|
||||||
self.name = hostname.to_string();
|
self.name = hostname.to_string();
|
||||||
self.access_url = Arc::from(access_url);
|
self.access_url = Arc::from(access_url);
|
||||||
self
|
self
|
||||||
|
|
@ -76,18 +72,21 @@ pub mod v2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_access_url(hostname: &str, port: Option<&u32>) -> String {
|
pub fn get_access_url(hostname: &str, port: Option<&u32>) -> String {
|
||||||
format!("{}{}", hostname, port.map_or_else(|| "".to_string(), |p| format!(":{}", p)))
|
format!(
|
||||||
|
"{}{}",
|
||||||
|
hostname,
|
||||||
|
port.map_or_else(|| "".to_string(), |p| format!(":{}", p))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
pub fn add_process(
|
pub fn get_state(&self) -> ServiceState {
|
||||||
&mut self,
|
self.state
|
||||||
proc_name: &str,
|
}
|
||||||
trigger: Triggers,
|
pub fn add_process(&mut self, proc_name: &str, trigger: Triggers, sender: MpscSender) {
|
||||||
sender: MpscSender,
|
|
||||||
) {
|
|
||||||
let proc_name: Arc<str> = Arc::from(proc_name);
|
let proc_name: Arc<str> = Arc::from(proc_name);
|
||||||
// queue add
|
// queue add
|
||||||
if let Triggers::Service { wait, .. } = trigger {
|
if let Triggers::Service { wait, .. } = trigger {
|
||||||
self.config.entry(wait)
|
self.config
|
||||||
|
.entry(wait)
|
||||||
.and_modify(|el| el.push_back(proc_name.clone()))
|
.and_modify(|el| el.push_back(proc_name.clone()))
|
||||||
.or_insert({
|
.or_insert({
|
||||||
let mut temp = VecDeque::new();
|
let mut temp = VecDeque::new();
|
||||||
|
|
@ -96,14 +95,15 @@ pub mod v2 {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// event add
|
// event add
|
||||||
self.event_registrator.entry(proc_name).or_insert((trigger, sender));
|
self.event_registrator
|
||||||
|
.entry(proc_name)
|
||||||
|
.or_insert((trigger, sender));
|
||||||
}
|
}
|
||||||
async fn check_state(&self) -> anyhow::Result<()> {
|
async fn check_state(&self) -> anyhow::Result<()> {
|
||||||
let url = self.access_url.clone();
|
let url = self.access_url.clone();
|
||||||
let resolve_future = tokio::task::spawn_blocking(move || {
|
let resolve_future = tokio::task::spawn_blocking(move || url.to_socket_addrs());
|
||||||
url.to_socket_addrs()
|
let addrs: Vec<_> =
|
||||||
});
|
match tokio::time::timeout(Duration::from_secs(1), resolve_future).await {
|
||||||
let addrs: Vec<_> = match tokio::time::timeout(Duration::from_secs(1), resolve_future).await {
|
|
||||||
Ok(Ok(addrs)) => addrs?.collect(),
|
Ok(Ok(addrs)) => addrs?.collect(),
|
||||||
Ok(Err(er)) => return Err(er.into()),
|
Ok(Err(er)) => return Err(er.into()),
|
||||||
Err(_) => return Err(anyhow::Error::msg("DNS resolution timeout")),
|
Err(_) => return Err(anyhow::Error::msg("DNS resolution timeout")),
|
||||||
|
|
@ -113,12 +113,20 @@ pub mod v2 {
|
||||||
return Err(anyhow::Error::msg("No addresses resolved"));
|
return Err(anyhow::Error::msg("No addresses resolved"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let tasks: Vec<_> = addrs.into_iter().map(|addr| async move {
|
let tasks: Vec<_> = addrs
|
||||||
match tokio::time::timeout(Duration::from_secs(2), tokio::net::TcpStream::connect(&addr)).await {
|
.into_iter()
|
||||||
|
.map(|addr| async move {
|
||||||
|
match tokio::time::timeout(
|
||||||
|
Duration::from_secs(2),
|
||||||
|
tokio::net::TcpStream::connect(&addr),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(Ok(_)) => Some(addr),
|
Ok(Ok(_)) => Some(addr),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}).collect();
|
})
|
||||||
|
.collect();
|
||||||
let mut any_success = false;
|
let mut any_success = false;
|
||||||
for task in futures::future::join_all(tasks).await {
|
for task in futures::future::join_all(tasks).await {
|
||||||
if task.is_some() {
|
if task.is_some() {
|
||||||
|
|
@ -127,7 +135,10 @@ pub mod v2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !any_success {
|
if !any_success {
|
||||||
return Err(anyhow::Error::msg(format!("No access to service `{}`", &self.access_url)));
|
return Err(anyhow::Error::msg(format!(
|
||||||
|
"No access to service `{}`",
|
||||||
|
&self.access_url
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -135,7 +146,9 @@ pub mod v2 {
|
||||||
async fn trigger_on(&mut self) {
|
async fn trigger_on(&mut self) {
|
||||||
match self.state {
|
match self.state {
|
||||||
ServiceState::Ok => {
|
ServiceState::Ok => {
|
||||||
let futures : Vec<Pin<Box<dyn Future<Output = ()> + Send>>> = self.event_registrator.iter()
|
let futures: Vec<Pin<Box<dyn Future<Output = ()> + Send>>> = self
|
||||||
|
.event_registrator
|
||||||
|
.iter()
|
||||||
.map(|(prc, (_, sender_opt))| (prc, (self.access_url.clone(), sender_opt)))
|
.map(|(prc, (_, sender_opt))| (prc, (self.access_url.clone(), sender_opt)))
|
||||||
.map(|(prc, (serv, sender_opt))| async move {
|
.map(|(prc, (serv, sender_opt))| async move {
|
||||||
info!("Notifying process {} ...", prc);
|
info!("Notifying process {} ...", prc);
|
||||||
|
|
@ -145,11 +158,11 @@ pub mod v2 {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
futures::future::join_all(futures).await;
|
futures::future::join_all(futures).await;
|
||||||
},
|
}
|
||||||
ServiceState::Unavailable => {
|
ServiceState::Unavailable => {
|
||||||
// looped check and notifying
|
// looped check and notifying
|
||||||
self.looped_check().await;
|
self.looped_check().await;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fn looped_check(self: &mut Self) {
|
async fn looped_check(self: &mut Self) {
|
||||||
|
|
@ -160,11 +173,16 @@ pub mod v2 {
|
||||||
let mut attempt: u32 = 1;
|
let mut attempt: u32 = 1;
|
||||||
let access_url = Arc::new(self.access_url.clone());
|
let access_url = Arc::new(self.access_url.clone());
|
||||||
|
|
||||||
if let Err(_) = tokio::time::timeout(tokio::time::Duration::from_secs((longest + 1) as u64), async {
|
if let Err(_) = tokio::time::timeout(
|
||||||
|
tokio::time::Duration::from_secs((longest + 1) as u64),
|
||||||
|
async {
|
||||||
// let access_url = access_url.clone();
|
// let access_url = access_url.clone();
|
||||||
loop {
|
loop {
|
||||||
interapter.tick().await;
|
interapter.tick().await;
|
||||||
info!("Trying to connect to {} (attempt: {}) ...", &access_url, attempt);
|
info!(
|
||||||
|
"Trying to connect to {} (attempt: {}) ...",
|
||||||
|
&access_url, attempt
|
||||||
|
);
|
||||||
attempt += 1;
|
attempt += 1;
|
||||||
|
|
||||||
let state_check_result = self.check_state().await;
|
let state_check_result = self.check_state().await;
|
||||||
|
|
@ -172,8 +190,12 @@ pub mod v2 {
|
||||||
if state_check_result.is_ok() {
|
if state_check_result.is_ok() {
|
||||||
info!("Connection to {} is `OK` now", &access_url);
|
info!("Connection to {} is `OK` now", &access_url);
|
||||||
self.state = ServiceState::Ok;
|
self.state = ServiceState::Ok;
|
||||||
let futures : Vec<Pin<Box<dyn Future<Output = ()> + Send>>> = self.event_registrator.iter()
|
let futures: Vec<Pin<Box<dyn Future<Output = ()> + Send>>> = self
|
||||||
.map(|(prc, (_, sender_opt))| (prc, (self.access_url.clone(), sender_opt)))
|
.event_registrator
|
||||||
|
.iter()
|
||||||
|
.map(|(prc, (_, sender_opt))| {
|
||||||
|
(prc, (self.access_url.clone(), sender_opt))
|
||||||
|
})
|
||||||
.map(|(prc, (serv, sender_opt))| async move {
|
.map(|(prc, (serv, sender_opt))| async move {
|
||||||
info!("Notifying process {} ...", prc);
|
info!("Notifying process {} ...", prc);
|
||||||
let _ = sender_opt.send(Events::Positive(serv.clone()));
|
let _ = sender_opt.send(Events::Positive(serv.clone()));
|
||||||
|
|
@ -186,31 +208,49 @@ pub mod v2 {
|
||||||
} else {
|
} else {
|
||||||
let now = timer.elapsed();
|
let now = timer.elapsed();
|
||||||
|
|
||||||
let iterator = self.config.iter()
|
let iterator = self
|
||||||
.filter(|(&wait, _)| tokio::time::Duration::from_secs(wait as u64) <= now)
|
.config
|
||||||
|
.iter()
|
||||||
|
.filter(|(&wait, _)| {
|
||||||
|
tokio::time::Duration::from_secs(wait as u64) <= now
|
||||||
|
})
|
||||||
.flat_map(|(_, a)| a.iter().cloned())
|
.flat_map(|(_, a)| a.iter().cloned())
|
||||||
.collect::<VecDeque<Arc<str>>>();
|
.collect::<VecDeque<Arc<str>>>();
|
||||||
|
|
||||||
for name in iterator {
|
for name in iterator {
|
||||||
let proc_name = name.to_string();
|
let proc_name = name.to_string();
|
||||||
info!("Trying to notify process `{}` ...", &proc_name);
|
info!("Trying to notify process `{}` ...", &proc_name);
|
||||||
let sender_opt = self.event_registrator.get(&name)
|
let sender_opt =
|
||||||
.map(|(trigger, sender)|
|
self.event_registrator.get(&name).map(|(trigger, sender)| {
|
||||||
(trigger.to_service_negative_event(self.access_url.clone()), sender)
|
(
|
||||||
);
|
trigger
|
||||||
|
.to_service_negative_event(self.access_url.clone()),
|
||||||
|
sender,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
if let Some((tr, tx)) = sender_opt {
|
if let Some((tr, tx)) = sender_opt {
|
||||||
let _ = tx.send(tr.unwrap()).await;
|
let _ = tx.send(tr.unwrap()).await;
|
||||||
} else {
|
} else {
|
||||||
error!("Cannot find {} channel sender in {} service", name.clone(), &self.access_url)
|
error!(
|
||||||
|
"Cannot find {} channel sender in {} service",
|
||||||
|
name.clone(),
|
||||||
|
&self.access_url
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).await {
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
info!("Timeout of establishing connection to {}. ", &access_url);
|
info!("Timeout of establishing connection to {}. ", &access_url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn get_arc_access_url(&self) -> Arc<str> {
|
||||||
|
self.access_url.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl ProcessUnit for ServicesController {
|
impl ProcessUnit for ServicesController {
|
||||||
|
|
@ -222,14 +262,16 @@ pub mod v2 {
|
||||||
warn!("Connection with `{}` service was established. Notifying {} process(es) ...", &self.access_url, &self.event_registrator.len());
|
warn!("Connection with `{}` service was established. Notifying {} process(es) ...", &self.access_url, &self.event_registrator.len());
|
||||||
self.state = ServiceState::Ok;
|
self.state = ServiceState::Ok;
|
||||||
self.trigger_on().await;
|
self.trigger_on().await;
|
||||||
},
|
}
|
||||||
(ServiceState::Ok, Err(_)) => {
|
(ServiceState::Ok, Err(_)) => {
|
||||||
warn!("Unreachable for connection service `{}`. Initializing reconnect mechanism ...", &self.access_url);
|
warn!("Unreachable for connection service `{}`. Initializing reconnect mechanism ...", &self.access_url);
|
||||||
self.state = ServiceState::Unavailable;
|
self.state = ServiceState::Unavailable;
|
||||||
self.trigger_on().await;
|
self.trigger_on().await;
|
||||||
},
|
}
|
||||||
(ServiceState::Unavailable, Err(_)) => warn!("Service {} is still unreachable", &self.access_url),
|
(ServiceState::Unavailable, Err(_)) => {
|
||||||
_ => { /* DEAD END WITH NO INTEREST */ },
|
warn!("Service {} is still unreachable", &self.access_url)
|
||||||
|
}
|
||||||
|
_ => { /* DEAD END WITH NO INTEREST */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue