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.

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