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.

210 lines
5.5 KiB

8 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
8 years ago
7 years ago
8 years ago
7 years ago
8 years ago
7 years ago
8 years ago
7 years ago
8 years ago
  1. use std::borrow::Cow;
  2. use std::error::Error;
  3. use std::fmt;
  4. use std::io::Error as IoError;
  5. use command_runner::CommandRunner;
  6. use resources::Resource;
  7. use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
  8. #[derive(Debug, PartialEq)]
  9. pub enum UserAdderError<E: Error> {
  10. AlreadyExists,
  11. UnknownError,
  12. ImplError(E)
  13. }
  14. impl<E: Error> Error for UserAdderError<E> {
  15. fn description(&self) -> &str {
  16. match self {
  17. &UserAdderError::AlreadyExists => "User already exists",
  18. &UserAdderError::UnknownError => "Unknown error",
  19. &UserAdderError::ImplError(_) => "User adding error"
  20. }
  21. }
  22. fn cause(&self) -> Option<&Error> {
  23. match self {
  24. &UserAdderError::ImplError(ref e) => Some(e),
  25. _ => None
  26. }
  27. }
  28. }
  29. impl<E: Error> fmt::Display for UserAdderError<E> {
  30. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  31. match self.cause() {
  32. Some(e) => write!(f, "{} (cause: {})", self.description(), e),
  33. None => write!(f, "{}", self.description())
  34. }
  35. }
  36. }
  37. pub trait UserAdder {
  38. type SubE: Error;
  39. fn add_user(&self, user_name: &str) -> Result<(), UserAdderError<Self::SubE>>;
  40. }
  41. #[derive(Debug, PartialEq)]
  42. pub enum UserError {
  43. GenericError
  44. }
  45. impl Error for UserError {
  46. fn description(&self) -> &str {
  47. match self {
  48. &UserError::GenericError => "Could not find out if user exists"
  49. }
  50. }
  51. fn cause(&self) -> Option<&Error> {
  52. match self {
  53. _ => None
  54. }
  55. }
  56. }
  57. impl fmt::Display for UserError {
  58. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  59. match self.cause() {
  60. Some(e) => write!(f, "{} (cause: {})", self.description(), e),
  61. None => write!(f, "{}", self.description())
  62. }
  63. }
  64. }
  65. pub struct User<'a, C: 'a + CommandRunner, E, A> where E: Error + Sized, A: 'a + UserAdder<SubE=E> {
  66. user_name: Cow<'a, str>,
  67. command_runner: &'a C,
  68. user_adder: &'a A
  69. }
  70. impl<'a, C: CommandRunner, E: Error + Sized, A: 'a + UserAdder<SubE=E>> User<'a, C, E, A> {
  71. pub fn new(user_name: Cow<'a, str>, command_runner: &'a C, user_adder: &'a A) -> Self {
  72. User {
  73. user_name: user_name,
  74. command_runner: command_runner,
  75. user_adder: user_adder
  76. }
  77. }
  78. }
  79. impl<'a, C: CommandRunner, E: Error, A: UserAdder<SubE=E>> fmt::Display for User<'a, C, E, A> {
  80. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  81. write!(f, "User {}", self.user_name)
  82. }
  83. }
  84. impl<'a, C: CommandRunner, E: 'static + Error, A: UserAdder<SubE=E>> Symbol for User<'a, C, E, A> {
  85. fn target_reached(&self) -> Result<bool, Box<Error>> {
  86. let output = try!(self.command_runner.run_with_args("getent", &["passwd", &*self.user_name]));
  87. match output.status.code() {
  88. Some(2) => Ok(false),
  89. Some(0) => Ok(true),
  90. _ => Err(Box::new(UserError::GenericError))
  91. }
  92. }
  93. fn execute(&self) -> Result<(), Box<Error>> {
  94. self.user_adder.add_user(&*self.user_name).map_err(|e| Box::new(e) as Box<Error>)
  95. }
  96. fn provides(&self) -> Option<Vec<Resource>> {
  97. Some(vec![Resource::new("user", self.user_name.to_string())])
  98. }
  99. fn as_action<'b>(&'b self, runner: &'b SymbolRunner) -> Box<Action + 'b> {
  100. Box::new(SymbolAction::new(runner, self))
  101. }
  102. fn into_action<'b>(self: Box<Self>, runner: &'b SymbolRunner) -> Box<Action + 'b> where Self: 'b {
  103. Box::new(OwnedSymbolAction::new(runner, *self))
  104. }
  105. }
  106. pub struct SystemUserAdder<'a, C: 'a + CommandRunner> {
  107. command_runner: &'a C
  108. }
  109. impl<'a, C: CommandRunner> SystemUserAdder<'a, C> {
  110. pub fn new(command_runner: &'a C) -> Self {
  111. SystemUserAdder { command_runner: command_runner }
  112. }
  113. }
  114. impl<'a, C: CommandRunner> UserAdder for SystemUserAdder<'a, C> {
  115. type SubE = IoError;
  116. fn add_user(&self, user_name: &str) -> Result<(), UserAdderError<IoError>> {
  117. let output = self.command_runner.run_with_args(
  118. "adduser",
  119. &[
  120. // "-m", // Necessary for Fedora, not accepted in Debian
  121. "--system",
  122. user_name
  123. ]);
  124. match output {
  125. Ok(output) => match output.status.code() {
  126. Some(0) => Ok(()),
  127. Some(1) =>
  128. {
  129. println!("{:?}", output);
  130. Err(UserAdderError::AlreadyExists)},
  131. Some(_) =>
  132. {
  133. println!("{:?}", output);
  134. Err(UserAdderError::UnknownError)
  135. },
  136. None => {
  137. println!("{:?}", output);
  138. Err(UserAdderError::UnknownError)
  139. },
  140. },
  141. Err(e) => Err(UserAdderError::ImplError(e))
  142. }
  143. }
  144. }
  145. #[cfg(test)]
  146. mod test {
  147. use std::error::Error;
  148. use std::fmt;
  149. use command_runner::StdCommandRunner;
  150. use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
  151. use symbols::user::User;
  152. use symbols::user::UserAdder;
  153. use symbols::user::UserAdderError;
  154. #[derive(Debug, PartialEq)]
  155. struct DummyError;
  156. impl Error for DummyError {
  157. fn description(&self) -> &str {
  158. "DummyError"
  159. }
  160. }
  161. impl fmt::Display for DummyError {
  162. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  163. write!(f, "DummyError")
  164. }
  165. }
  166. struct DummyUserAdder;
  167. impl UserAdder for DummyUserAdder {
  168. type SubE = DummyError;
  169. fn add_user(&self, user_name: &str) -> Result<(), UserAdderError<Self::SubE>> {
  170. Ok(())
  171. }
  172. }
  173. #[test]
  174. fn test_target_reached_nonexisting() {
  175. let symbol = User { user_name: "nonexisting".into(), command_runner: &StdCommandRunner, user_adder: &DummyUserAdder };
  176. assert_eq!(symbol.target_reached().unwrap(), false);
  177. }
  178. #[test]
  179. fn test_target_reached_root() {
  180. let symbol = User { user_name: "root".into(), command_runner: &StdCommandRunner, user_adder: &DummyUserAdder };
  181. assert_eq!(symbol.target_reached().unwrap(), true);
  182. }
  183. }