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.

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