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.

199 lines
4.9 KiB

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