From 0bc56a8f69eac95e8f17cb50fba4683fe26e21e5 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Fri, 22 Sep 2017 15:13:12 +0200 Subject: [PATCH] Start with SchematicsFactory and bin --- src/bin.rs | 13 +++++ src/factory.rs | 110 +++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 + src/repository.rs | 6 +-- src/schema.rs | 18 +++---- src/symbols/factory.rs | 1 - src/symbols/mod.rs | 6 +++ src/symbols/user.rs | 31 ++++++------ 8 files changed, 157 insertions(+), 30 deletions(-) create mode 100644 src/bin.rs create mode 100644 src/factory.rs diff --git a/src/bin.rs b/src/bin.rs new file mode 100644 index 0000000..6ab956b --- /dev/null +++ b/src/bin.rs @@ -0,0 +1,13 @@ +use std::process::exit; +use std::env; + +pub fn schematics_main(run: &Fn (bool) -> Result<(), ()>) { + let args: Vec = env::args().collect(); + let dry_run = match args.len() { + 1 => false, + 2 => if args[1] == "--dry-run" { true } else { panic!() }, + _ => panic!() + }; + + exit(match run(dry_run) { Ok(_) => 0, Err(_) => 1 }); +} diff --git a/src/factory.rs b/src/factory.rs new file mode 100644 index 0000000..d61391c --- /dev/null +++ b/src/factory.rs @@ -0,0 +1,110 @@ +use regex::Regex; + +use std::collections::HashMap; + +use command_runner::CommandRunner; +use command_runner::StdCommandRunner; +use loggers::StdErrLogger; +use repository::{DispatchingSymbolRepository, SymbolRepository}; +use resources::Resource; +use schema::{NonRepeatingSymbolRunner, ReportingSymbolRunner, RequirementsResolvingSymbolRunner}; +use symbols::{Symbol, SymbolRunner}; +use symbols::dir::Dir; +use symbols::list::List; +use symbols::owner::Owner; +use symbols::systemd::user_session::SystemdUserSession; +use symbols::tls::TlsCsr; +use symbols::tls::TlsKey; +use symbols::user::{User, UserAdder}; +use symbols::user::SystemUserAdder; + +pub struct Factory { +} + +impl Factory { + pub fn new() -> Self { + Self {} + } + + 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<'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: 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> { + 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 + } 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 + } else { Box::new(Dir::new(value.to_string())) as Box } + ) + }, + "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) + } 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) + } 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) + } else { None } + }, + _ => None + } + } +} diff --git a/src/lib.rs b/src/lib.rs index cd29069..200423a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,9 @@ missing_debug_implementations extern crate regex; extern crate users; +pub mod bin; pub mod command_runner; +pub mod factory; pub mod loggers; pub mod symbols; pub mod schema; diff --git a/src/repository.rs b/src/repository.rs index 6dfd8b6..571e622 100644 --- a/src/repository.rs +++ b/src/repository.rs @@ -4,11 +4,11 @@ use symbols::Symbol; use resources::Resource; pub trait SymbolRepository<'a> { - fn get_symbol(&self, resource: &Resource) -> Option>; + fn get_symbol(&'a self, resource: &Resource) -> Option>; } impl<'a, C> SymbolRepository<'a> for C where C: Fn(&Resource) -> Option> { - fn get_symbol(&self, resource: &Resource) -> Option> { + fn get_symbol(&'a self, resource: &Resource) -> Option> { self(resource) } } @@ -24,7 +24,7 @@ impl<'a> DispatchingSymbolRepository<'a> { } impl<'a> SymbolRepository<'a> for DispatchingSymbolRepository<'a> { - fn get_symbol(&self, resource: &Resource) -> Option> { + fn get_symbol(&'a self, resource: &Resource) -> Option> { self.repositories.get(resource.get_type()).and_then(|repo| repo.get_symbol(resource)) } } diff --git a/src/schema.rs b/src/schema.rs index 5d0fd87..248e14e 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -119,18 +119,18 @@ impl<'a, R, L> SymbolRunner for ReportingSymbolRunner<'a, R, L> where R: SymbolR use std::collections::HashSet; use resources::Resource; -pub struct NonRepeatingSymbolRunner<'a, R> where R: 'a + SymbolRunner { - upstream: &'a R, +pub struct NonRepeatingSymbolRunner { + upstream: R, done: RefCell> } -impl<'a, R> NonRepeatingSymbolRunner<'a, R> where R: SymbolRunner { - pub fn new(symbol_runner: &'a R) -> Self { +impl NonRepeatingSymbolRunner where R: SymbolRunner { + pub fn new(symbol_runner: R) -> Self { NonRepeatingSymbolRunner{ upstream: symbol_runner, done: RefCell::new(HashSet::new()) } } } -impl<'a, R> SymbolRunner for NonRepeatingSymbolRunner<'a, R> where R: SymbolRunner { +impl SymbolRunner for NonRepeatingSymbolRunner { fn run_symbol(&self, symbol: &Symbol) -> Result<(), Box> { if let Some(resources) = symbol.provides() { @@ -151,15 +151,15 @@ impl<'a, R> SymbolRunner for NonRepeatingSymbolRunner<'a, R> where R: SymbolRunn } use std::marker::PhantomData; -pub struct RequirementsResolvingSymbolRunner<'a, 's, R: 'a + SymbolRunner, G: 'a + SymbolRepository<'s>>(&'a R, &'a G, PhantomData>); +pub struct RequirementsResolvingSymbolRunner<'a, 's, R: 'a + SymbolRunner, G: 'a + SymbolRepository<'s>>(R, &'a G, PhantomData>); -impl<'a, 's, R, G> RequirementsResolvingSymbolRunner<'a, 's, R, G> where R: SymbolRunner, G: SymbolRepository<'s> { - pub fn new(symbol_runner: &'a R, symbol_repo: &'a G) -> Self { +impl<'s, 'a: 's, R, G> RequirementsResolvingSymbolRunner<'a, 's, R, G> where R: SymbolRunner, G: SymbolRepository<'s> { + pub fn new(symbol_runner: R, symbol_repo: &'a G) -> Self { RequirementsResolvingSymbolRunner(symbol_runner, symbol_repo, PhantomData) } } -impl<'a, 's, R, G> SymbolRunner for RequirementsResolvingSymbolRunner<'a, 's, R, G> where R: SymbolRunner, G: SymbolRepository<'s> { +impl<'s, 'a: 's, R, G> SymbolRunner for RequirementsResolvingSymbolRunner<'a, 's, R, G> where R: SymbolRunner, G: SymbolRepository<'s> { fn run_symbol(&self, symbol: &Symbol) -> Result<(), Box> { for resource in symbol.get_prerequisites() { diff --git a/src/symbols/factory.rs b/src/symbols/factory.rs index 2019b33..86d38fd 100644 --- a/src/symbols/factory.rs +++ b/src/symbols/factory.rs @@ -13,7 +13,6 @@ pub struct SymbolFactory<'a, C: 'a + CommandRunner, R: 'a + SymbolRunner>{ } impl<'b, C: 'b + CommandRunner, R: 'b + SymbolRunner> SymbolFactory<'b, C, R> { - pub fn new(command_runner: &'b C, symbol_runner: &'b R) -> Self { let acme_user = "acme"; // FIXME: CONFIG diff --git a/src/symbols/mod.rs b/src/symbols/mod.rs index c0f391c..449015e 100644 --- a/src/symbols/mod.rs +++ b/src/symbols/mod.rs @@ -10,6 +10,12 @@ pub trait SymbolRunner { fn run_symbol(&self, symbol: &Symbol) -> Result<(), Box>; } +impl SymbolRunner for Box { + fn run_symbol(&self, symbol: &Symbol) -> Result<(), Box> { + (**self).run_symbol(symbol) + } +} + // Symbol pub trait Symbol: Display { fn target_reached(&self) -> Result>; diff --git a/src/symbols/user.rs b/src/symbols/user.rs index cf5750c..15fc7c0 100644 --- a/src/symbols/user.rs +++ b/src/symbols/user.rs @@ -7,14 +7,14 @@ use command_runner::CommandRunner; use resources::Resource; use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner}; -#[derive(Debug, PartialEq)] -pub enum UserAdderError { +#[derive(Debug)] +pub enum UserAdderError { AlreadyExists, UnknownError, - ImplError(E) + ImplError(Box) } -impl Error for UserAdderError { +impl Error for UserAdderError { fn description(&self) -> &str { match self { &UserAdderError::AlreadyExists => "User already exists", @@ -24,13 +24,13 @@ impl Error for UserAdderError { } fn cause(&self) -> Option<&Error> { match self { - &UserAdderError::ImplError(ref e) => Some(e), + &UserAdderError::ImplError(ref e) => Some(e.as_ref()), _ => None } } } -impl fmt::Display for UserAdderError { +impl fmt::Display for UserAdderError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.cause() { Some(e) => write!(f, "{} (cause: {})", self.description(), e), @@ -40,8 +40,7 @@ impl fmt::Display for UserAdderError { } pub trait UserAdder { - type SubE: Error; - fn add_user(&self, user_name: &str) -> Result<(), UserAdderError>; + fn add_user(&self, user_name: &str) -> Result<(), UserAdderError>; } #[derive(Debug, PartialEq)] @@ -71,13 +70,13 @@ impl fmt::Display for UserError { } } -pub struct User<'a, C: 'a + CommandRunner, E, A> where E: Error + Sized, A: 'a + UserAdder { +pub struct User<'a, C: 'a + CommandRunner, A: 'a + UserAdder> { user_name: Cow<'a, str>, command_runner: &'a C, user_adder: &'a A } -impl<'a, C: CommandRunner, E: Error + Sized, A: 'a + UserAdder> User<'a, C, E, A> { +impl<'a, C: CommandRunner, A: 'a + UserAdder> User<'a, C, A> { pub fn new(user_name: Cow<'a, str>, command_runner: &'a C, user_adder: &'a A) -> Self { User { user_name: user_name, @@ -87,13 +86,13 @@ impl<'a, C: CommandRunner, E: Error + Sized, A: 'a + UserAdder> User<'a, } } -impl<'a, C: CommandRunner, E: Error, A: UserAdder> fmt::Display for User<'a, C, E, A> { +impl<'a, C: CommandRunner, A: 'a + UserAdder> fmt::Display for User<'a, C, A> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "User {}", self.user_name) } } -impl<'a, C: CommandRunner, E: 'static + Error, A: UserAdder> Symbol for User<'a, C, E, A> { +impl<'a, C: CommandRunner, A: 'a + UserAdder> Symbol for User<'a, C, A> { fn target_reached(&self) -> Result> { let output = try!(self.command_runner.run_with_args("getent", &["passwd", &*self.user_name])); match output.status.code() { @@ -131,8 +130,7 @@ impl<'a, C: CommandRunner> SystemUserAdder<'a, C> { } impl<'a, C: CommandRunner> UserAdder for SystemUserAdder<'a, C> { - type SubE = IoError; - fn add_user(&self, user_name: &str) -> Result<(), UserAdderError> { + fn add_user(&self, user_name: &str) -> Result<(), UserAdderError> { let output = self.command_runner.run_with_args( "adduser", &[ @@ -157,7 +155,7 @@ Err(UserAdderError::UnknownError) Err(UserAdderError::UnknownError) }, }, - Err(e) => Err(UserAdderError::ImplError(e)) + Err(e) => Err(UserAdderError::ImplError(Box::new(e))) } } } @@ -190,8 +188,7 @@ mod test { struct DummyUserAdder; impl UserAdder for DummyUserAdder { - type SubE = DummyError; - fn add_user(&self, user_name: &str) -> Result<(), UserAdderError> { + fn add_user(&self, user_name: &str) -> Result<(), UserAdderError> { Ok(()) } }