@ -1,20 +1,22 @@
use std ::borrow ::Cow ;
use std ::ops ::Deref ;
use std ::path ::Path ;
use std ::path ::PathBuf ;
use command_runner ::{ CommandRunner , SetuidCommandRunner } ;
use storage ::{ SimpleStorage , Storage } ;
use symbols ::acme ::{ AcmeCert , AcmeCertChain } ;
use symbols ::acme ::{ newAcmeUser , AcmeCert , AcmeCertChain } ;
use symbols ::cron ::Cron ;
use symbols ::file ::File ;
use symbols ::git ::checkout ::GitCheckout ;
use symbols ::hook ::Hook ;
use symbols ::list ::List ;
use symbols ::mariadb ::{ DatabaseDump , MariaDBDatabase , MariaDBUser } ;
use symbols ::nginx ::server ::{ php_server_config_snippet , server_config , NginxServer } ;
use symbols ::nginx ::server ::{ server_config , NginxServer } ;
use symbols ::owner ::Owner ;
use symbols ::stored_directory ::{ StorageDirection , StoredDirectory } ;
use symbols ::systemd ::reload ::ReloadService ;
use symbols ::systemd ::user_service ::UserService ;
use symbols ::tls ::SelfSignedTlsCert ;
use symbols ::{ Symbol , SymbolRunner } ;
@ -22,8 +24,11 @@ pub trait Policy {
fn user_name_for_host ( & self , host_name : & 'static str ) -> String {
host_name . split ( '.' ) . rev ( ) . fold ( String ::new ( ) , | result , part | if result . is_empty ( ) { result } else { result + "_" } + part )
}
fn home_for_user ( & self , user_name : & str ) -> String {
format ! ( "/home/{}" , user_name )
fn home_for_user ( & self , user_name : & str ) -> PathBuf {
format ! ( "/home/{}" , user_name ) . into ( )
}
fn socket_path ( & self , user_name : & str , service_name : & str ) -> PathBuf {
format ! ( "/var/tmp/{}-{}.socket" , user_name , service_name ) . into ( )
}
}
@ -42,7 +47,7 @@ impl<'b, C: 'b + CommandRunner, R: 'b + SymbolRunner, P: 'b + Policy> SymbolFact
pub fn new ( command_runner : & 'b C , symbol_runner : & 'b R , policy : & 'b P ) -> Self {
let acme_user = "acme" ; // FIXME: CONFIG
let acme_command_runner = SetuidCommandRunner ::new ( acme_user , command_runner ) ;
let acme_command_runner = SetuidCommandRunner ::new ( acme_user . into ( ) , command_runner ) ;
SymbolFactory {
command_runner ,
acme_command_runner ,
@ -57,14 +62,14 @@ impl<'b, C: 'b + CommandRunner, R: 'b + SymbolRunner, P: 'b + Policy> SymbolFact
nginx_server_symbol : S ,
) -> impl Symbol + 'a {
List ::from ( (
SelfSignedTlsCert ::new ( host . into ( ) , self . command_runner ) ,
SelfSignedTlsCert ::new ( host , self . command_runner ) ,
Hook ::new (
nginx_server_symbol ,
ReloadService ::new ( "nginx" , self . command_runner ) ,
) ,
AcmeCert ::new ( host . into ( ) , & self . acme_command_runner ) ,
AcmeCert ::new ( host , & self . acme_command_runner ) ,
Hook ::new (
AcmeCertChain ::new ( host . into ( ) , & self . acme_command_runner ) ,
AcmeCertChain ::new ( host , & self . acme_command_runner ) ,
ReloadService ::new ( "nginx" , self . command_runner ) ,
) ,
) )
@ -79,8 +84,8 @@ impl<'b, C: 'b + CommandRunner, R: 'b + SymbolRunner, P: 'b + Policy> SymbolFact
)
}
fn get_php_fpm_pool_socket_path < 'a > ( & 'a self , user_name : & str ) -> String {
format ! ( "/run/php/{}.sock" , user_name )
fn get_php_fpm_pool_socket_path < 'a > ( & 'a self , user_name : & str ) -> PathBuf {
format ! ( "/run/php/{}.sock" , user_name ) . into ( )
}
fn get_php_fpm_pool < 'a > ( & 'a self , user_name : & str ) -> impl Symbol + 'a {
@ -100,17 +105,18 @@ pm.max_children = 10
catch_workers_output = yes
env [ PATH ] = / usr / local / bin :/ usr / bin :/ bin
" ,
user_name , socket
user_name ,
socket . to_str ( ) . unwrap ( )
) ,
) ,
ReloadService ::new ( "php7.0-fpm" , self . command_runner ) ,
)
}
pub fn serve_php < 'a > (
pub fn serve_php < 'a , ROOT : AsRef < Path > > (
& 'a self ,
host_name : & 'static str ,
root_dir : Cow < 'a , str > ,
root_dir : ROOT ,
additional_config : & 'a str ,
) -> impl Symbol + 'a {
let user_name = self . policy . user_name_for_host ( host_name ) ;
@ -121,7 +127,7 @@ env[PATH] = /usr/local/bin:/usr/bin:/bin
host_name ,
NginxServer ::new_php (
host_name ,
socket . into ( ) ,
socket ,
root_dir ,
self . command_runner ,
additional_config ,
@ -130,10 +136,10 @@ env[PATH] = /usr/local/bin:/usr/bin:/bin
) )
}
pub fn serve_wordpress < 'a > (
pub fn serve_wordpress < 'a , ROOT : 'a + AsRef < Path > > (
& 'a self ,
host_name : & 'static str ,
root_dir : Cow < 'a , str > ,
root_dir : ROOT ,
) -> impl Symbol + 'a {
self . serve_php (
host_name ,
@ -179,16 +185,16 @@ env[PATH] = /usr/local/bin:/usr/bin:/bin
} }
" ,
root_dir ,
socket ) ) ,
socket . to_str ( ) . unwrap ( ) ) ) ,
self . command_runner
) )
) )
}
pub fn serve_nextcloud < 'a > (
pub fn serve_nextcloud < 'a , ROOT : 'a + AsRef < Path > > (
& 'a self ,
host_name : & 'static str ,
root_dir : Cow < 'a , str > ,
root_dir : ROOT ,
) -> impl Symbol + 'a {
self . serve_php (
host_name ,
@ -272,13 +278,13 @@ env[PATH] = /usr/local/bin:/usr/bin:/bin
let string_target = target . into ( ) ;
(
StoredDirectory ::new (
string_target . clone ( ) . into ( ) ,
string_target . clone ( ) ,
data . clone ( ) ,
StorageDirection ::Save ,
self . command_runner ,
) ,
StoredDirectory ::new (
string_target . into ( ) ,
string_target ,
data . clone ( ) ,
StorageDirection ::Load ,
self . command_runner ,
@ -290,11 +296,8 @@ env[PATH] = /usr/local/bin:/usr/bin:/bin
let db_dump = SimpleStorage ::new ( "/root/data" . to_string ( ) , format ! ( "{}.sql" , name ) ) ;
List ::from ( (
MariaDBDatabase ::new (
name . into ( ) ,
db_dump
. read_filename ( )
. expect ( "Initial db dump missing" )
. into ( ) ,
name ,
db_dump . read_filename ( ) . expect ( "Initial db dump missing" ) ,
self . command_runner ,
) ,
DatabaseDump ::new ( name , db_dump , self . command_runner ) ,
@ -302,10 +305,10 @@ env[PATH] = /usr/local/bin:/usr/bin:/bin
}
pub fn get_mariadb_user < 'a > ( & 'a self , user_name : & 'static str ) -> impl Symbol + 'a {
MariaDBUser ::new ( user_name . into ( ) , self . command_runner )
MariaDBUser ::new ( user_name , self . command_runner )
}
pub fn get_git_checkout < 'a , T : 'a + AsRef < str > > (
pub fn get_git_checkout < 'a , T : 'a + AsRef < Path > > (
& 'a self ,
target : T ,
source : & 'a str ,
@ -314,11 +317,15 @@ env[PATH] = /usr/local/bin:/usr/bin:/bin
GitCheckout ::new ( target , source , branch , self . command_runner )
}
pub fn get_owner < 'a , F : 'a + AsRef < str > > ( & 'a self , file : F , user : & 'a str ) -> impl Symbol + 'a {
Owner ::new ( file , user . into ( ) , self . command_runner )
pub fn get_owner < 'a , U : 'a + AsRef < str > , F : 'a + AsRef < Path > > (
& 'a self ,
file : F ,
user : U ,
) -> impl Symbol + 'a {
Owner ::new ( file , user , self . command_runner )
}
pub fn get_file < 'a , F : 'a + Deref < Target = str > , Q : 'a + AsRef < Path > > (
pub fn get_file < 'a , F : 'a + AsRef < str > , Q : 'a + AsRef < Path > > (
& 'a self ,
path : Q ,
content : F ,
@ -326,11 +333,94 @@ env[PATH] = /usr/local/bin:/usr/bin:/bin
File ::new ( path , content )
}
pub fn get_cron < 'a , T : 'a + Deref < Target = str > , U : 'a + Deref < Target = str > > (
pub fn get_cron < 'a , T : 'a + AsRef < str > , U : 'a + AsRef < str > > (
& 'a self ,
user : U ,
content : T ,
) -> impl Symbol + 'a {
Cron ::new ( user , content , self . command_runner )
}
pub fn get_acme_user < 'a , S : 'a + AsRef < str > , D : 'a + AsRef < str > > (
& 'a self ,
cert : D ,
user_name : S ,
) -> impl Symbol + 'a {
let home = self . policy . home_for_user ( user_name . as_ref ( ) ) ;
newAcmeUser ( self . command_runner , cert , user_name , home )
}
pub fn get_systemd_user_service < 'a > (
& 'a self ,
user_name : Cow < 'a , str > ,
service_name : & 'a str ,
config : Cow < 'a , str > ,
) -> impl Symbol + 'a {
let socket_path = self . policy . socket_path ( & user_name , service_name ) ;
let home = self . policy . home_for_user ( & user_name ) ;
UserService ::new (
socket_path . into ( ) ,
home . into ( ) ,
user_name ,
service_name ,
self . command_runner ,
config . into ( ) ,
)
}
fn get_nodejs_systemd_user_service < 'a , T : Into < Cow < 'a , Path > > > (
& 'a self ,
user_name : Cow < 'a , str > ,
service_name : & 'a str ,
path : T ,
) -> impl Symbol + 'a {
let socket_path = self . policy . socket_path ( & user_name , service_name ) ;
let home = self . policy . home_for_user ( & user_name ) ;
UserService ::new_nodejs (
home . into ( ) ,
user_name ,
service_name ,
path . into ( ) ,
self . command_runner ,
socket_path . into ( ) ,
)
}
pub fn proxy_socket < 'a , T : Into < Cow < 'a , Path > > > (
& 'a self ,
host_name : & 'static str ,
service_name : & 'a str ,
root_dir : T ,
) -> impl Symbol + 'a {
let user_name = self . policy . user_name_for_host ( host_name ) ;
let socket_path = self . policy . socket_path ( & user_name , service_name ) ;
self . get_nginx_acme_server (
host_name ,
NginxServer ::new_proxy ( host_name , socket_path , root_dir . into ( ) , self . command_runner ) ,
)
}
pub fn serve_nodejs <
'a ,
'c : 'a ,
S : 'a + Symbol ,
T : 'a + Into < Cow < 'a , Path > > ,
SP : 'a + Into < Cow < 'a , Path > > ,
> (
& 'c self ,
host : & 'static str ,
service_name : & 'a str ,
path : T ,
static_path : SP ,
nodejs_symbol : S ,
) -> impl Symbol + 'a {
let user_name = self . policy . user_name_for_host ( host ) ;
List ::from ( (
Hook ::new (
nodejs_symbol ,
self . get_nodejs_systemd_user_service ( user_name . into ( ) , service_name , path ) ,
) ,
self . proxy_socket ( host , service_name , static_path ) ,
) )
}
}