A library for writing host-specific, single-binary configuration management and deployment tools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
3.9 KiB

use regex::Regex;
use command_runner::CommandRunner;
use loggers::StdErrLogger;
use repository::SymbolRepository;
use resources::Resource;
use schema::{NonRepeatingSymbolRunner, ReportingSymbolRunner, RequirementsResolvingSymbolRunner};
use symbols::dir::Dir;
use symbols::list::List;
use symbols::owner::Owner;
use symbols::systemd::user_session::SystemdUserSession;
use symbols::tls::{TlsCsr, TlsKey};
use symbols::user::SystemUserAdder;
use symbols::user::{User, UserAdder};
use symbols::{Symbol, SymbolRunner};
#[derive(Default)]
pub struct Factory {}
impl Factory {
pub fn new() -> Self {
Default::default()
}
pub fn get_repo<'a, CR: CommandRunner>(
&self,
command_runner: &'a CR,
) -> DefaultSymbolRepository<'a, SystemUserAdder<'a, CR>, CR> {
DefaultSymbolRepository::new(command_runner)
}
pub fn get_symbol_runner<'a, RUNNER: SymbolRunner, REPO: SymbolRepository<'a>>(
&self,
symbol_runner: &'a RUNNER,
repo: &'a REPO,
) -> Box<dyn 'a + SymbolRunner> {
let runner1 = ReportingSymbolRunner::new(symbol_runner, StdErrLogger);
let runner2 = NonRepeatingSymbolRunner::new(runner1);
Box::new(RequirementsResolvingSymbolRunner::new(runner2, repo))
}
}
pub struct DefaultSymbolRepository<'a, A: 'a + UserAdder, C: 'a + CommandRunner> {
user_adder: A,
command_runner: &'a C,
home: Regex,
home_config: Regex,
csr: Regex,
private_key: Regex,
systemd_linger: Regex,
}
impl<'a, C: 'a + CommandRunner> DefaultSymbolRepository<'a, SystemUserAdder<'a, C>, C> {
pub fn new(command_runner: &'a C) -> Self {
Self {
command_runner,
user_adder: SystemUserAdder::new(command_runner),
home: Regex::new("^/home/([^/]+)$").unwrap(),
home_config: Regex::new("^/home/([^/]+)/.config(?:/|$)").unwrap(),
csr: Regex::new("^/etc/ssl/local_certs/([^/]+).csr$").unwrap(),
private_key: Regex::new("^/etc/ssl/private/([^/]+).key$").unwrap(),
systemd_linger: Regex::new("^/var/lib/systemd/linger/([^/]+)$").unwrap(),
}
}
}
impl<'a, C: CommandRunner> SymbolRepository<'a>
for DefaultSymbolRepository<'a, SystemUserAdder<'a, C>, C>
{
fn get_symbol(&'a self, resource: &Resource) -> Option<Box<dyn Symbol + 'a>> {
match resource.get_type() {
"user" => Some(Box::new(User::new(
resource.get_value().to_string().into(),
self.command_runner,
&self.user_adder,
))),
"dir" => {
let value = resource.get_value();
Some(if let Some(matches) = self.home_config.captures(value) {
Box::new(List::new(vec![
Box::new(Dir::new(value.to_string())),
Box::new(Owner::new(
value.to_string(),
matches[1].to_string().into(),
self.command_runner,
)),
])) as Box<dyn Symbol>
} else if let Some(matches) = self.home.captures(value) {
Box::new(User::new(
matches[1].to_string().into(),
self.command_runner,
&self.user_adder,
)) as Box<dyn Symbol>
} else {
Box::new(Dir::new(value.to_string())) as Box<dyn Symbol>
})
}
"file" => {
let value = resource.get_value();
if let Some(matches) = self.csr.captures(value) {
Some(Box::new(TlsCsr::new(
matches[1].to_string().into(),
self.command_runner,
)) as Box<dyn Symbol>)
} else if let Some(matches) = self.private_key.captures(value) {
Some(Box::new(TlsKey::new(
matches[1].to_string().into(),
self.command_runner,
)) as Box<dyn Symbol>)
} else if let Some(matches) = self.systemd_linger.captures(value) {
Some(Box::new(SystemdUserSession::new(
matches[1].to_string().into(),
self.command_runner,
)) as Box<dyn Symbol>)
} else {
None
}
}
_ => None,
}
}
}