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.

221 lines
5.3 KiB

8 years ago
7 years ago
7 years ago
8 years ago
8 years ago
5 years ago
8 years ago
8 years ago
5 years ago
5 years ago
8 years ago
5 years ago
8 years ago
5 years ago
5 years ago
8 years ago
8 years ago
5 years ago
8 years ago
8 years ago
5 years ago
8 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 years ago
8 years ago
5 years ago
5 years ago
5 years ago
5 years ago
7 years ago
5 years ago
8 years ago
5 years ago
5 years ago
8 years ago
7 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 years ago
7 years ago
5 years ago
8 years ago
5 years ago
7 years ago
5 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 years ago
  1. use std::borrow::Cow;
  2. use std::error::Error;
  3. use std::fmt;
  4. use command_runner::CommandRunner;
  5. use resources::Resource;
  6. use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
  7. #[derive(Debug)]
  8. pub enum UserAdderError {
  9. AlreadyExists,
  10. UnknownError,
  11. ImplError(Box<dyn Error>),
  12. }
  13. impl Error for UserAdderError {
  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<&dyn Error> {
  22. match self {
  23. UserAdderError::ImplError(ref e) => Some(e.as_ref()),
  24. _ => None,
  25. }
  26. }
  27. }
  28. impl fmt::Display for UserAdderError {
  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. fn add_user(&self, user_name: &str) -> Result<(), UserAdderError>;
  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<&dyn 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, C: 'a + CommandRunner, A: 'a + UserAdder> {
  64. user_name: Cow<'a, str>,
  65. command_runner: &'a C,
  66. user_adder: &'a A,
  67. }
  68. impl<'a, C: CommandRunner, A: 'a + UserAdder> User<'a, C, A> {
  69. pub fn new(user_name: Cow<'a, str>, command_runner: &'a C, user_adder: &'a A) -> Self {
  70. User {
  71. user_name,
  72. command_runner,
  73. user_adder,
  74. }
  75. }
  76. }
  77. impl<'a, C: CommandRunner, A: 'a + UserAdder> fmt::Display for User<'a, C, A> {
  78. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  79. write!(f, "User {}", self.user_name)
  80. }
  81. }
  82. impl<'a, C: CommandRunner, A: 'a + UserAdder> Symbol for User<'a, C, A> {
  83. fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  84. let output = self
  85. .command_runner
  86. .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<dyn Error>> {
  94. self
  95. .user_adder
  96. .add_user(&*self.user_name)
  97. .map_err(|e| Box::new(e) as Box<dyn Error>)
  98. }
  99. fn provides(&self) -> Option<Vec<Resource>> {
  100. Some(vec![Resource::new("user", self.user_name.to_string())])
  101. }
  102. fn as_action<'b>(&'b self, runner: &'b dyn SymbolRunner) -> Box<dyn Action + 'b> {
  103. Box::new(SymbolAction::new(runner, self))
  104. }
  105. fn into_action<'b>(self: Box<Self>, runner: &'b dyn SymbolRunner) -> Box<dyn Action + 'b>
  106. where
  107. Self: 'b,
  108. {
  109. Box::new(OwnedSymbolAction::new(runner, *self))
  110. }
  111. }
  112. pub struct SystemUserAdder<'a, C: 'a + CommandRunner> {
  113. command_runner: &'a C,
  114. }
  115. impl<'a, C: CommandRunner> SystemUserAdder<'a, C> {
  116. pub fn new(command_runner: &'a C) -> Self {
  117. SystemUserAdder { command_runner }
  118. }
  119. }
  120. impl<'a, C: CommandRunner> UserAdder for SystemUserAdder<'a, C> {
  121. fn add_user(&self, user_name: &str) -> Result<(), UserAdderError> {
  122. let output = self.command_runner.run_with_args(
  123. "adduser",
  124. &[
  125. // "-m", // Necessary for Fedora, not accepted in Debian
  126. "--system", user_name,
  127. ],
  128. );
  129. match output {
  130. Ok(output) => match output.status.code() {
  131. Some(0) => Ok(()),
  132. Some(1) => {
  133. println!("{:?}", output);
  134. Err(UserAdderError::AlreadyExists)
  135. }
  136. Some(_) => {
  137. println!("{:?}", output);
  138. Err(UserAdderError::UnknownError)
  139. }
  140. None => {
  141. println!("{:?}", output);
  142. Err(UserAdderError::UnknownError)
  143. }
  144. },
  145. Err(e) => Err(UserAdderError::ImplError(Box::new(e))),
  146. }
  147. }
  148. }
  149. #[cfg(test)]
  150. mod test {
  151. use std::error::Error;
  152. use std::fmt;
  153. use command_runner::StdCommandRunner;
  154. use symbols::user::User;
  155. use symbols::user::UserAdder;
  156. use symbols::user::UserAdderError;
  157. use symbols::Symbol;
  158. #[derive(Debug, PartialEq)]
  159. struct DummyError;
  160. impl Error for DummyError {
  161. fn description(&self) -> &str {
  162. "DummyError"
  163. }
  164. }
  165. impl fmt::Display for DummyError {
  166. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  167. write!(f, "DummyError")
  168. }
  169. }
  170. struct DummyUserAdder;
  171. impl UserAdder for DummyUserAdder {
  172. fn add_user(&self, _user_name: &str) -> Result<(), UserAdderError> {
  173. Ok(())
  174. }
  175. }
  176. #[test]
  177. fn test_target_reached_nonexisting() {
  178. let symbol = User {
  179. user_name: "nonexisting".into(),
  180. command_runner: &StdCommandRunner,
  181. user_adder: &DummyUserAdder,
  182. };
  183. assert_eq!(symbol.target_reached().unwrap(), false);
  184. }
  185. #[test]
  186. fn test_target_reached_root() {
  187. let symbol = User {
  188. user_name: "root".into(),
  189. command_runner: &StdCommandRunner,
  190. user_adder: &DummyUserAdder,
  191. };
  192. assert_eq!(symbol.target_reached().unwrap(), true);
  193. }
  194. }