use crate::artifacts::{ DatabaseName as DatabaseNameArtifact, Path as PathArtifact, ServiceName as ServiceNameArtifact, UserName as UserNameArtifact, }; 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::to_artifact::ToArtifact; use std::fmt::Display; use std::marker::PhantomData; use std::path::{Path, PathBuf}; pub trait Policy { fn acme_user() -> &'static str { "acme" } fn user_home(user_name: &str) -> PathBuf { format!("/home/{}", user_name).into() } fn user_name_for_domain(domain_name: &'_ str) -> String { domain_name.split('.').rev().fold(String::new(), |result, part| if result.is_empty() { result } else { result + "_" } + part) } fn php_version() -> &'static str { "7.0" } fn path_for_data(name: impl Display) -> PathBuf { ("/root/data".as_ref() as &Path).join(format!("_{}", name)) } } pub struct DefaultPolicy; impl Policy for DefaultPolicy {} pub trait ResourceLocator { type Prerequisites: ToArtifact; fn locate(resource: &R) -> (R::Artifact, Self::Prerequisites) where R: Resource; } pub struct DefaultLocator

{ phantom: PhantomData

, } impl> ResourceLocator> for DefaultLocator

{ type Prerequisites = Dir; fn locate(resource: &Key) -> ( as Resource>::Artifact, Self::Prerequisites) { ( PathArtifact::from(format!("/etc/ssl/private/{}.key", resource.0.as_ref())), Dir("/etc/ssl/private".into()), ) } } impl> ResourceLocator> for DefaultLocator

{ type Prerequisites = Dir; fn locate(resource: &Csr) -> ( as Resource>::Artifact, Self::Prerequisites) { ( PathArtifact::from(format!("/etc/ssl/local_certs/{}.csr", resource.0.as_ref())), Dir("/etc/ssl/local_certs".into()), ) } } impl> ResourceLocator> for DefaultLocator

{ type Prerequisites = Dir; fn locate(resource: &Cert) -> ( as Resource>::Artifact, Self::Prerequisites) { ( PathArtifact::from(format!("/etc/ssl/local_certs/{}.crt", resource.0.as_ref())), Dir("/etc/ssl/local_certs".into()), ) } } impl> ResourceLocator> for DefaultLocator

{ type Prerequisites = Dir; fn locate( resource: &CertChain, ) -> ( as Resource>::Artifact, Self::Prerequisites) { ( PathArtifact::from(format!( "/etc/ssl/local_certs/{}.chained.crt", resource.0.as_ref() )), Dir("/etc/ssl/local_certs".into()), ) } } impl> ResourceLocator> for DefaultLocator

{ type Prerequisites = Dir; fn locate( resource: &KeyAndCertBundle, ) -> ( as Resource>::Artifact, Self::Prerequisites, ) { ( PathArtifact::from(format!( "/etc/ssl/private/{}.with_key.crt", resource.0.as_ref() )), Dir("/etc/ssl/private".into()), ) } } impl<'a, POLICY, P: AsRef> ResourceLocator> for DefaultLocator { type Prerequisites = Dir; fn locate(resource: &File

) -> ( as Resource>::Artifact, Self::Prerequisites) { ((), Dir(resource.0.as_ref().parent().unwrap().into())) } } impl<'a, POLICY, P: AsRef> ResourceLocator> for DefaultLocator { type Prerequisites = Dir; fn locate( resource: &GitCheckout<'a, P>, ) -> ( as Resource>::Artifact, Self::Prerequisites, ) { ((), Dir(resource.0.as_ref().parent().unwrap().into())) } } impl> ResourceLocator> for DefaultLocator { type Prerequisites = Option>; fn locate(resource: &Dir

) -> ( as Resource>::Artifact, Self::Prerequisites) { ((), resource.0.as_ref().parent().map(|p| Dir(p.into()))) } } impl ResourceLocator> for DefaultLocator { type Prerequisites = (); fn locate( _resource: &NpmInstall

, ) -> ( as Resource>::Artifact, Self::Prerequisites) { ((), ()) } } impl> ResourceLocator> for DefaultLocator { type Prerequisites = (); fn locate( resource: &StoredDirectory

, ) -> ( as Resource>::Artifact, Self::Prerequisites, ) { (PathArtifact::from(POLICY::path_for_data(resource.0)), ()) } } impl> ResourceLocator> for DefaultLocator { type Prerequisites = Dir; fn locate( resource: &LoadedDirectory

, ) -> ( as Resource>::Artifact, Self::Prerequisites, ) { ( PathArtifact::from(POLICY::path_for_data(resource.0)), Dir(resource.1.as_ref().parent().unwrap().into()), ) } } impl ResourceLocator for DefaultLocator

{ type Prerequisites = Dir; fn locate( _resource: &AcmeAccountKey, ) -> (::Artifact, Self::Prerequisites) { let acme_user = P::acme_user(); let home = P::user_home(acme_user); (PathArtifact::from(home.join("account.key")), Dir(home)) } } impl ResourceLocator for DefaultLocator

{ type Prerequisites = (); fn locate(_resource: &AcmeUser) -> (::Artifact, Self::Prerequisites) { let acme_user = P::acme_user(); (UserNameArtifact(acme_user.into()), ()) } } impl ResourceLocator for DefaultLocator

{ type Prerequisites = Dir; fn locate( _resource: &AcmeChallengesDir, ) -> ( ::Artifact, Self::Prerequisites, ) { let acme_user = P::acme_user(); let home = P::user_home(acme_user); (PathArtifact::from(home.join("challenges")), Dir(home)) } } impl ResourceLocator for DefaultLocator

{ type Prerequisites = (); fn locate( _resource: &AcmeChallengesNginxSnippet, ) -> ( ::Artifact, Self::Prerequisites, ) { ( PathArtifact::from("/etc/nginx/snippets/acme-challenge.conf"), (), ) } } impl ResourceLocator for DefaultLocator

{ type Prerequisites = Dir; fn locate( _resource: &AcmeRootCert, ) -> (::Artifact, Self::Prerequisites) { let acme_user = P::acme_user(); let home = P::user_home(acme_user); ( PathArtifact::from(home.join("lets_encrypt_x3_cross_signed.pem")), Dir(home), ) } } impl> ResourceLocator> for DefaultLocator

{ type Prerequisites = (); fn locate( resource: &UserForDomain, ) -> ( as Resource>::Artifact, Self::Prerequisites, ) { let user_name = P::user_name_for_domain(resource.0.as_ref()); let home = P::user_home(&user_name); ((UserNameArtifact(user_name), PathArtifact::from(home)), ()) } } impl

ResourceLocator for DefaultLocator

{ type Prerequisites = (); fn locate(_resource: &User) -> (::Artifact, Self::Prerequisites) { ((), ()) } } impl ResourceLocator> for DefaultLocator { type Prerequisites = User; fn locate(resource: &Owner

) -> ( as Resource>::Artifact, Self::Prerequisites) { ((), User(resource.0.clone())) } } impl

ResourceLocator for DefaultLocator

{ type Prerequisites = (); fn locate( _resource: &DefaultServer, ) -> (::Artifact, Self::Prerequisites) { (PathArtifact::from("/etc/nginx/sites-enabled/default"), ()) } } impl, POLICY> ResourceLocator> for DefaultLocator { type Prerequisites = (); fn locate( resource: &ServeCustom, ) -> ( as Resource>::Artifact, Self::Prerequisites) { ( PathArtifact::from(("/etc/nginx/sites-enabled/".as_ref() as &Path).join(&resource.0)), (), ) } } impl, P, POLICY> ResourceLocator> for DefaultLocator { type Prerequisites = (); fn locate( resource: &ServePhp, ) -> ( as Resource>::Artifact, Self::Prerequisites) { ( PathArtifact::from(("/etc/nginx/sites-enabled/".as_ref() as &Path).join(&resource.0)), (), ) } } impl, P, POLICY> ResourceLocator> for DefaultLocator { type Prerequisites = (); fn locate( resource: &ServeService, ) -> ( as Resource>::Artifact, Self::Prerequisites, ) { ( PathArtifact::from(("/etc/nginx/sites-enabled/".as_ref() as &Path).join(&resource.0)), (), ) } } impl, POLICY> ResourceLocator> for DefaultLocator { type Prerequisites = (); fn locate( resource: &ServeRedir, ) -> ( as Resource>::Artifact, Self::Prerequisites) { ( PathArtifact::from(("/etc/nginx/sites-enabled/".as_ref() as &Path).join(&resource.0)), (), ) } } impl, P, POLICY> ResourceLocator> for DefaultLocator { type Prerequisites = (); fn locate( resource: &ServeStatic, ) -> ( as Resource>::Artifact, Self::Prerequisites, ) { ( PathArtifact::from(("/etc/nginx/sites-enabled/".as_ref() as &Path).join(&resource.0)), (), ) } } impl, P: Policy> ResourceLocator> for DefaultLocator

{ type Prerequisites = (); fn locate( resource: &PhpFpmPool, ) -> ( as Resource>::Artifact, Self::Prerequisites) { let ((user, _), ()) = Self::locate(&UserForDomain(&resource.0)); let php_version = P::php_version(); ( ( PathArtifact::from(format!("/run/php/{}.sock", user.0)), PathArtifact::from(format!( "/etc/php/{}/fpm/pool.d/{}.conf", php_version, user.0 )), user, ServiceNameArtifact(format!("php{}-fpm", php_version)), ), (), ) } } impl, P, POLICY: Policy> ResourceLocator> for DefaultLocator { type Prerequisites = (Dir, Owner); fn locate( resource: &SystemdSocketService, ) -> ( as Resource>::Artifact, Self::Prerequisites, ) { let ((user_name, home_path), ()) = Self::locate(&UserForDomain(&resource.0)); let config = home_path.as_ref().join(".config"); let service_dir_path = config.join("systemd/user"); ( ( PathArtifact::from(format!("/var/tmp/{}-{}.socket", user_name.0, resource.1)), PathArtifact::from(service_dir_path.join(format!("{}.service", resource.1))), user_name.clone(), ), (Dir(service_dir_path), Owner(user_name.0, config)), ) } } impl, P: Policy> ResourceLocator> for DefaultLocator

{ type Prerequisites = (); fn locate( resource: &MariaDbDatabase, ) -> ( as Resource>::Artifact, Self::Prerequisites, ) { let ((user_name, _), ()) = Self::locate(&UserForDomain(&resource.0)); ( ( DatabaseNameArtifact(user_name.0.clone()), user_name.clone(), PathArtifact::from(P::path_for_data(format!("{}.sql", user_name.0))), ), (), ) } } impl, P: Policy> ResourceLocator> for DefaultLocator

{ type Prerequisites = (); fn locate( resource: &MariaDbUser, ) -> ( as Resource>::Artifact, Self::Prerequisites) { let ((user_name, _), ()) = Self::locate(&UserForDomain(&resource.0)); ((user_name), ()) } } impl ResourceLocator> for DefaultLocator { type Prerequisites = (); fn locate( _resource: &WordpressPlugin

, ) -> ( as Resource>::Artifact, Self::Prerequisites, ) { ((), ()) } } impl ResourceLocator> for DefaultLocator { type Prerequisites = (); fn locate( _resource: &WordpressTranslation

, ) -> ( as Resource>::Artifact, Self::Prerequisites, ) { ((), ()) } } impl ResourceLocator> for DefaultLocator

{ type Prerequisites = (); fn locate(_resource: &Cron) -> ( as Resource>::Artifact, Self::Prerequisites) { ((), ()) } }