Compare commits
5 commits
b093a952be
...
59461f38f6
| Author | SHA1 | Date | |
|---|---|---|---|
| 59461f38f6 | |||
| bdfec3e127 | |||
| 1df56447de | |||
| 21018bd6f6 | |||
| e8b2f9fc5c |
10 changed files with 98 additions and 50 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
name = "schematics"
|
name = "schematics"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Adrian Heine <mail@adrianheine.de>"]
|
authors = ["Adrian Heine <mail@adrianheine.de>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
build = "src/build.rs"
|
build = "src/build.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ pub fn create_static_output_files(source_dir: &str) {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if err.kind() == NotFound {
|
if err.kind() == NotFound {
|
||||||
} else {
|
} else {
|
||||||
Err(err).unwrap()
|
Err(err).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::resources::{
|
||||||
Resource, ServeCustom, ServePhp, ServeRedir, ServeService, ServeStatic, StoredDirectory,
|
Resource, ServeCustom, ServePhp, ServeRedir, ServeService, ServeStatic, StoredDirectory,
|
||||||
SystemdSocketService, User, UserForDomain, WordpressPlugin, WordpressTranslation,
|
SystemdSocketService, User, UserForDomain, WordpressPlugin, WordpressTranslation,
|
||||||
};
|
};
|
||||||
use crate::static_files::LETS_ENCRYPT_R3_CROSS_SIGNED;
|
use crate::static_files::LETS_ENCRYPT_R3;
|
||||||
use crate::storage::SimpleStorage;
|
use crate::storage::SimpleStorage;
|
||||||
use crate::storage::Storage;
|
use crate::storage::Storage;
|
||||||
use crate::symbols::acme::Cert as CertSymbol;
|
use crate::symbols::acme::Cert as CertSymbol;
|
||||||
|
|
@ -33,7 +33,7 @@ use crate::symbols::wordpress::{
|
||||||
Plugin as WordpressPluginSymbol, Translation as WordpressTranslationSymbol,
|
Plugin as WordpressPluginSymbol, Translation as WordpressTranslationSymbol,
|
||||||
};
|
};
|
||||||
use crate::templates::nginx;
|
use crate::templates::nginx;
|
||||||
use crate::templates::php::fpm_pool_config as php_fpm_pool_config;
|
use crate::templates::php::{fpm_pool_config as php_fpm_pool_config, FpmPoolConfig as PhpFpmPoolConfig};
|
||||||
use crate::templates::systemd::{
|
use crate::templates::systemd::{
|
||||||
nodejs_service as systemd_nodejs_service, socket_service as systemd_socket_service,
|
nodejs_service as systemd_nodejs_service, socket_service as systemd_socket_service,
|
||||||
};
|
};
|
||||||
|
|
@ -250,16 +250,16 @@ impl<D: AsRef<str> + Clone + Display> ImplementationBuilder<ServeCustom<D>> for
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Clone + Display, P: AsRef<Path>> ImplementationBuilder<ServePhp<D, P>> for DefaultBuilder {
|
impl<D: Clone + Display, P: AsRef<Path>, C: Clone + Into<PhpFpmPoolConfig>> ImplementationBuilder<ServePhp<D, P, C>> for DefaultBuilder {
|
||||||
type Prerequisites = (
|
type Prerequisites = (
|
||||||
PhpFpmPool<D>,
|
PhpFpmPool<D>,
|
||||||
CertChain<D>,
|
CertChain<D>,
|
||||||
Key<D>,
|
Key<D>,
|
||||||
AcmeChallengesNginxSnippet,
|
AcmeChallengesNginxSnippet,
|
||||||
);
|
);
|
||||||
fn prerequisites(resource: &ServePhp<D, P>) -> Self::Prerequisites {
|
fn prerequisites(resource: &ServePhp<D, P, C>) -> Self::Prerequisites {
|
||||||
(
|
(
|
||||||
PhpFpmPool(resource.0.clone(), 10),
|
PhpFpmPool(resource.0.clone(), resource.4.clone().into()),
|
||||||
CertChain(resource.0.clone()),
|
CertChain(resource.0.clone()),
|
||||||
Key(resource.0.clone()),
|
Key(resource.0.clone()),
|
||||||
AcmeChallengesNginxSnippet,
|
AcmeChallengesNginxSnippet,
|
||||||
|
|
@ -271,8 +271,8 @@ impl<D: Clone + Display, P: AsRef<Path>> ImplementationBuilder<ServePhp<D, P>> f
|
||||||
ReloadServiceSymbol<StdCommandRunner, StdCommandRunner, &'static str>,
|
ReloadServiceSymbol<StdCommandRunner, StdCommandRunner, &'static str>,
|
||||||
);
|
);
|
||||||
fn create(
|
fn create(
|
||||||
resource: &ServePhp<D, P>,
|
resource: &ServePhp<D, P, C>,
|
||||||
target: &<ServePhp<D, P> as Resource>::Artifact,
|
target: &<ServePhp<D, P, C> as Resource>::Artifact,
|
||||||
(pool, cert, key, challenges_snippet_path): <Self::Prerequisites as ToArtifact>::Artifact,
|
(pool, cert, key, challenges_snippet_path): <Self::Prerequisites as ToArtifact>::Artifact,
|
||||||
) -> Self::Implementation {
|
) -> Self::Implementation {
|
||||||
(
|
(
|
||||||
|
|
@ -428,7 +428,7 @@ impl<D: Clone> ImplementationBuilder<PhpFpmPool<D>> for DefaultBuilder {
|
||||||
(
|
(
|
||||||
FileSymbol::new(
|
FileSymbol::new(
|
||||||
conf_path.clone().into(),
|
conf_path.clone().into(),
|
||||||
php_fpm_pool_config(&user_name.0, &socket_path, resource.1),
|
php_fpm_pool_config(&user_name.0, &socket_path, &resource.1),
|
||||||
),
|
),
|
||||||
ReloadServiceSymbol::new(StdCommandRunner, service_name.0.clone()),
|
ReloadServiceSymbol::new(StdCommandRunner, service_name.0.clone()),
|
||||||
)
|
)
|
||||||
|
|
@ -676,7 +676,7 @@ impl ImplementationBuilder<AcmeRootCert> for DefaultBuilder {
|
||||||
target: &<AcmeRootCert as Resource>::Artifact,
|
target: &<AcmeRootCert as Resource>::Artifact,
|
||||||
(): <Self::Prerequisites as ToArtifact>::Artifact,
|
(): <Self::Prerequisites as ToArtifact>::Artifact,
|
||||||
) -> Self::Implementation {
|
) -> Self::Implementation {
|
||||||
FileSymbol::new(target.clone().into(), LETS_ENCRYPT_R3_CROSS_SIGNED)
|
FileSymbol::new(target.clone().into(), LETS_ENCRYPT_R3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ where
|
||||||
{
|
{
|
||||||
async fn run(&self, program: &str, args: &[&OsStr], input: &str) -> IoResult<Output> {
|
async fn run(&self, program: &str, args: &[&OsStr], input: &str) -> IoResult<Output> {
|
||||||
let raw_new_args = [self.user_name, "-s", "/usr/bin/env", "--", program];
|
let raw_new_args = [self.user_name, "-s", "/usr/bin/env", "--", program];
|
||||||
let mut new_args: Vec<&OsStr> = raw_new_args.iter().map(|s| s.as_ref()).collect();
|
let mut new_args: Vec<&OsStr> = raw_new_args.iter().map(AsRef::as_ref).collect();
|
||||||
new_args.extend_from_slice(args);
|
new_args.extend_from_slice(args);
|
||||||
self.command_runner.run("su", &new_args, input).await
|
self.command_runner.run("su", &new_args, input).await
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,7 @@ impl<P: Policy> ResourceLocator<AcmeRootCert> for DefaultLocator<P> {
|
||||||
let acme_user = P::acme_user();
|
let acme_user = P::acme_user();
|
||||||
let home = P::user_home(acme_user);
|
let home = P::user_home(acme_user);
|
||||||
(
|
(
|
||||||
PathArtifact::from(home.join("lets_encrypt_r3_cross_signed.pem")),
|
PathArtifact::from(home.join("lets_encrypt_r3.pem")),
|
||||||
Dir(home),
|
Dir(home),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -298,11 +298,11 @@ impl<D: AsRef<Path>, POLICY> ResourceLocator<ServeCustom<D>> for DefaultLocator<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: AsRef<Path>, P, POLICY> ResourceLocator<ServePhp<D, P>> for DefaultLocator<POLICY> {
|
impl<D: AsRef<Path>, P, C, POLICY> ResourceLocator<ServePhp<D, P, C>> for DefaultLocator<POLICY> {
|
||||||
type Prerequisites = ();
|
type Prerequisites = ();
|
||||||
fn locate(
|
fn locate(
|
||||||
resource: &ServePhp<D, P>,
|
resource: &ServePhp<D, P, C>,
|
||||||
) -> (<ServePhp<D, P> as Resource>::Artifact, Self::Prerequisites) {
|
) -> (<ServePhp<D, P, C> as Resource>::Artifact, Self::Prerequisites) {
|
||||||
(
|
(
|
||||||
PathArtifact::from(Path::new("/etc/nginx/sites-enabled/").join(&resource.0)),
|
PathArtifact::from(Path::new("/etc/nginx/sites-enabled/").join(&resource.0)),
|
||||||
(),
|
(),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use crate::artifacts::{
|
||||||
DatabaseName as DatabaseNameArtifact, Path as PathArtifact, ServiceName as ServiceNameArtifact,
|
DatabaseName as DatabaseNameArtifact, Path as PathArtifact, ServiceName as ServiceNameArtifact,
|
||||||
UserName as UserNameArtifact,
|
UserName as UserNameArtifact,
|
||||||
};
|
};
|
||||||
|
use crate::templates::php::FpmPoolConfig;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
|
@ -146,8 +147,14 @@ impl<D> Resource for ServeCustom<D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||||
pub struct ServePhp<D, P>(pub D, pub P, pub &'static str, pub String, pub usize);
|
pub struct ServePhp<D, P, C>(
|
||||||
impl<D, P> Resource for ServePhp<D, P> {
|
pub D,
|
||||||
|
pub P,
|
||||||
|
pub &'static str,
|
||||||
|
pub String,
|
||||||
|
pub C,
|
||||||
|
);
|
||||||
|
impl<D, P, C> Resource for ServePhp<D, P, C> {
|
||||||
type Artifact = PathArtifact;
|
type Artifact = PathArtifact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,7 +184,7 @@ impl Resource for DefaultServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||||
pub struct PhpFpmPool<D>(pub D, pub usize);
|
pub struct PhpFpmPool<D>(pub D, pub FpmPoolConfig);
|
||||||
impl<D> Resource for PhpFpmPool<D> {
|
impl<D> Resource for PhpFpmPool<D> {
|
||||||
type Artifact = (
|
type Artifact = (
|
||||||
PathArtifact,
|
PathArtifact,
|
||||||
|
|
@ -275,6 +282,7 @@ macro_rules! default_resources {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only one enum entry per resource type, otherwise the equality checks fail
|
||||||
default_resources!(
|
default_resources!(
|
||||||
AcmeAccountKey: AcmeAccountKey,
|
AcmeAccountKey: AcmeAccountKey,
|
||||||
AcmeChallengesDir: AcmeChallengesDir,
|
AcmeChallengesDir: AcmeChallengesDir,
|
||||||
|
|
@ -301,7 +309,7 @@ default_resources!(
|
||||||
PhpFpmPool: PhpFpmPool<D>,
|
PhpFpmPool: PhpFpmPool<D>,
|
||||||
ServeCustom: ServeCustom<D>,
|
ServeCustom: ServeCustom<D>,
|
||||||
ServeService: ServeService<D, PathBuf>,
|
ServeService: ServeService<D, PathBuf>,
|
||||||
ServePhp: ServePhp<D, PathBuf>,
|
ServePhp: ServePhp<D, PathBuf, FpmPoolConfig>,
|
||||||
ServeRedir: ServeRedir<D>,
|
ServeRedir: ServeRedir<D>,
|
||||||
ServeStatic: ServeStatic<D, PathBuf>,
|
ServeStatic: ServeStatic<D, PathBuf>,
|
||||||
StoredDirectory: StoredDirectory<PathBuf>,
|
StoredDirectory: StoredDirectory<PathBuf>,
|
||||||
|
|
@ -310,3 +318,8 @@ default_resources!(
|
||||||
WordpressPlugin: WordpressPlugin<PathBuf>,
|
WordpressPlugin: WordpressPlugin<PathBuf>,
|
||||||
WordpressTranslation: WordpressTranslation<PathBuf>,
|
WordpressTranslation: WordpressTranslation<PathBuf>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
pub fn serve_php<D, P: Into<PathBuf>, C: Into<FpmPoolConfig>>(domain: D, path: P, root_filename: &'static str, nginx_config: impl Into<String>, pool_config: C) -> ServePhp<D, PathBuf, FpmPoolConfig> {
|
||||||
|
ServePhp(
|
||||||
|
domain, path.into(), root_filename, nginx_config.into(), pool_config.into())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ impl<N: AsRef<str>, C: CommandRunner, S: Storage> Symbol for Dump<'_, N, C, S> {
|
||||||
let dump_date = self.storage.recent_date()?;
|
let dump_date = self.storage.recent_date()?;
|
||||||
let output = self.run_sql(&format!("select UNIX_TIMESTAMP(MAX(UPDATE_TIME)) from information_schema.tables WHERE table_schema = '{}'", self.db_name.as_ref())).await?;
|
let output = self.run_sql(&format!("select UNIX_TIMESTAMP(MAX(UPDATE_TIME)) from information_schema.tables WHERE table_schema = '{}'", self.db_name.as_ref())).await?;
|
||||||
let modified_date = output.trim_end();
|
let modified_date = output.trim_end();
|
||||||
Ok(modified_date != "NULL" && u64::from_str(modified_date)? <= dump_date)
|
Ok(modified_date == "NULL" || u64::from_str(modified_date)? <= dump_date)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,40 @@
|
||||||
|
use std::fmt::{Display, Error, Formatter};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Hash, Eq)]
|
||||||
|
pub struct FpmPoolConfig {
|
||||||
|
max_children: usize,
|
||||||
|
custom: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for FpmPoolConfig {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||||
|
match &self.custom {
|
||||||
|
None => write!(f, "pm.max_children = {}", self.max_children),
|
||||||
|
Some(custom) => write!(f, "pm.max_children = {}\n{}", self.max_children, custom),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<usize> for FpmPoolConfig {
|
||||||
|
fn from(max_children: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
max_children,
|
||||||
|
custom: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FpmPoolConfig {
|
||||||
|
pub fn new(max_children: usize, custom: impl Into<String>) -> Self {
|
||||||
|
Self { max_children, custom: Some(custom.into()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fpm_pool_config<U: AsRef<str>, S: AsRef<Path>>(
|
pub fn fpm_pool_config<U: AsRef<str>, S: AsRef<Path>>(
|
||||||
user_name: U,
|
user_name: U,
|
||||||
socket_path: S,
|
socket_path: S,
|
||||||
max_children: usize,
|
config: &FpmPoolConfig,
|
||||||
) -> String {
|
) -> String {
|
||||||
format!(
|
format!(
|
||||||
"[{0}]
|
"[{0}]
|
||||||
|
|
@ -13,12 +44,12 @@ group = www-data
|
||||||
listen = {1}
|
listen = {1}
|
||||||
listen.owner = www-data
|
listen.owner = www-data
|
||||||
pm = ondemand
|
pm = ondemand
|
||||||
pm.max_children = {2}
|
|
||||||
catch_workers_output = yes
|
catch_workers_output = yes
|
||||||
env[PATH] = /usr/local/bin:/usr/bin:/bin
|
env[PATH] = /usr/local/bin:/usr/bin:/bin
|
||||||
|
{2}
|
||||||
",
|
",
|
||||||
user_name.as_ref(),
|
user_name.as_ref(),
|
||||||
socket_path.as_ref().to_str().unwrap(),
|
socket_path.as_ref().to_str().unwrap(),
|
||||||
max_children,
|
config
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
static_files/lets_encrypt_r3.pem
Normal file
30
static_files/lets_encrypt_r3.pem
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
nLRbwHOoq7hHwg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEZTCCA02gAwIBAgIQQAF1BIMUpMghjISpDBbN3zANBgkqhkiG9w0BAQsFADA/
|
|
||||||
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
|
||||||
DkRTVCBSb290IENBIFgzMB4XDTIwMTAwNzE5MjE0MFoXDTIxMDkyOTE5MjE0MFow
|
|
||||||
MjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxCzAJBgNVBAMT
|
|
||||||
AlIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuwIVKMz2oJTTDxLs
|
|
||||||
jVWSw/iC8ZmmekKIp10mqrUrucVMsa+Oa/l1yKPXD0eUFFU1V4yeqKI5GfWCPEKp
|
|
||||||
Tm71O8Mu243AsFzzWTjn7c9p8FoLG77AlCQlh/o3cbMT5xys4Zvv2+Q7RVJFlqnB
|
|
||||||
U840yFLuta7tj95gcOKlVKu2bQ6XpUA0ayvTvGbrZjR8+muLj1cpmfgwF126cm/7
|
|
||||||
gcWt0oZYPRfH5wm78Sv3htzB2nFd1EbjzK0lwYi8YGd1ZrPxGPeiXOZT/zqItkel
|
|
||||||
/xMY6pgJdz+dU/nPAeX1pnAXFK9jpP+Zs5Od3FOnBv5IhR2haa4ldbsTzFID9e1R
|
|
||||||
oYvbFQIDAQABo4IBaDCCAWQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E
|
|
||||||
BAMCAYYwSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5p
|
|
||||||
ZGVudHJ1c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTE
|
|
||||||
p7Gkeyxx+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEE
|
|
||||||
AYLfEwEBATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2Vu
|
|
||||||
Y3J5cHQub3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0
|
|
||||||
LmNvbS9EU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYf
|
|
||||||
r52LFMLGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0B
|
|
||||||
AQsFAAOCAQEA2UzgyfWEiDcx27sT4rP8i2tiEmxYt0l+PAK3qB8oYevO4C5z70kH
|
|
||||||
ejWEHx2taPDY/laBL21/WKZuNTYQHHPD5b1tXgHXbnL7KqC401dk5VvCadTQsvd8
|
|
||||||
S8MXjohyc9z9/G2948kLjmE6Flh9dDYrVYA9x2O+hEPGOaEOa1eePynBgPayvUfL
|
|
||||||
qjBstzLhWVQLGAkXXmNs+5ZnPBxzDJOLxhF2JIbeQAcH5H0tZrUlo5ZYyOqA7s9p
|
|
||||||
O5b85o3AM/OJ+CktFBQtfvBhcJVd9wvlwPsk+uyOy2HI7mNxKKgsBTt375teA2Tw
|
|
||||||
UdHkhVNcsAKX1H7GNNLOEADksd86wuoXvg==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue