use std::borrow::Cow; use std::error::Error; use std::fmt; use command_runner::CommandRunner; use resources::Resource; use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner}; #[derive(Debug)] pub enum UserAdderError { AlreadyExists, UnknownError, ImplError(Box) } impl Error for UserAdderError { fn description(&self) -> &str { match self { UserAdderError::AlreadyExists => "User already exists", UserAdderError::UnknownError => "Unknown error", UserAdderError::ImplError(_) => "User adding error" } } fn cause(&self) -> Option<&Error> { match self { UserAdderError::ImplError(ref e) => Some(e.as_ref()), _ => None } } } 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), None => write!(f, "{}", self.description()) } } } pub trait UserAdder { fn add_user(&self, user_name: &str) -> Result<(), UserAdderError>; } #[derive(Debug, PartialEq)] pub enum UserError { GenericError } impl Error for UserError { fn description(&self) -> &str { match self { UserError::GenericError => "Could not find out if user exists" } } fn cause(&self) -> Option<&Error> { match self { _ => None } } } impl fmt::Display for UserError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.cause() { Some(e) => write!(f, "{} (cause: {})", self.description(), e), None => write!(f, "{}", self.description()) } } } 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, 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, command_runner, user_adder } } } 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, 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() { Some(2) => Ok(false), Some(0) => Ok(true), _ => Err(Box::new(UserError::GenericError)) } } fn execute(&self) -> Result<(), Box> { self.user_adder.add_user(&*self.user_name).map_err(|e| Box::new(e) as Box) } fn provides(&self) -> Option> { Some(vec![Resource::new("user", self.user_name.to_string())]) } fn as_action<'b>(&'b self, runner: &'b SymbolRunner) -> Box { Box::new(SymbolAction::new(runner, self)) } fn into_action<'b>(self: Box, runner: &'b SymbolRunner) -> Box where Self: 'b { Box::new(OwnedSymbolAction::new(runner, *self)) } } pub struct SystemUserAdder<'a, C: 'a + CommandRunner> { command_runner: &'a C } impl<'a, C: CommandRunner> SystemUserAdder<'a, C> { pub fn new(command_runner: &'a C) -> Self { SystemUserAdder { command_runner } } } impl<'a, C: CommandRunner> UserAdder for SystemUserAdder<'a, C> { fn add_user(&self, user_name: &str) -> Result<(), UserAdderError> { let output = self.command_runner.run_with_args( "adduser", &[ // "-m", // Necessary for Fedora, not accepted in Debian "--system", user_name ]); match output { Ok(output) => match output.status.code() { Some(0) => Ok(()), Some(1) => { println!("{:?}", output); Err(UserAdderError::AlreadyExists)}, Some(_) => { println!("{:?}", output); Err(UserAdderError::UnknownError) }, None => { println!("{:?}", output); Err(UserAdderError::UnknownError) }, }, Err(e) => Err(UserAdderError::ImplError(Box::new(e))) } } } #[cfg(test)] mod test { use std::error::Error; use std::fmt; use command_runner::StdCommandRunner; use symbols::Symbol; use symbols::user::User; use symbols::user::UserAdder; use symbols::user::UserAdderError; #[derive(Debug, PartialEq)] struct DummyError; impl Error for DummyError { fn description(&self) -> &str { "DummyError" } } impl fmt::Display for DummyError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "DummyError") } } struct DummyUserAdder; impl UserAdder for DummyUserAdder { fn add_user(&self, user_name: &str) -> Result<(), UserAdderError> { Ok(()) } } #[test] fn test_target_reached_nonexisting() { let symbol = User { user_name: "nonexisting".into(), command_runner: &StdCommandRunner, user_adder: &DummyUserAdder }; assert_eq!(symbol.target_reached().unwrap(), false); } #[test] fn test_target_reached_root() { let symbol = User { user_name: "root".into(), command_runner: &StdCommandRunner, user_adder: &DummyUserAdder }; assert_eq!(symbol.target_reached().unwrap(), true); } }