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.

110 lines
3.8 KiB

  1. use regex::Regex;
  2. use std::collections::HashMap;
  3. use command_runner::CommandRunner;
  4. use command_runner::StdCommandRunner;
  5. use loggers::StdErrLogger;
  6. use repository::{DispatchingSymbolRepository, SymbolRepository};
  7. use resources::Resource;
  8. use schema::{NonRepeatingSymbolRunner, ReportingSymbolRunner, RequirementsResolvingSymbolRunner};
  9. use symbols::{Symbol, SymbolRunner};
  10. use symbols::dir::Dir;
  11. use symbols::list::List;
  12. use symbols::owner::Owner;
  13. use symbols::systemd::user_session::SystemdUserSession;
  14. use symbols::tls::TlsCsr;
  15. use symbols::tls::TlsKey;
  16. use symbols::user::{User, UserAdder};
  17. use symbols::user::SystemUserAdder;
  18. pub struct Factory {
  19. }
  20. impl Factory {
  21. pub fn new() -> Self {
  22. Self {}
  23. }
  24. pub fn get_repo<'a, CR: CommandRunner>(&self, command_runner: &'a CR) -> DefaultSymbolRepository<'a, SystemUserAdder<'a, CR>, CR> {
  25. DefaultSymbolRepository::new(command_runner)
  26. }
  27. pub fn get_symbol_runner<'a, RUNNER: SymbolRunner, REPO: SymbolRepository<'a>>(&self, symbol_runner: &'a RUNNER, repo: &'a REPO) -> Box<'a + SymbolRunner> {
  28. let runner1 = ReportingSymbolRunner::new(symbol_runner, StdErrLogger);
  29. let runner2 = NonRepeatingSymbolRunner::new(runner1);
  30. Box::new(RequirementsResolvingSymbolRunner::new(runner2, repo))
  31. }
  32. }
  33. pub struct DefaultSymbolRepository<'a, A: 'a + UserAdder, C: 'a + CommandRunner> {
  34. user_adder: A,
  35. command_runner: &'a C,
  36. home: Regex,
  37. home_config: Regex,
  38. csr: Regex,
  39. private_key: Regex,
  40. systemd_linger: Regex
  41. }
  42. impl<'a, C: 'a + CommandRunner> DefaultSymbolRepository<'a, SystemUserAdder<'a, C>, C> {
  43. pub fn new(command_runner: &'a C) -> Self {
  44. Self {
  45. command_runner: command_runner,
  46. user_adder: SystemUserAdder::new(command_runner),
  47. home: Regex::new("^/home/([^/]+)$").unwrap(),
  48. home_config: Regex::new("^/home/([^/]+)/.config(?:/|$)").unwrap(),
  49. csr: Regex::new("^/etc/ssl/local_certs/([^/]+).csr$").unwrap(),
  50. private_key: Regex::new("^/etc/ssl/private/([^/]+).key$").unwrap(),
  51. systemd_linger: Regex::new("^/var/lib/systemd/linger/([^/]+)$").unwrap()
  52. }
  53. }
  54. }
  55. impl<'a, C: CommandRunner> SymbolRepository<'a> for DefaultSymbolRepository<'a, SystemUserAdder<'a, C>, C> {
  56. fn get_symbol(&'a self, resource: &Resource) -> Option<Box<Symbol + 'a>> {
  57. match resource.get_type() {
  58. "user" => Some(Box::new(User::new(
  59. resource.get_value().to_string().into(),
  60. self.command_runner,
  61. &self.user_adder
  62. ))),
  63. "dir" => {
  64. let value = resource.get_value();
  65. Some(
  66. if let Some(matches) = self.home_config.captures(value) {
  67. Box::new(List::new(vec![
  68. Box::new(Dir::new(value.to_string())),
  69. Box::new(Owner::new(value.to_string(), matches[1].to_string().into(), self.command_runner))
  70. ])) as Box<Symbol>
  71. } else if let Some(matches) = self.home.captures(value) {
  72. Box::new(
  73. User::new(matches[1].to_string().into(), self.command_runner, &self.user_adder)
  74. ) as Box<Symbol>
  75. } else { Box::new(Dir::new(value.to_string())) as Box<Symbol> }
  76. )
  77. },
  78. "file" => {
  79. let value = resource.get_value();
  80. if let Some(matches) = self.csr.captures(value) {
  81. Some(Box::new(TlsCsr::new(
  82. matches[1].to_string().into(),
  83. self.command_runner
  84. )) as Box<Symbol>)
  85. } else if let Some(matches) = self.private_key.captures(value) {
  86. Some(Box::new(TlsKey::new(
  87. matches[1].to_string().into(),
  88. self.command_runner
  89. )) as Box<Symbol>)
  90. } else if let Some(matches) = self.systemd_linger.captures(value) {
  91. Some(Box::new(SystemdUserSession::new(
  92. matches[1].to_string().into(),
  93. self.command_runner
  94. )) as Box<Symbol>)
  95. } else { None }
  96. },
  97. _ => None
  98. }
  99. }
  100. }