use crate::command_runner::{SetuidCommandRunner, StdCommandRunner}; use crate::resources::{ AcmeAccountKey, AcmeChallengesDir, AcmeChallengesNginxSnippet, AcmeRootCert, AcmeUser, Cert, CertChain, Cron, Csr, DefaultServer, Dir, File, GitCheckout, Key, KeyAndCertBundle, LoadedDirectory, MariaDbDatabase, MariaDbUser, NpmInstall, Owner, PhpFpmPool, Resource, ServeCustom, ServePhp, ServeRedir, ServeService, ServeStatic, StoredDirectory, SystemdSocketService, User, UserForDomain, WordpressPlugin, WordpressTranslation, }; use crate::static_files::LETS_ENCRYPT_X3_CROSS_SIGNED; use crate::storage::SimpleStorage; use crate::symbols::acme::Cert as CertSymbol; use crate::symbols::concat::Concat as ConcatSymbol; use crate::symbols::cron::Cron as CronSymbol; use crate::symbols::dir::Dir as DirSymbol; use crate::symbols::file::File as FileSymbol; use crate::symbols::git::Checkout as GitCheckoutSymbol; use crate::symbols::mariadb::{ Database as MariaDbDatabaseSymbol, Dump as MariaDbDumpSymbol, User as MariaDbUserSymbol, }; use crate::symbols::npm::Install as NpmInstallSymbol; use crate::symbols::owner::Owner as OwnerSymbol; use crate::symbols::saved_directory::{SavedDirectory as SavedDirectorySymbol, StorageDirection}; use crate::symbols::systemd::{ ReloadService as ReloadServiceSymbol, UserService as UserServiceSymbol, UserSession as SystemdUserSessionSymbol, }; use crate::symbols::tls::Csr as CsrSymbol; use crate::symbols::tls::Key as KeySymbol; use crate::symbols::user::User as UserSymbol; use crate::symbols::wordpress::{ Plugin as WordpressPluginSymbol, Translation as WordpressTranslationSymbol, }; use crate::templates::nginx; use crate::templates::php::fpm_pool_config as php_fpm_pool_config; use crate::templates::systemd::{ nodejs_service as systemd_nodejs_service, socket_service as systemd_socket_service, }; use crate::to_artifact::ToArtifact; use std::fmt::Display; use std::path::{Path, PathBuf}; pub trait SymbolBuilder { type Prerequisites: ToArtifact; fn prerequisites(resource: &R) -> Self::Prerequisites; type Symbol; fn create( resource: &R, target: &R::Artifact, inputs: ::Artifact, ) -> Self::Symbol where R: Resource; } pub struct DefaultBuilder; impl SymbolBuilder> for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &Key) -> Self::Prerequisites {} type Symbol = KeySymbol; fn create( _resource: &Key, target: & as Resource>::Artifact, (): ::Artifact, ) -> Self::Symbol { KeySymbol::new(StdCommandRunner, target.0.clone()) } } impl SymbolBuilder> for DefaultBuilder { type Prerequisites = Key; fn prerequisites(resource: &Csr) -> Self::Prerequisites { Key(resource.0.clone()) } type Symbol = CsrSymbol; fn create( resource: &Csr, target: & as Resource>::Artifact, key: ::Artifact, ) -> Self::Symbol { CsrSymbol::new( StdCommandRunner, resource.0.clone(), key.0, target.0.clone(), ) } } impl SymbolBuilder> for DefaultBuilder { type Prerequisites = ( Csr, AcmeRootCert, AcmeAccountKey, AcmeChallengesDir, AcmeUser, DefaultServer, ); fn prerequisites(resource: &Cert) -> Self::Prerequisites { ( Csr(resource.0.clone()), AcmeRootCert, AcmeAccountKey, AcmeChallengesDir, AcmeUser, DefaultServer, ) } type Symbol = CertSymbol< SetuidCommandRunner<'static, String, StdCommandRunner>, SetuidCommandRunner<'static, String, StdCommandRunner>, D, PathBuf, >; fn create( resource: &Cert, target: & as Resource>::Artifact, (csr, root_cert, account_key, challenges_dir, user_name, _): ::Artifact, ) -> Self::Symbol { CertSymbol::new( resource.0.clone(), SetuidCommandRunner::new(user_name.0, &StdCommandRunner), root_cert.0, account_key.0, challenges_dir.0, csr.0, target.0.clone(), ) } } impl SymbolBuilder> for DefaultBuilder { type Prerequisites = (Cert, AcmeRootCert); fn prerequisites(resource: &CertChain) -> Self::Prerequisites { (Cert(resource.0.clone()), AcmeRootCert) } type Symbol = ConcatSymbol<[PathBuf; 2], PathBuf, PathBuf>; fn create( _resource: &CertChain, target: & as Resource>::Artifact, (cert, root_cert): ::Artifact, ) -> Self::Symbol { ConcatSymbol::new([cert.0, root_cert.0], target.0.clone()) } } impl SymbolBuilder> for DefaultBuilder { type Prerequisites = (CertChain, Key); fn prerequisites(resource: &KeyAndCertBundle) -> Self::Prerequisites { (CertChain(resource.0.clone()), Key(resource.0.clone())) } type Symbol = ConcatSymbol<[PathBuf; 2], PathBuf, PathBuf>; fn create( _resource: &KeyAndCertBundle, target: & as Resource>::Artifact, (cert_chain, key): ::Artifact, ) -> Self::Symbol { ConcatSymbol::new([key.0, cert_chain.0], target.0.clone()) } } impl + Clone> SymbolBuilder> for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &File

) -> Self::Prerequisites {} type Symbol = FileSymbol; fn create( resource: &File

, _target: & as Resource>::Artifact, (): ::Artifact, ) -> Self::Symbol { FileSymbol::new(resource.0.clone(), resource.1.clone()) } } impl<'a, P: AsRef + Clone> SymbolBuilder> for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &GitCheckout<'a, P>) -> Self::Prerequisites {} type Symbol = GitCheckoutSymbol; fn create( resource: &GitCheckout<'a, P>, _target: & as Resource>::Artifact, (): ::Artifact, ) -> Self::Symbol { GitCheckoutSymbol::new(resource.0.clone(), resource.1, resource.2, StdCommandRunner) } } impl SymbolBuilder for DefaultBuilder { type Prerequisites = AcmeChallengesNginxSnippet; fn prerequisites(_resource: &DefaultServer) -> Self::Prerequisites { AcmeChallengesNginxSnippet } type Symbol = ( FileSymbol, ReloadServiceSymbol, ); fn create( _resource: &DefaultServer, target: &::Artifact, challenges_snippet_path: ::Artifact, ) -> Self::Symbol { ( FileSymbol::new( target.0.clone(), nginx::default_server(challenges_snippet_path), ), ReloadServiceSymbol::new(StdCommandRunner, "nginx"), ) } } impl + Clone + Display> SymbolBuilder> for DefaultBuilder { type Prerequisites = (CertChain, Key, AcmeChallengesNginxSnippet); fn prerequisites(resource: &ServeCustom) -> Self::Prerequisites { ( CertChain(resource.0.clone()), Key(resource.0.clone()), AcmeChallengesNginxSnippet, ) } type Symbol = ( FileSymbol, ReloadServiceSymbol, ); fn create( resource: &ServeCustom, target: & as Resource>::Artifact, (cert, key, challenges_snippet_path): ::Artifact, ) -> Self::Symbol { ( FileSymbol::new( target.0.clone(), nginx::server_config( &resource.0, cert.0, key.0, &resource.1, challenges_snippet_path, ), ), ReloadServiceSymbol::new(StdCommandRunner, "nginx"), ) } } impl> SymbolBuilder> for DefaultBuilder { type Prerequisites = ( PhpFpmPool, CertChain, Key, AcmeChallengesNginxSnippet, ); fn prerequisites(resource: &ServePhp) -> Self::Prerequisites { ( PhpFpmPool(resource.0.clone(), 10), CertChain(resource.0.clone()), Key(resource.0.clone()), AcmeChallengesNginxSnippet, ) } type Symbol = ( FileSymbol, ReloadServiceSymbol, ); fn create( resource: &ServePhp, target: & as Resource>::Artifact, (pool, cert, key, challenges_snippet_path): ::Artifact, ) -> Self::Symbol { ( FileSymbol::new( target.0.clone(), nginx::server_config( &resource.0, cert.0, key.0, nginx::php_snippet(resource.2, &pool.0, &resource.1) + &resource.3, challenges_snippet_path, ), ), ReloadServiceSymbol::new(StdCommandRunner, "nginx"), ) } } impl> SymbolBuilder> for DefaultBuilder { type Prerequisites = ( SystemdSocketService, CertChain, Key, AcmeChallengesNginxSnippet, ); fn prerequisites(resource: &ServeService) -> Self::Prerequisites { ( SystemdSocketService( resource.0.clone(), resource.1, resource.2.clone(), resource.4.clone(), resource.5, ), CertChain(resource.0.clone()), Key(resource.0.clone()), AcmeChallengesNginxSnippet, ) } type Symbol = ( FileSymbol, ReloadServiceSymbol, ); fn create( resource: &ServeService, target: & as Resource>::Artifact, (socket, cert, key, challenges_snippet_path): ::Artifact, ) -> Self::Symbol { ( FileSymbol::new( target.0.clone(), nginx::server_config( &resource.0, cert.0, key.0, nginx::proxy_snippet(&socket.0, &resource.3), challenges_snippet_path, ), ), ReloadServiceSymbol::new(StdCommandRunner, "nginx"), ) } } impl + Clone + Display> SymbolBuilder> for DefaultBuilder { type Prerequisites = (CertChain, Key, AcmeChallengesNginxSnippet); fn prerequisites(resource: &ServeRedir) -> Self::Prerequisites { ( CertChain(resource.0.clone()), Key(resource.0.clone()), AcmeChallengesNginxSnippet, ) } type Symbol = ( FileSymbol, ReloadServiceSymbol, ); fn create( resource: &ServeRedir, target: & as Resource>::Artifact, (cert, key, challenges_snippet_path): ::Artifact, ) -> Self::Symbol { ( FileSymbol::new( target.0.clone(), nginx::server_config( &resource.0, cert.0, key.0, nginx::redir_snippet(resource.1.as_ref()), challenges_snippet_path, ), ), ReloadServiceSymbol::new(StdCommandRunner, "nginx"), ) } } impl + Clone + Display, P: AsRef> SymbolBuilder> for DefaultBuilder { type Prerequisites = (CertChain, Key, AcmeChallengesNginxSnippet); fn prerequisites(resource: &ServeStatic) -> Self::Prerequisites { ( CertChain(resource.0.clone()), Key(resource.0.clone()), AcmeChallengesNginxSnippet, ) } type Symbol = ( FileSymbol, ReloadServiceSymbol, ); fn create( resource: &ServeStatic, target: & as Resource>::Artifact, (cert, key, challenges_snippet_path): ::Artifact, ) -> Self::Symbol { ( FileSymbol::new( target.0.clone(), nginx::server_config( &resource.0, cert.0, key.0, nginx::static_snippet(resource.1.as_ref()), challenges_snippet_path, ), ), ReloadServiceSymbol::new(StdCommandRunner, "nginx"), ) } } impl SymbolBuilder> for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &PhpFpmPool) -> Self::Prerequisites {} type Symbol = ( FileSymbol, ReloadServiceSymbol, ); fn create( resource: &PhpFpmPool, (socket_path, conf_path, user_name, service_name): & as Resource>::Artifact, (): ::Artifact, ) -> Self::Symbol { ( FileSymbol::new( conf_path.0.clone(), php_fpm_pool_config(&user_name.0, &socket_path.0, resource.1), ), ReloadServiceSymbol::new(StdCommandRunner, service_name.0.clone()), ) } } impl> SymbolBuilder> for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &SystemdSocketService) -> Self::Prerequisites {} type Symbol = ( FileSymbol, SystemdUserSessionSymbol<'static, String, StdCommandRunner>, UserServiceSymbol<'static, PathBuf, String, StdCommandRunner>, ); fn create( resource: &SystemdSocketService, (socket_path, conf_path, user_name): & as Resource>::Artifact, (): ::Artifact, ) -> Self::Symbol { ( FileSymbol::new( conf_path.0.clone(), if resource.4 { systemd_nodejs_service(&resource.2, socket_path, &resource.3) } else { systemd_socket_service( socket_path, resource.2.as_ref().to_str().unwrap(), &resource.3, "", ) }, ), SystemdUserSessionSymbol::new(user_name.0.clone(), &StdCommandRunner), UserServiceSymbol::new( socket_path.0.clone(), user_name.0.clone(), resource.1, &StdCommandRunner, ), ) } } impl SymbolBuilder> for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &Dir

) -> Self::Prerequisites {} type Symbol = DirSymbol

; fn create( resource: &Dir

, _target: & as Resource>::Artifact, (): ::Artifact, ) -> Self::Symbol { DirSymbol::new(resource.0.clone()) } } impl> SymbolBuilder> for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &NpmInstall

) -> Self::Prerequisites {} type Symbol = NpmInstallSymbol<'static, P, StdCommandRunner>; fn create( resource: &NpmInstall

, _target: & as Resource>::Artifact, (): ::Artifact, ) -> Self::Symbol { NpmInstallSymbol::new(resource.0.clone(), &StdCommandRunner) } } impl> SymbolBuilder> for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &StoredDirectory

) -> Self::Prerequisites {} type Symbol = SavedDirectorySymbol; fn create( resource: &StoredDirectory

, target: & as Resource>::Artifact, (): ::Artifact, ) -> Self::Symbol { SavedDirectorySymbol::new( resource.1.clone(), SimpleStorage::new(target.0.clone()), StorageDirection::Store, StdCommandRunner, ) } } impl> SymbolBuilder> for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &LoadedDirectory

) -> Self::Prerequisites {} type Symbol = SavedDirectorySymbol; fn create( resource: &LoadedDirectory

, target: & as Resource>::Artifact, (): ::Artifact, ) -> Self::Symbol { SavedDirectorySymbol::new( resource.1.clone(), SimpleStorage::new(target.0.clone()), StorageDirection::Load, StdCommandRunner, ) } } impl SymbolBuilder> for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &UserForDomain) -> Self::Prerequisites {} type Symbol = UserSymbol; fn create( _resource: &UserForDomain, (user_name, _home_path): & as Resource>::Artifact, (): ::Artifact, ) -> Self::Symbol { UserSymbol::new(user_name.0.clone(), StdCommandRunner) } } impl SymbolBuilder for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &User) -> Self::Prerequisites {} type Symbol = UserSymbol; fn create( resource: &User, (): &::Artifact, (): ::Artifact, ) -> Self::Symbol { UserSymbol::new(resource.0.clone(), StdCommandRunner) } } impl + Clone> SymbolBuilder> for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &Owner

) -> Self::Prerequisites {} type Symbol = OwnerSymbol; fn create( resource: &Owner

, (): & as Resource>::Artifact, (): ::Artifact, ) -> Self::Symbol { OwnerSymbol::new(resource.1.clone(), resource.0.clone(), StdCommandRunner) } } impl SymbolBuilder for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &AcmeUser) -> Self::Prerequisites {} type Symbol = UserSymbol; fn create( _resource: &AcmeUser, user_name: &::Artifact, (): ::Artifact, ) -> Self::Symbol { UserSymbol::new(user_name.0.clone(), StdCommandRunner) } } impl SymbolBuilder for DefaultBuilder { type Prerequisites = AcmeUser; fn prerequisites(_resource: &AcmeChallengesDir) -> Self::Prerequisites { AcmeUser } type Symbol = ( DirSymbol, OwnerSymbol, ); fn create( _resource: &AcmeChallengesDir, target: &::Artifact, user_name: ::Artifact, ) -> Self::Symbol { ( DirSymbol::new(target.0.clone()), OwnerSymbol::new(target.0.clone(), user_name.0, StdCommandRunner), ) } } impl SymbolBuilder for DefaultBuilder { type Prerequisites = AcmeChallengesDir; fn prerequisites(_resource: &AcmeChallengesNginxSnippet) -> Self::Prerequisites { AcmeChallengesDir } type Symbol = FileSymbol; fn create( _resource: &AcmeChallengesNginxSnippet, target: &::Artifact, challenges_dir: ::Artifact, ) -> Self::Symbol { FileSymbol::new( target.0.clone(), nginx::acme_challenges_snippet(challenges_dir), ) } } impl SymbolBuilder for DefaultBuilder { type Prerequisites = AcmeUser; fn prerequisites(_resource: &AcmeAccountKey) -> Self::Prerequisites { AcmeUser } type Symbol = ( KeySymbol, OwnerSymbol, ); fn create( _resource: &AcmeAccountKey, target: &::Artifact, user_name: ::Artifact, ) -> Self::Symbol { ( KeySymbol::new(StdCommandRunner, target.0.clone()), OwnerSymbol::new(target.0.clone(), user_name.0, StdCommandRunner), ) } } impl SymbolBuilder for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &AcmeRootCert) -> Self::Prerequisites {} type Symbol = FileSymbol; fn create( _resource: &AcmeRootCert, target: &::Artifact, (): ::Artifact, ) -> Self::Symbol { FileSymbol::new(target.0.clone(), LETS_ENCRYPT_X3_CROSS_SIGNED) } } impl SymbolBuilder> for DefaultBuilder { type Prerequisites = (); fn prerequisites(_resource: &MariaDbUser) -> Self::Prerequisites {} type Symbol = MariaDbUserSymbol<'static, String, StdCommandRunner>; fn create( _resource: &MariaDbUser, user_name: & as Resource>::Artifact, _: ::Artifact, ) -> Self::Symbol { MariaDbUserSymbol::new(user_name.0.clone(), &StdCommandRunner) } } impl SymbolBuilder> for DefaultBuilder { type Prerequisites = MariaDbUser; fn prerequisites(resource: &MariaDbDatabase) -> Self::Prerequisites { MariaDbUser(resource.0.clone()) } type Symbol = ( MariaDbDatabaseSymbol<'static, String, SimpleStorage, StdCommandRunner>, MariaDbDumpSymbol<'static, String, StdCommandRunner, SimpleStorage>, ); fn create( _resource: &MariaDbDatabase, (db_name, _, data_path): & as Resource>::Artifact, _: ::Artifact, ) -> Self::Symbol { let db_dump = SimpleStorage::new(data_path.0.clone()); ( MariaDbDatabaseSymbol::new(db_name.0.clone(), db_dump.clone(), &StdCommandRunner), MariaDbDumpSymbol::new(db_name.0.clone(), db_dump, &StdCommandRunner), ) } } impl> SymbolBuilder> for DefaultBuilder { type Prerequisites = Dir; fn prerequisites(resource: &WordpressPlugin

) -> Self::Prerequisites { Dir(resource.0.as_ref().join("wp-content/plugins")) } type Symbol = WordpressPluginSymbol<'static, P, &'static str, StdCommandRunner>; fn create( resource: &WordpressPlugin

, (): & as Resource>::Artifact, _: ::Artifact, ) -> Self::Symbol { WordpressPluginSymbol::new(resource.0.clone(), resource.1, &StdCommandRunner) } } impl> SymbolBuilder> for DefaultBuilder { type Prerequisites = Dir; fn prerequisites(resource: &WordpressTranslation

) -> Self::Prerequisites { Dir(resource.0.as_ref().join("wp-content/languages")) } type Symbol = WordpressTranslationSymbol<'static, &'static str, PathBuf, StdCommandRunner>; fn create( resource: &WordpressTranslation

, (): & as Resource>::Artifact, _: ::Artifact, ) -> Self::Symbol { WordpressTranslationSymbol::new( resource.0.as_ref().join("wp-content/languages"), resource.1, resource.2, &StdCommandRunner, ) } } impl SymbolBuilder> for DefaultBuilder { type Prerequisites = UserForDomain; fn prerequisites(resource: &Cron) -> Self::Prerequisites { UserForDomain(resource.0.clone()) } type Symbol = CronSymbol<'static, String, String, StdCommandRunner>; fn create( resource: &Cron, (): & as Resource>::Artifact, user_name: ::Artifact, ) -> Self::Symbol { CronSymbol::new((user_name.0).0, resource.1.clone(), &StdCommandRunner) } }