mirror of https://github.com/breard-r/acmed.git
				
				
			
				
				  
				  Failed to extract signature
				  
				
			
		
		
		
	
				 5 changed files with 462 additions and 6 deletions
			
			
		- 
					157Cargo.lock
 - 
					1Cargo.toml
 - 
					259src/cli.rs
 - 
					30src/log.rs
 - 
					21src/main.rs
 
@ -0,0 +1,259 @@ | 
				
			|||
use crate::log::Level;
 | 
				
			|||
use clap::{Args, Parser};
 | 
				
			|||
use std::path::{Path, PathBuf};
 | 
				
			|||
 | 
				
			|||
#[derive(Parser, Debug)]
 | 
				
			|||
#[command(version, about, long_about = None)]
 | 
				
			|||
pub struct CliArgs {
 | 
				
			|||
	/// Path to the main configuration file
 | 
				
			|||
	#[arg(short, long, value_name = "FILE", default_value = crate::DEFAULT_CONFIG_PATH)]
 | 
				
			|||
	pub config: PathBuf,
 | 
				
			|||
 | 
				
			|||
	/// Specify the log level
 | 
				
			|||
	#[arg(long, value_name = "LEVEL", value_enum, default_value_t = crate::DEFAULT_LOG_LEVEL)]
 | 
				
			|||
	pub log_level: Level,
 | 
				
			|||
 | 
				
			|||
	#[command(flatten)]
 | 
				
			|||
	pub log: Log,
 | 
				
			|||
 | 
				
			|||
	/// Runs in the foreground
 | 
				
			|||
	#[arg(short, long, default_value_t = false)]
 | 
				
			|||
	pub foreground: bool,
 | 
				
			|||
 | 
				
			|||
	#[command(flatten)]
 | 
				
			|||
	pub pid: Pid,
 | 
				
			|||
 | 
				
			|||
	/// Add a root certificate to the trust store (can be set multiple times)
 | 
				
			|||
	#[arg(long, value_name = "FILE")]
 | 
				
			|||
	pub root_cert: Vec<PathBuf>,
 | 
				
			|||
}
 | 
				
			|||
 | 
				
			|||
#[derive(Args, Debug)]
 | 
				
			|||
#[group(multiple = false)]
 | 
				
			|||
pub struct Log {
 | 
				
			|||
	/// Sends log messages via syslog
 | 
				
			|||
	#[arg(long)]
 | 
				
			|||
	pub log_syslog: bool,
 | 
				
			|||
 | 
				
			|||
	/// Prints log messages to the standard error output
 | 
				
			|||
	#[arg(long)]
 | 
				
			|||
	pub log_stderr: bool,
 | 
				
			|||
}
 | 
				
			|||
 | 
				
			|||
#[derive(Args, Debug)]
 | 
				
			|||
#[group(multiple = false)]
 | 
				
			|||
pub struct Pid {
 | 
				
			|||
	/// Path to the PID file
 | 
				
			|||
	#[arg(long, value_name = "FILE", default_value = crate::DEFAULT_PID_FILE)]
 | 
				
			|||
	pid_file: PathBuf,
 | 
				
			|||
 | 
				
			|||
	/// Do not create any PID file
 | 
				
			|||
	#[arg(long)]
 | 
				
			|||
	no_pid_file: bool,
 | 
				
			|||
}
 | 
				
			|||
 | 
				
			|||
impl Pid {
 | 
				
			|||
	pub fn get_pid_file(&self) -> Option<&Path> {
 | 
				
			|||
		if !self.no_pid_file {
 | 
				
			|||
			Some(self.pid_file.as_path())
 | 
				
			|||
		} else {
 | 
				
			|||
			None
 | 
				
			|||
		}
 | 
				
			|||
	}
 | 
				
			|||
}
 | 
				
			|||
 | 
				
			|||
#[cfg(test)]
 | 
				
			|||
mod tests {
 | 
				
			|||
	use super::*;
 | 
				
			|||
	use clap::CommandFactory;
 | 
				
			|||
 | 
				
			|||
	#[test]
 | 
				
			|||
	fn verify_cli() {
 | 
				
			|||
		CliArgs::command().debug_assert();
 | 
				
			|||
	}
 | 
				
			|||
 | 
				
			|||
	#[test]
 | 
				
			|||
	fn no_args() {
 | 
				
			|||
		let args: &[&str] = &[];
 | 
				
			|||
		let pa = CliArgs::try_parse_from(args).unwrap();
 | 
				
			|||
		assert_eq!(pa.config, PathBuf::from(crate::DEFAULT_CONFIG_PATH));
 | 
				
			|||
		assert_eq!(pa.log_level, Level::Warn);
 | 
				
			|||
		assert_eq!(pa.log.log_syslog, false);
 | 
				
			|||
		assert_eq!(pa.log.log_stderr, false);
 | 
				
			|||
		assert_eq!(pa.foreground, false);
 | 
				
			|||
		assert_eq!(pa.pid.pid_file, PathBuf::from(crate::DEFAULT_PID_FILE));
 | 
				
			|||
		assert_eq!(pa.pid.no_pid_file, false);
 | 
				
			|||
		assert_eq!(
 | 
				
			|||
			pa.pid.get_pid_file(),
 | 
				
			|||
			Some(PathBuf::from(crate::DEFAULT_PID_FILE).as_path())
 | 
				
			|||
		);
 | 
				
			|||
		assert!(pa.root_cert.is_empty());
 | 
				
			|||
	}
 | 
				
			|||
 | 
				
			|||
	#[test]
 | 
				
			|||
	fn all_args_long_1() {
 | 
				
			|||
		let argv: &[&str] = &[
 | 
				
			|||
			"acmed",
 | 
				
			|||
			"--config",
 | 
				
			|||
			"/tmp/test.toml",
 | 
				
			|||
			"--log-level",
 | 
				
			|||
			"debug",
 | 
				
			|||
			"--log-syslog",
 | 
				
			|||
			"--foreground",
 | 
				
			|||
			"--pid-file",
 | 
				
			|||
			"/tmp/debug/acmed.pid",
 | 
				
			|||
			"--root-cert",
 | 
				
			|||
			"/tmp/certs/root_01.pem",
 | 
				
			|||
			"--root-cert",
 | 
				
			|||
			"/tmp/certs/root_02.pem",
 | 
				
			|||
			"--root-cert",
 | 
				
			|||
			"/tmp/certs/root_03.pem",
 | 
				
			|||
		];
 | 
				
			|||
		let pa = CliArgs::try_parse_from(argv).unwrap();
 | 
				
			|||
		assert_eq!(pa.config, PathBuf::from("/tmp/test.toml"));
 | 
				
			|||
		assert_eq!(pa.log_level, Level::Debug);
 | 
				
			|||
		assert_eq!(pa.log.log_syslog, true);
 | 
				
			|||
		assert_eq!(pa.log.log_stderr, false);
 | 
				
			|||
		assert_eq!(pa.foreground, true);
 | 
				
			|||
		assert_eq!(
 | 
				
			|||
			pa.pid.get_pid_file(),
 | 
				
			|||
			Some(PathBuf::from("/tmp/debug/acmed.pid").as_path())
 | 
				
			|||
		);
 | 
				
			|||
		assert_eq!(
 | 
				
			|||
			pa.root_cert,
 | 
				
			|||
			vec![
 | 
				
			|||
				PathBuf::from("/tmp/certs/root_01.pem"),
 | 
				
			|||
				PathBuf::from("/tmp/certs/root_02.pem"),
 | 
				
			|||
				PathBuf::from("/tmp/certs/root_03.pem")
 | 
				
			|||
			]
 | 
				
			|||
		);
 | 
				
			|||
	}
 | 
				
			|||
 | 
				
			|||
	#[test]
 | 
				
			|||
	fn all_args_long_2() {
 | 
				
			|||
		let argv: &[&str] = &[
 | 
				
			|||
			"acmed",
 | 
				
			|||
			"--config",
 | 
				
			|||
			"/tmp/test.toml",
 | 
				
			|||
			"--log-level",
 | 
				
			|||
			"debug",
 | 
				
			|||
			"--log-stderr",
 | 
				
			|||
			"--foreground",
 | 
				
			|||
			"--no-pid-file",
 | 
				
			|||
			"--root-cert",
 | 
				
			|||
			"/tmp/certs/root_01.pem",
 | 
				
			|||
			"--root-cert",
 | 
				
			|||
			"/tmp/certs/root_02.pem",
 | 
				
			|||
			"--root-cert",
 | 
				
			|||
			"/tmp/certs/root_03.pem",
 | 
				
			|||
		];
 | 
				
			|||
		let pa = CliArgs::try_parse_from(argv).unwrap();
 | 
				
			|||
		assert_eq!(pa.config, PathBuf::from("/tmp/test.toml"));
 | 
				
			|||
		assert_eq!(pa.log_level, Level::Debug);
 | 
				
			|||
		assert_eq!(pa.log.log_syslog, false);
 | 
				
			|||
		assert_eq!(pa.log.log_stderr, true);
 | 
				
			|||
		assert_eq!(pa.foreground, true);
 | 
				
			|||
		assert_eq!(pa.pid.get_pid_file(), None);
 | 
				
			|||
		assert_eq!(
 | 
				
			|||
			pa.root_cert,
 | 
				
			|||
			vec![
 | 
				
			|||
				PathBuf::from("/tmp/certs/root_01.pem"),
 | 
				
			|||
				PathBuf::from("/tmp/certs/root_02.pem"),
 | 
				
			|||
				PathBuf::from("/tmp/certs/root_03.pem")
 | 
				
			|||
			]
 | 
				
			|||
		);
 | 
				
			|||
	}
 | 
				
			|||
 | 
				
			|||
	#[test]
 | 
				
			|||
	fn all_args_short_1() {
 | 
				
			|||
		let argv: &[&str] = &[
 | 
				
			|||
			"acmed",
 | 
				
			|||
			"-c",
 | 
				
			|||
			"/tmp/test.toml",
 | 
				
			|||
			"--log-level",
 | 
				
			|||
			"debug",
 | 
				
			|||
			"--log-syslog",
 | 
				
			|||
			"-f",
 | 
				
			|||
			"--pid-file",
 | 
				
			|||
			"/tmp/debug/acmed.pid",
 | 
				
			|||
			"--root-cert",
 | 
				
			|||
			"/tmp/certs/root_01.pem",
 | 
				
			|||
			"--root-cert",
 | 
				
			|||
			"/tmp/certs/root_02.pem",
 | 
				
			|||
			"--root-cert",
 | 
				
			|||
			"/tmp/certs/root_03.pem",
 | 
				
			|||
		];
 | 
				
			|||
		let pa = CliArgs::try_parse_from(argv).unwrap();
 | 
				
			|||
		assert_eq!(pa.config, PathBuf::from("/tmp/test.toml"));
 | 
				
			|||
		assert_eq!(pa.log_level, Level::Debug);
 | 
				
			|||
		assert_eq!(pa.log.log_syslog, true);
 | 
				
			|||
		assert_eq!(pa.log.log_stderr, false);
 | 
				
			|||
		assert_eq!(pa.foreground, true);
 | 
				
			|||
		assert_eq!(
 | 
				
			|||
			pa.pid.get_pid_file(),
 | 
				
			|||
			Some(PathBuf::from("/tmp/debug/acmed.pid").as_path())
 | 
				
			|||
		);
 | 
				
			|||
		assert_eq!(
 | 
				
			|||
			pa.root_cert,
 | 
				
			|||
			vec![
 | 
				
			|||
				PathBuf::from("/tmp/certs/root_01.pem"),
 | 
				
			|||
				PathBuf::from("/tmp/certs/root_02.pem"),
 | 
				
			|||
				PathBuf::from("/tmp/certs/root_03.pem")
 | 
				
			|||
			]
 | 
				
			|||
		);
 | 
				
			|||
	}
 | 
				
			|||
 | 
				
			|||
	#[test]
 | 
				
			|||
	fn all_args_short_2() {
 | 
				
			|||
		let argv: &[&str] = &[
 | 
				
			|||
			"acmed",
 | 
				
			|||
			"-c",
 | 
				
			|||
			"/tmp/test.toml",
 | 
				
			|||
			"--log-level",
 | 
				
			|||
			"debug",
 | 
				
			|||
			"--log-stderr",
 | 
				
			|||
			"-f",
 | 
				
			|||
			"--no-pid-file",
 | 
				
			|||
			"--root-cert",
 | 
				
			|||
			"/tmp/certs/root_01.pem",
 | 
				
			|||
			"--root-cert",
 | 
				
			|||
			"/tmp/certs/root_02.pem",
 | 
				
			|||
			"--root-cert",
 | 
				
			|||
			"/tmp/certs/root_03.pem",
 | 
				
			|||
		];
 | 
				
			|||
		let pa = CliArgs::try_parse_from(argv).unwrap();
 | 
				
			|||
		assert_eq!(pa.config, PathBuf::from("/tmp/test.toml"));
 | 
				
			|||
		assert_eq!(pa.log_level, Level::Debug);
 | 
				
			|||
		assert_eq!(pa.log.log_syslog, false);
 | 
				
			|||
		assert_eq!(pa.log.log_stderr, true);
 | 
				
			|||
		assert_eq!(pa.foreground, true);
 | 
				
			|||
		assert_eq!(pa.pid.get_pid_file(), None);
 | 
				
			|||
		assert_eq!(
 | 
				
			|||
			pa.root_cert,
 | 
				
			|||
			vec![
 | 
				
			|||
				PathBuf::from("/tmp/certs/root_01.pem"),
 | 
				
			|||
				PathBuf::from("/tmp/certs/root_02.pem"),
 | 
				
			|||
				PathBuf::from("/tmp/certs/root_03.pem")
 | 
				
			|||
			]
 | 
				
			|||
		);
 | 
				
			|||
	}
 | 
				
			|||
 | 
				
			|||
	#[test]
 | 
				
			|||
	fn err_log_output() {
 | 
				
			|||
		let argv: &[&str] = &["acmed", "--log-stderr", "--log-syslog"];
 | 
				
			|||
		let pa = CliArgs::try_parse_from(argv);
 | 
				
			|||
		assert!(pa.is_err());
 | 
				
			|||
	}
 | 
				
			|||
 | 
				
			|||
	#[test]
 | 
				
			|||
	fn err_pid_file() {
 | 
				
			|||
		let argv: &[&str] = &[
 | 
				
			|||
			"acmed",
 | 
				
			|||
			"--pid-file",
 | 
				
			|||
			"/tmp/debug/acmed.pid",
 | 
				
			|||
			"--no-pid-file",
 | 
				
			|||
		];
 | 
				
			|||
		let pa = CliArgs::try_parse_from(argv);
 | 
				
			|||
		assert!(pa.is_err());
 | 
				
			|||
	}
 | 
				
			|||
}
 | 
				
			|||
@ -0,0 +1,30 @@ | 
				
			|||
use clap::ValueEnum;
 | 
				
			|||
use tracing_subscriber::FmtSubscriber;
 | 
				
			|||
 | 
				
			|||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
 | 
				
			|||
pub enum Level {
 | 
				
			|||
	Error,
 | 
				
			|||
	Warn,
 | 
				
			|||
	Info,
 | 
				
			|||
	Debug,
 | 
				
			|||
	Trace,
 | 
				
			|||
}
 | 
				
			|||
 | 
				
			|||
impl Level {
 | 
				
			|||
	fn tracing(&self) -> tracing::Level {
 | 
				
			|||
		match self {
 | 
				
			|||
			Self::Error => tracing::Level::ERROR,
 | 
				
			|||
			Self::Warn => tracing::Level::WARN,
 | 
				
			|||
			Self::Info => tracing::Level::INFO,
 | 
				
			|||
			Self::Debug => tracing::Level::DEBUG,
 | 
				
			|||
			Self::Trace => tracing::Level::TRACE,
 | 
				
			|||
		}
 | 
				
			|||
	}
 | 
				
			|||
}
 | 
				
			|||
 | 
				
			|||
pub fn init(level: Level, is_syslog: bool) {
 | 
				
			|||
	let subscriber = FmtSubscriber::builder()
 | 
				
			|||
		.with_max_level(level.tracing())
 | 
				
			|||
		.finish();
 | 
				
			|||
	tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
 | 
				
			|||
}
 | 
				
			|||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue