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.

82 lines
1.9 KiB

8 years ago
8 years ago
5 years ago
8 years ago
5 years ago
5 years ago
7 years ago
8 years ago
8 years ago
8 years ago
5 years ago
5 years ago
8 years ago
5 years ago
5 years ago
8 years ago
  1. use crate::command_runner::CommandRunner;
  2. use crate::symbols::Symbol;
  3. use async_trait::async_trait;
  4. use once_cell::sync::Lazy;
  5. use std::error::Error;
  6. use tokio::sync::Semaphore;
  7. pub type Wait = Lazy<Semaphore>;
  8. static WAIT: Wait = Lazy::new(|| Semaphore::new(1));
  9. #[derive(Debug)]
  10. pub struct User<U, C> {
  11. user_name: U,
  12. command_runner: C,
  13. }
  14. impl<U, C> User<U, C> {
  15. pub fn new(user_name: U, command_runner: C) -> Self {
  16. Self {
  17. user_name,
  18. command_runner,
  19. }
  20. }
  21. }
  22. #[async_trait(?Send)]
  23. impl<U: AsRef<str>, C: CommandRunner> Symbol for User<U, C> {
  24. async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  25. let output = self
  26. .command_runner
  27. .run_with_args("getent", args!["passwd", self.user_name.as_ref()])
  28. .await?;
  29. match output.status.code() {
  30. Some(2) => Ok(false),
  31. Some(0) => Ok(true),
  32. _ => Err("Unknown error".into()),
  33. }
  34. }
  35. async fn execute(&self) -> Result<(), Box<dyn Error>> {
  36. // adduser is not reentrant because finding the next uid
  37. // and creating the account is not an atomic operation
  38. let wait = WAIT.acquire().await;
  39. self
  40. .command_runner
  41. .run_successfully(
  42. "adduser",
  43. args![
  44. // "-m", // Necessary for Fedora, not accepted in Debian
  45. "--system",
  46. self.user_name.as_ref(),
  47. ],
  48. )
  49. .await
  50. }
  51. }
  52. #[cfg(test)]
  53. mod test {
  54. use crate::async_utils::run;
  55. use crate::command_runner::StdCommandRunner;
  56. use crate::symbols::user::User;
  57. use crate::symbols::Symbol;
  58. #[test]
  59. fn test_target_reached_nonexisting() {
  60. let symbol = User {
  61. user_name: "nonexisting",
  62. command_runner: StdCommandRunner,
  63. };
  64. assert_eq!(run(symbol.target_reached()).unwrap(), false);
  65. }
  66. #[test]
  67. fn test_target_reached_root() {
  68. let symbol = User {
  69. user_name: "root",
  70. command_runner: StdCommandRunner,
  71. };
  72. assert_eq!(run(symbol.target_reached()).unwrap(), true);
  73. }
  74. }