271 lines
8.0 KiB
Rust
271 lines
8.0 KiB
Rust
use clap::Parser;
|
|
use figment::{
|
|
Figment,
|
|
providers::{Format, Serialized, Yaml},
|
|
};
|
|
use log::warn;
|
|
use serde::{Deserialize, Serialize};
|
|
use std::error::Error;
|
|
use std::path::PathBuf;
|
|
|
|
#[allow(unused)]
|
|
use flexi_logger::{
|
|
FileSpec, LogSpecification, Logger, LoggerHandle, colored_with_thread, with_thread,
|
|
writers::{SyslogConnection, SyslogLineHeader, SyslogWriter},
|
|
};
|
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
pub(crate) struct DataFunctionsInterval {
|
|
pub(crate) log_debug_watcher: Option<u64>,
|
|
multipath: Option<u64>,
|
|
meminfo: Option<u64>,
|
|
processes: Option<u64>,
|
|
bonding: Option<u64>,
|
|
filesum: Option<u64>,
|
|
}
|
|
|
|
impl Default for DataFunctionsInterval {
|
|
fn default() -> Self {
|
|
DataFunctionsInterval {
|
|
log_debug_watcher: Some(5),
|
|
multipath: Some(60),
|
|
meminfo: Some(30),
|
|
processes: Some(30),
|
|
bonding: Some(30),
|
|
filesum: Some(60),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DataFunctionsInterval {
|
|
pub fn meminfo(&self) -> Option<u64> {
|
|
self.meminfo
|
|
}
|
|
pub fn processes(&self) -> Option<u64> {
|
|
self.processes
|
|
}
|
|
pub fn filesum(&self) -> Option<u64> {
|
|
self.filesum
|
|
}
|
|
pub fn bonding(&self) -> Option<u64> {
|
|
self.bonding
|
|
}
|
|
pub fn multipath(&self) -> Option<u64> {
|
|
self.multipath
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Debug, Clone)]
|
|
pub(crate) struct DataFunctionsFilesum {
|
|
pub(crate) passwd: Option<String>,
|
|
pub(crate) shadow: Option<String>,
|
|
pub(crate) group: Option<String>,
|
|
pub(crate) authorized_keys: Option<String>,
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
pub struct DataFunctionsExtra {
|
|
multipath: Option<String>,
|
|
bonding: Option<String>,
|
|
filesum: DataFunctionsFilesum,
|
|
}
|
|
|
|
impl Default for DataFunctionsExtra {
|
|
fn default() -> Self {
|
|
DataFunctionsExtra {
|
|
multipath: None,
|
|
bonding: None,
|
|
filesum: DataFunctionsFilesum {
|
|
passwd: None,
|
|
shadow: None,
|
|
group: None,
|
|
authorized_keys: None,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DataFunctionsExtra {
|
|
pub(crate) fn filesum(&self) -> DataFunctionsFilesum {
|
|
self.filesum.clone()
|
|
}
|
|
pub(crate) fn multipath(&self) -> Option<String> {
|
|
self.multipath.clone()
|
|
}
|
|
pub(crate) fn bonding(&self) -> Option<String> {
|
|
self.bonding.clone()
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Debug, Clone, clap::ValueEnum)]
|
|
enum LogConfig {
|
|
None,
|
|
StdErr,
|
|
Syslog,
|
|
Logfile,
|
|
LogfileAndSyslog,
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
pub struct AppConfig {
|
|
logoutput: LogConfig,
|
|
logdir: String,
|
|
logfile_basename: String,
|
|
loglevel: String,
|
|
pub(crate) base_oid: String,
|
|
pub(crate) debug_log_marker: PathBuf,
|
|
pub(crate) intervals: DataFunctionsInterval,
|
|
pub(crate) extra_config: DataFunctionsExtra,
|
|
}
|
|
|
|
impl Default for AppConfig {
|
|
fn default() -> Self {
|
|
AppConfig {
|
|
logoutput: LogConfig::Logfile,
|
|
logdir: "log".to_string(),
|
|
logfile_basename: "rsnmpagent".to_string(),
|
|
loglevel: "info".to_string(),
|
|
base_oid: ".1.3.6.1.4.1.8072.9999.9999".to_string(),
|
|
debug_log_marker: "debug.marker".to_string().into(),
|
|
intervals: DataFunctionsInterval::default(),
|
|
extra_config: DataFunctionsExtra::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl AppConfig {
|
|
pub fn base_oid(&self) -> &str {
|
|
&self.base_oid
|
|
}
|
|
}
|
|
|
|
// Define the struct to hold the command-line arguments.
|
|
#[derive(Parser, Deserialize, Serialize, Debug)]
|
|
#[command(author, version, about = "rsnmpd, snmpd passpersist extension", long_about = None)]
|
|
struct Cli {
|
|
/// Optional path to a configuration file.
|
|
#[arg(short, long, value_name = "FILENAME", default_value = "config.yml")]
|
|
configfile: PathBuf,
|
|
|
|
#[arg(short, long, value_name = "LOGOUTPUT", value_enum, default_value_t = LogConfig::Logfile)]
|
|
logoutput: LogConfig,
|
|
|
|
#[arg(short, long)]
|
|
show_parsed_config: bool,
|
|
}
|
|
|
|
pub fn build_config() -> Result<AppConfig, Box<dyn Error>> {
|
|
let cli = Cli::parse();
|
|
|
|
#[cfg(debug_assertions)]
|
|
if cli.show_parsed_config {
|
|
eprintln!("Parsed config line options: {:#?}", cli);
|
|
}
|
|
|
|
let config: AppConfig = Figment::new()
|
|
.merge(Serialized::defaults(AppConfig::default()))
|
|
.merge(Yaml::file(&cli.configfile))
|
|
.merge(Serialized::defaults(&cli))
|
|
.extract()?;
|
|
|
|
if cli.show_parsed_config {
|
|
eprintln!("Loaded configuration: {:#?}", config);
|
|
}
|
|
|
|
Ok(config)
|
|
}
|
|
|
|
pub fn start_logging(config: &AppConfig) -> Result<LoggerHandle, Box<dyn Error>> {
|
|
let r = match config.logoutput {
|
|
LogConfig::None => {
|
|
let handle = Logger::with(LogSpecification::off()).do_not_log().start()?;
|
|
warn!("Starting None logging config");
|
|
handle
|
|
}
|
|
LogConfig::StdErr => {
|
|
let handle = Logger::try_with_str(&config.loglevel)?
|
|
.format(colored_with_thread)
|
|
.start()?;
|
|
warn!("Starting StdErr logging config with level: {}", config.loglevel);
|
|
handle
|
|
}
|
|
LogConfig::Syslog => {
|
|
#[cfg(target_os = "windows")]
|
|
{
|
|
Err("Syslog in windows not implemented")?
|
|
}
|
|
#[cfg(target_os = "linux")]
|
|
{
|
|
let syslog_writer = SyslogWriter::builder(
|
|
SyslogConnection::syslog_call(),
|
|
SyslogLineHeader::Rfc3164,
|
|
flexi_logger::writers::SyslogFacility::SystemDaemons,
|
|
)
|
|
.build()?;
|
|
let handle = Logger::try_with_str(&config.loglevel)?
|
|
.log_to_writer(syslog_writer)
|
|
.format(with_thread)
|
|
.start()?;
|
|
warn!("Starting Syslog logging config with level: {}", config.loglevel);
|
|
handle
|
|
}
|
|
}
|
|
LogConfig::Logfile => {
|
|
let handle = Logger::try_with_str(&config.loglevel)?
|
|
.log_to_file(
|
|
FileSpec::default()
|
|
.directory(&config.logdir)
|
|
.basename(&config.logfile_basename)
|
|
.suppress_timestamp(),
|
|
)
|
|
.append()
|
|
.format(with_thread)
|
|
.start()?;
|
|
warn!(
|
|
"Starting Logfile logging to {} with level: {}",
|
|
config.logdir, config.loglevel
|
|
);
|
|
handle
|
|
}
|
|
LogConfig::LogfileAndSyslog => {
|
|
#[cfg(target_os = "windows")]
|
|
{
|
|
eprintln!(
|
|
"Starting LogfileAndSyslog logging to {} with level: {}",
|
|
config.logdir, config.loglevel
|
|
);
|
|
Err("Syslog in windows not implemented")?
|
|
}
|
|
#[cfg(target_os = "linux")]
|
|
{
|
|
let handle = Logger::try_with_str(&config.loglevel)
|
|
.expect("Log start failed")
|
|
.log_to_file(
|
|
FileSpec::default()
|
|
.directory(&config.logdir)
|
|
.basename(&config.logfile_basename)
|
|
.suppress_timestamp(),
|
|
)
|
|
.append()
|
|
.format(with_thread)
|
|
.add_writer(
|
|
"syslog",
|
|
SyslogWriter::builder(
|
|
SyslogConnection::syslog_call(),
|
|
SyslogLineHeader::Rfc3164,
|
|
flexi_logger::writers::SyslogFacility::SystemDaemons,
|
|
)
|
|
.build()?,
|
|
)
|
|
.start()?;
|
|
warn!(
|
|
"Starting LogfileAndSyslog logging to {} with level: {}",
|
|
config.logdir, config.loglevel
|
|
);
|
|
handle
|
|
}
|
|
}
|
|
};
|
|
Ok(r)
|
|
}
|