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.

397 lines
9.9 KiB

2 years ago
7 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. use crate::artifacts::{
  2. DatabaseName as DatabaseNameArtifact, Path as PathArtifact, ServiceName as ServiceNameArtifact,
  3. UserName as UserNameArtifact,
  4. };
  5. use crate::templates::php::FpmPoolConfig;
  6. use std::hash::Hash;
  7. use std::path::Path;
  8. pub trait Resource {
  9. type Artifact;
  10. }
  11. #[derive(Debug, Hash, PartialEq, Eq)]
  12. pub struct Key<D>(pub D);
  13. impl<D> Resource for Key<D> {
  14. type Artifact = PathArtifact;
  15. }
  16. #[derive(Debug, Hash, PartialEq, Eq)]
  17. pub struct Csr<D>(pub D);
  18. impl<D> Resource for Csr<D> {
  19. type Artifact = PathArtifact;
  20. }
  21. #[derive(Debug, Hash, PartialEq, Eq)]
  22. pub struct Cert<D>(pub D);
  23. impl<D> Resource for Cert<D> {
  24. type Artifact = PathArtifact;
  25. }
  26. #[derive(Debug, Hash, PartialEq, Eq)]
  27. pub struct CertChain<D>(pub D);
  28. impl<D> Resource for CertChain<D> {
  29. type Artifact = PathArtifact;
  30. }
  31. #[derive(Debug, Hash, PartialEq, Eq)]
  32. pub struct KeyAndCertBundle<D>(pub D);
  33. impl<D> Resource for KeyAndCertBundle<D> {
  34. type Artifact = PathArtifact;
  35. }
  36. #[derive(Debug, Hash, PartialEq, Eq)]
  37. pub struct File<P>(pub P, pub Rc<str>);
  38. impl<P> Resource for File<P> {
  39. type Artifact = ();
  40. }
  41. impl File<Rc<Path>> {
  42. pub fn new(p: impl Into<Rc<Path>>, content: impl AsRef<str>) -> Self {
  43. Self(p.into(), content.as_ref().into())
  44. }
  45. }
  46. #[derive(Debug, Hash, PartialEq, Eq)]
  47. pub struct GitCheckout<'a, P>(pub P, pub &'a str, pub &'a str);
  48. impl<'a, P> Resource for GitCheckout<'a, P> {
  49. type Artifact = ();
  50. }
  51. impl<'a> GitCheckout<'a, Rc<Path>> {
  52. pub fn new(target: impl Into<Rc<Path>>, src: &'a str, head: &'a str) -> Self {
  53. Self(target.into(), src, head)
  54. }
  55. }
  56. #[derive(Debug, Hash, PartialEq, Eq)]
  57. pub struct Dir<P>(pub P);
  58. impl<P> Resource for Dir<P> {
  59. type Artifact = ();
  60. }
  61. impl Dir<Rc<Path>> {
  62. pub fn new(p: impl AsRef<Path>) -> Self {
  63. Self(p.as_ref().into())
  64. }
  65. }
  66. #[derive(Debug, Hash, PartialEq, Eq)]
  67. pub struct UserForDomain<D>(pub D);
  68. impl<D> Resource for UserForDomain<D> {
  69. type Artifact = (UserNameArtifact, PathArtifact);
  70. }
  71. #[derive(Debug, Hash, PartialEq, Eq)]
  72. pub struct AcmeAccountKey;
  73. impl Resource for AcmeAccountKey {
  74. type Artifact = PathArtifact;
  75. }
  76. #[derive(Debug, Hash, PartialEq, Eq)]
  77. pub struct AcmeUser;
  78. impl Resource for AcmeUser {
  79. type Artifact = (UserNameArtifact, PathArtifact);
  80. }
  81. #[derive(Debug, Hash, PartialEq, Eq)]
  82. pub struct AcmeRootCert;
  83. impl Resource for AcmeRootCert {
  84. type Artifact = PathArtifact;
  85. }
  86. #[derive(Debug, Hash, PartialEq, Eq)]
  87. pub struct AcmeChallengesDir;
  88. impl Resource for AcmeChallengesDir {
  89. type Artifact = PathArtifact;
  90. }
  91. #[derive(Debug, Hash, PartialEq, Eq)]
  92. pub struct AcmeChallengesNginxSnippet;
  93. impl Resource for AcmeChallengesNginxSnippet {
  94. type Artifact = PathArtifact;
  95. }
  96. #[derive(Debug, Hash, PartialEq, Eq)]
  97. pub struct StoredDirectory<P>(pub &'static str, pub P);
  98. impl<P> Resource for StoredDirectory<P> {
  99. type Artifact = PathArtifact;
  100. }
  101. #[derive(Debug, Hash, PartialEq, Eq)]
  102. pub struct LoadedDirectory<P>(pub &'static str, pub P);
  103. impl<P> Resource for LoadedDirectory<P> {
  104. type Artifact = PathArtifact;
  105. }
  106. pub fn get_saved_directory(
  107. storage_name: &'static str,
  108. target: impl Into<Rc<Path>>,
  109. ) -> (StoredDirectory<Rc<Path>>, LoadedDirectory<Rc<Path>>) {
  110. let target = target.into();
  111. (
  112. StoredDirectory(storage_name, target.clone()),
  113. LoadedDirectory(storage_name, target),
  114. )
  115. }
  116. #[derive(Debug, Hash, PartialEq, Eq)]
  117. pub struct User(pub Rc<str>);
  118. impl Resource for User {
  119. type Artifact = PathArtifact;
  120. }
  121. #[derive(Debug, Hash, PartialEq, Eq)]
  122. pub struct SystemdSocketService<D, P>(pub D, pub &'static str, pub P, pub P, pub bool);
  123. impl<D, P> Resource for SystemdSocketService<D, P> {
  124. type Artifact = (PathArtifact, PathArtifact, UserNameArtifact);
  125. }
  126. #[derive(Debug, Hash, PartialEq, Eq)]
  127. pub struct NpmInstall<P>(pub P);
  128. impl<P> Resource for NpmInstall<P> {
  129. type Artifact = ();
  130. }
  131. impl NpmInstall<Rc<Path>> {
  132. pub fn new(path: impl Into<Rc<Path>>) -> Self {
  133. Self(path.into())
  134. }
  135. }
  136. #[derive(Debug, Hash, PartialEq, Eq)]
  137. pub struct Owner<P>(pub Rc<str>, pub P);
  138. impl<P> Resource for Owner<P> {
  139. type Artifact = ();
  140. }
  141. impl Owner<Rc<Path>> {
  142. pub fn new(user: &UserNameArtifact, p: impl Into<Rc<Path>>) -> Self {
  143. Self(user.0.clone(), p.into())
  144. }
  145. }
  146. #[derive(Debug, Hash, PartialEq, Eq)]
  147. pub struct ServeCustom<D>(pub D, pub Rc<str>);
  148. impl<D> Resource for ServeCustom<D> {
  149. type Artifact = PathArtifact;
  150. }
  151. #[derive(Debug, Hash, PartialEq, Eq)]
  152. pub struct ServePhp<D, P, C>(pub D, pub P, pub &'static str, pub Rc<str>, pub C);
  153. impl<D, P, C> Resource for ServePhp<D, P, C> {
  154. type Artifact = PathArtifact;
  155. }
  156. // Domain, service name, exec, static, dir
  157. #[derive(Debug, Hash, PartialEq, Eq)]
  158. pub struct ServeService<D, P>(pub D, pub &'static str, pub P, pub P, pub P, pub bool);
  159. impl<D, P> Resource for ServeService<D, P> {
  160. type Artifact = PathArtifact;
  161. }
  162. impl<D> ServeService<D, Rc<Path>> {
  163. pub fn new(
  164. domain: D,
  165. service_name: &'static str,
  166. exec: impl Into<Rc<Path>>,
  167. static_path: impl Into<Rc<Path>>,
  168. working_directory: impl Into<Rc<Path>>,
  169. is_nodejs: bool,
  170. ) -> Self {
  171. Self(
  172. domain,
  173. service_name,
  174. exec.into(),
  175. static_path.into(),
  176. working_directory.into(),
  177. is_nodejs,
  178. )
  179. }
  180. }
  181. #[derive(Debug, Hash, PartialEq, Eq)]
  182. pub struct ServeRedir<D>(pub D, pub D);
  183. impl<D> Resource for ServeRedir<D> {
  184. type Artifact = PathArtifact;
  185. }
  186. #[derive(Debug, Hash, PartialEq, Eq)]
  187. pub struct ServeStatic<D, P>(pub D, pub P);
  188. impl<D, P> Resource for ServeStatic<D, P> {
  189. type Artifact = PathArtifact;
  190. }
  191. impl<D> ServeStatic<D, Rc<Path>> {
  192. pub fn new(domain: D, path: impl Into<Rc<Path>>) -> Self {
  193. Self(domain, path.into())
  194. }
  195. }
  196. #[derive(Debug, Hash, PartialEq, Eq)]
  197. pub struct DefaultServer;
  198. impl Resource for DefaultServer {
  199. type Artifact = PathArtifact;
  200. }
  201. #[derive(Debug, Hash, PartialEq, Eq)]
  202. pub struct PhpFpmPool<D>(pub D, pub FpmPoolConfig);
  203. impl<D> Resource for PhpFpmPool<D> {
  204. type Artifact = (
  205. PathArtifact,
  206. PathArtifact,
  207. UserNameArtifact,
  208. ServiceNameArtifact,
  209. );
  210. }
  211. // A single domain could possibly need multiple databases
  212. #[derive(Debug, Hash, PartialEq, Eq)]
  213. pub struct MariaDbDatabase<D>(pub D);
  214. impl<D> Resource for MariaDbDatabase<D> {
  215. type Artifact = (DatabaseNameArtifact, UserNameArtifact, PathArtifact);
  216. }
  217. #[derive(Debug, Hash, PartialEq, Eq)]
  218. pub struct MariaDbUser<D>(pub D);
  219. impl<D> Resource for MariaDbUser<D> {
  220. type Artifact = UserNameArtifact;
  221. }
  222. #[derive(Debug, Hash, PartialEq, Eq)]
  223. pub struct PostgresqlDatabase<D>(pub D);
  224. impl<D> Resource for PostgresqlDatabase<D> {
  225. type Artifact = (DatabaseNameArtifact, PathArtifact);
  226. }
  227. #[derive(Debug, Hash, PartialEq, Eq)]
  228. pub struct WordpressPlugin<P>(pub P, pub &'static str);
  229. impl<P> Resource for WordpressPlugin<P> {
  230. type Artifact = ();
  231. }
  232. impl WordpressPlugin<Rc<Path>> {
  233. pub fn new(path: impl Into<Rc<Path>>, name: &'static str) -> Self {
  234. Self(path.into(), name)
  235. }
  236. }
  237. #[derive(Debug, Hash, PartialEq, Eq)]
  238. pub struct WordpressTranslation<P>(pub P, pub &'static str, pub &'static str);
  239. impl<P> Resource for WordpressTranslation<P> {
  240. type Artifact = ();
  241. }
  242. impl WordpressTranslation<Rc<Path>> {
  243. pub fn new(path: impl Into<Rc<Path>>, version: &'static str, lang: &'static str) -> Self {
  244. Self(path.into(), version, lang)
  245. }
  246. }
  247. #[derive(Debug, Hash, PartialEq, Eq)]
  248. pub struct Cron<D>(pub D, pub Rc<str>);
  249. impl<D> Resource for Cron<D> {
  250. type Artifact = ();
  251. }
  252. use std::rc::{Rc, Weak};
  253. pub trait FromResource<R> {
  254. fn from_resource(from: &Rc<R>) -> (Self, Weak<R>)
  255. where
  256. Self: Sized;
  257. }
  258. pub trait FromArtifact<R: Resource> {
  259. fn from_artifact(from: R::Artifact) -> Self
  260. where
  261. Self: Sized;
  262. fn into_artifact(self) -> R::Artifact
  263. where
  264. Self: Sized;
  265. }
  266. macro_rules! default_resources {
  267. ( $($name:ident: $type:ty,)* ) => {
  268. #[derive(Debug, PartialEq, Eq, Hash)]
  269. pub enum DefaultResources<'a, D> {
  270. $( $name(Rc<$type>) ),*
  271. }
  272. $(impl<'a, D> FromResource<$type> for DefaultResources<'a, D> {
  273. fn from_resource(inner: &Rc<$type>) -> (Self, Weak<$type>) {
  274. (Self::$name(Rc::clone(&inner)), Rc::downgrade(&inner))
  275. }
  276. })*
  277. #[derive(Clone, Debug)]
  278. pub enum DefaultArtifacts<'a, D> {
  279. $( $name(<$type as Resource>::Artifact) ),*
  280. }
  281. $(impl<'a, D> FromArtifact<$type> for DefaultArtifacts<'a, D> {
  282. fn from_artifact(from: <$type as Resource>::Artifact) -> Self {
  283. Self::$name(from)
  284. }
  285. fn into_artifact(self) -> <$type as Resource>::Artifact {
  286. match self {
  287. Self::$name(inner) => inner,
  288. _ => panic!()
  289. }
  290. }
  291. })*
  292. }
  293. }
  294. // Only one enum entry per resource type, otherwise the equality checks fail
  295. default_resources!(
  296. AcmeAccountKey: AcmeAccountKey,
  297. AcmeChallengesDir: AcmeChallengesDir,
  298. AcmeChallengesNginxSnippet: AcmeChallengesNginxSnippet,
  299. AcmeRootCert: AcmeRootCert,
  300. AcmeUser: AcmeUser,
  301. Cert: Cert<D>,
  302. CertChain: CertChain<D>,
  303. Cron: Cron<D>,
  304. Csr: Csr<D>,
  305. DefaultServer: DefaultServer,
  306. Dir: Dir<Rc<Path>>,
  307. File: File<Rc<Path>>,
  308. GitCheckout: GitCheckout<'a, Rc<Path>>,
  309. Key: Key<D>,
  310. KeyAndCertBundle: KeyAndCertBundle<D>,
  311. LoadedDirectory: LoadedDirectory<Rc<Path>>,
  312. MariaDbDatabase: MariaDbDatabase<D>,
  313. MariaDbUser: MariaDbUser<D>,
  314. PostgresqlDatabase: PostgresqlDatabase<D>,
  315. SystemdSocketService: SystemdSocketService<D, Rc<Path>>,
  316. NpmInstall: NpmInstall<Rc<Path>>,
  317. Owner: Owner<Rc<Path>>,
  318. PhpFpmPool: PhpFpmPool<D>,
  319. ServeCustom: ServeCustom<D>,
  320. ServeService: ServeService<D, Rc<Path>>,
  321. ServePhp: ServePhp<D, Rc<Path>, FpmPoolConfig>,
  322. ServeRedir: ServeRedir<D>,
  323. ServeStatic: ServeStatic<D, Rc<Path>>,
  324. StoredDirectory: StoredDirectory<Rc<Path>>,
  325. User: User,
  326. UserForDomain: UserForDomain<D>,
  327. WordpressPlugin: WordpressPlugin<Rc<Path>>,
  328. WordpressTranslation: WordpressTranslation<Rc<Path>>,
  329. );
  330. pub fn serve_php<D, C: Into<FpmPoolConfig>>(
  331. domain: D,
  332. path: impl Into<Rc<Path>>,
  333. root_filename: &'static str,
  334. nginx_config: impl Into<Rc<str>>,
  335. pool_config: C,
  336. ) -> ServePhp<D, Rc<Path>, FpmPoolConfig> {
  337. ServePhp(
  338. domain,
  339. path.into(),
  340. root_filename,
  341. nginx_config.into(),
  342. pool_config.into(),
  343. )
  344. }