Start with SchematicsFactory and bin
This commit is contained in:
parent
c91eb2f04e
commit
0bc56a8f69
8 changed files with 157 additions and 30 deletions
13
src/bin.rs
Normal file
13
src/bin.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
use std::process::exit;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
pub fn schematics_main(run: &Fn (bool) -> Result<(), ()>) {
|
||||||
|
let args: Vec<String> = 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 });
|
||||||
|
}
|
||||||
110
src/factory.rs
Normal file
110
src/factory.rs
Normal file
|
|
@ -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<Box<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<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<Symbol>
|
||||||
|
} else { Box::new(Dir::new(value.to_string())) as Box<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<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<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<Symbol>)
|
||||||
|
} else { None }
|
||||||
|
},
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,9 @@ missing_debug_implementations
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
extern crate users;
|
extern crate users;
|
||||||
|
|
||||||
|
pub mod bin;
|
||||||
pub mod command_runner;
|
pub mod command_runner;
|
||||||
|
pub mod factory;
|
||||||
pub mod loggers;
|
pub mod loggers;
|
||||||
pub mod symbols;
|
pub mod symbols;
|
||||||
pub mod schema;
|
pub mod schema;
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ use symbols::Symbol;
|
||||||
use resources::Resource;
|
use resources::Resource;
|
||||||
|
|
||||||
pub trait SymbolRepository<'a> {
|
pub trait SymbolRepository<'a> {
|
||||||
fn get_symbol(&self, resource: &Resource) -> Option<Box<Symbol + 'a>>;
|
fn get_symbol(&'a self, resource: &Resource) -> Option<Box<Symbol + 'a>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, C> SymbolRepository<'a> for C where C: Fn(&Resource) -> Option<Box<Symbol + 'a>> {
|
impl<'a, C> SymbolRepository<'a> for C where C: Fn(&Resource) -> Option<Box<Symbol + 'a>> {
|
||||||
fn get_symbol(&self, resource: &Resource) -> Option<Box<Symbol + 'a>> {
|
fn get_symbol(&'a self, resource: &Resource) -> Option<Box<Symbol + 'a>> {
|
||||||
self(resource)
|
self(resource)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -24,7 +24,7 @@ impl<'a> DispatchingSymbolRepository<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SymbolRepository<'a> for DispatchingSymbolRepository<'a> {
|
impl<'a> SymbolRepository<'a> for DispatchingSymbolRepository<'a> {
|
||||||
fn get_symbol(&self, resource: &Resource) -> Option<Box<Symbol + 'a>> {
|
fn get_symbol(&'a self, resource: &Resource) -> Option<Box<Symbol + 'a>> {
|
||||||
self.repositories.get(resource.get_type()).and_then(|repo| repo.get_symbol(resource))
|
self.repositories.get(resource.get_type()).and_then(|repo| repo.get_symbol(resource))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,18 +119,18 @@ impl<'a, R, L> SymbolRunner for ReportingSymbolRunner<'a, R, L> where R: SymbolR
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use resources::Resource;
|
use resources::Resource;
|
||||||
|
|
||||||
pub struct NonRepeatingSymbolRunner<'a, R> where R: 'a + SymbolRunner {
|
pub struct NonRepeatingSymbolRunner<R: SymbolRunner> {
|
||||||
upstream: &'a R,
|
upstream: R,
|
||||||
done: RefCell<HashSet<Resource>>
|
done: RefCell<HashSet<Resource>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R> NonRepeatingSymbolRunner<'a, R> where R: SymbolRunner {
|
impl<R> NonRepeatingSymbolRunner<R> where R: SymbolRunner {
|
||||||
pub fn new(symbol_runner: &'a R) -> Self {
|
pub fn new(symbol_runner: R) -> Self {
|
||||||
NonRepeatingSymbolRunner{ upstream: symbol_runner, done: RefCell::new(HashSet::new()) }
|
NonRepeatingSymbolRunner{ upstream: symbol_runner, done: RefCell::new(HashSet::new()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R> SymbolRunner for NonRepeatingSymbolRunner<'a, R> where R: SymbolRunner {
|
impl<R: SymbolRunner> SymbolRunner for NonRepeatingSymbolRunner<R> {
|
||||||
fn run_symbol(&self, symbol: &Symbol) -> Result<(), Box<Error>>
|
fn run_symbol(&self, symbol: &Symbol) -> Result<(), Box<Error>>
|
||||||
{
|
{
|
||||||
if let Some(resources) = symbol.provides() {
|
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;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
pub struct RequirementsResolvingSymbolRunner<'a, 's, R: 'a + SymbolRunner, G: 'a + SymbolRepository<'s>>(&'a R, &'a G, PhantomData<Box<Symbol + 's>>);
|
pub struct RequirementsResolvingSymbolRunner<'a, 's, R: 'a + SymbolRunner, G: 'a + SymbolRepository<'s>>(R, &'a G, PhantomData<Box<Symbol + 's>>);
|
||||||
|
|
||||||
impl<'a, 's, R, G> RequirementsResolvingSymbolRunner<'a, 's, R, G> where R: SymbolRunner, G: SymbolRepository<'s> {
|
impl<'s, '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 {
|
pub fn new(symbol_runner: R, symbol_repo: &'a G) -> Self {
|
||||||
RequirementsResolvingSymbolRunner(symbol_runner, symbol_repo, PhantomData)
|
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<Error>>
|
fn run_symbol(&self, symbol: &Symbol) -> Result<(), Box<Error>>
|
||||||
{
|
{
|
||||||
for resource in symbol.get_prerequisites() {
|
for resource in symbol.get_prerequisites() {
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
impl<'b, C: 'b + CommandRunner, R: 'b + SymbolRunner> SymbolFactory<'b, C, R> {
|
||||||
|
|
||||||
pub fn new(command_runner: &'b C, symbol_runner: &'b R) -> Self {
|
pub fn new(command_runner: &'b C, symbol_runner: &'b R) -> Self {
|
||||||
let acme_user = "acme"; // FIXME: CONFIG
|
let acme_user = "acme"; // FIXME: CONFIG
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,12 @@ pub trait SymbolRunner {
|
||||||
fn run_symbol(&self, symbol: &Symbol) -> Result<(), Box<Error>>;
|
fn run_symbol(&self, symbol: &Symbol) -> Result<(), Box<Error>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<R: SymbolRunner + ?Sized> SymbolRunner for Box<R> {
|
||||||
|
fn run_symbol(&self, symbol: &Symbol) -> Result<(), Box<Error>> {
|
||||||
|
(**self).run_symbol(symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Symbol
|
// Symbol
|
||||||
pub trait Symbol: Display {
|
pub trait Symbol: Display {
|
||||||
fn target_reached(&self) -> Result<bool, Box<Error>>;
|
fn target_reached(&self) -> Result<bool, Box<Error>>;
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,14 @@ use command_runner::CommandRunner;
|
||||||
use resources::Resource;
|
use resources::Resource;
|
||||||
use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
|
use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug)]
|
||||||
pub enum UserAdderError<E: Error> {
|
pub enum UserAdderError {
|
||||||
AlreadyExists,
|
AlreadyExists,
|
||||||
UnknownError,
|
UnknownError,
|
||||||
ImplError(E)
|
ImplError(Box<Error>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Error> Error for UserAdderError<E> {
|
impl Error for UserAdderError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
&UserAdderError::AlreadyExists => "User already exists",
|
&UserAdderError::AlreadyExists => "User already exists",
|
||||||
|
|
@ -24,13 +24,13 @@ impl<E: Error> Error for UserAdderError<E> {
|
||||||
}
|
}
|
||||||
fn cause(&self) -> Option<&Error> {
|
fn cause(&self) -> Option<&Error> {
|
||||||
match self {
|
match self {
|
||||||
&UserAdderError::ImplError(ref e) => Some(e),
|
&UserAdderError::ImplError(ref e) => Some(e.as_ref()),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Error> fmt::Display for UserAdderError<E> {
|
impl fmt::Display for UserAdderError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self.cause() {
|
match self.cause() {
|
||||||
Some(e) => write!(f, "{} (cause: {})", self.description(), e),
|
Some(e) => write!(f, "{} (cause: {})", self.description(), e),
|
||||||
|
|
@ -40,8 +40,7 @@ impl<E: Error> fmt::Display for UserAdderError<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UserAdder {
|
pub trait UserAdder {
|
||||||
type SubE: Error;
|
fn add_user(&self, user_name: &str) -> Result<(), UserAdderError>;
|
||||||
fn add_user(&self, user_name: &str) -> Result<(), UserAdderError<Self::SubE>>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[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<SubE=E> {
|
pub struct User<'a, C: 'a + CommandRunner, A: 'a + UserAdder> {
|
||||||
user_name: Cow<'a, str>,
|
user_name: Cow<'a, str>,
|
||||||
command_runner: &'a C,
|
command_runner: &'a C,
|
||||||
user_adder: &'a A
|
user_adder: &'a A
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, C: CommandRunner, E: Error + Sized, A: 'a + UserAdder<SubE=E>> 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 {
|
pub fn new(user_name: Cow<'a, str>, command_runner: &'a C, user_adder: &'a A) -> Self {
|
||||||
User {
|
User {
|
||||||
user_name: user_name,
|
user_name: user_name,
|
||||||
|
|
@ -87,13 +86,13 @@ impl<'a, C: CommandRunner, E: Error + Sized, A: 'a + UserAdder<SubE=E>> User<'a,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, C: CommandRunner, E: Error, A: UserAdder<SubE=E>> 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 {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "User {}", self.user_name)
|
write!(f, "User {}", self.user_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, C: CommandRunner, E: 'static + Error, A: UserAdder<SubE=E>> 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<bool, Box<Error>> {
|
fn target_reached(&self) -> Result<bool, Box<Error>> {
|
||||||
let output = try!(self.command_runner.run_with_args("getent", &["passwd", &*self.user_name]));
|
let output = try!(self.command_runner.run_with_args("getent", &["passwd", &*self.user_name]));
|
||||||
match output.status.code() {
|
match output.status.code() {
|
||||||
|
|
@ -131,8 +130,7 @@ impl<'a, C: CommandRunner> SystemUserAdder<'a, C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, C: CommandRunner> UserAdder for 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<IoError>> {
|
|
||||||
let output = self.command_runner.run_with_args(
|
let output = self.command_runner.run_with_args(
|
||||||
"adduser",
|
"adduser",
|
||||||
&[
|
&[
|
||||||
|
|
@ -157,7 +155,7 @@ Err(UserAdderError::UnknownError)
|
||||||
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;
|
struct DummyUserAdder;
|
||||||
|
|
||||||
impl UserAdder for 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<Self::SubE>> {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue