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.

84 lines
2.0 KiB

8 years ago
8 years ago
4 years ago
5 years ago
8 years ago
5 years ago
5 years ago
7 years ago
8 years ago
4 years ago
4 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 const 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. let res = 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. drop(wait);
  51. res
  52. }
  53. }
  54. #[cfg(test)]
  55. mod test {
  56. use crate::async_utils::run;
  57. use crate::command_runner::StdCommandRunner;
  58. use crate::symbols::user::User;
  59. use crate::symbols::Symbol;
  60. #[test]
  61. fn test_target_reached_nonexisting() {
  62. let symbol = User {
  63. user_name: "nonexisting",
  64. command_runner: StdCommandRunner,
  65. };
  66. assert_eq!(run(symbol.target_reached()).unwrap(), false);
  67. }
  68. #[test]
  69. fn test_target_reached_root() {
  70. let symbol = User {
  71. user_name: "root",
  72. command_runner: StdCommandRunner,
  73. };
  74. assert_eq!(run(symbol.target_reached()).unwrap(), true);
  75. }
  76. }