Periodically refresh certs for all domains
This commit is contained in:
parent
5b26396106
commit
06cda77772
@ -1,4 +1,5 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::str::FromStr;
|
||||||
use std::{fs, io, sync};
|
use std::{fs, io, sync};
|
||||||
|
|
||||||
use crate::error::{MapUnexpected, ToUnexpected};
|
use crate::error::{MapUnexpected, ToUnexpected};
|
||||||
@ -37,10 +38,14 @@ pub enum SetError {
|
|||||||
Unexpected(#[from] error::Unexpected),
|
Unexpected(#[from] error::Unexpected),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used in the return from all_domains from Store.
|
||||||
|
pub type AllDomainsResult<T> = Result<T, error::Unexpected>;
|
||||||
|
|
||||||
#[mockall::automock]
|
#[mockall::automock]
|
||||||
pub trait Store {
|
pub trait Store {
|
||||||
fn get(&self, domain: &domain::Name) -> Result<Config, GetError>;
|
fn get(&self, domain: &domain::Name) -> Result<Config, GetError>;
|
||||||
fn set(&self, domain: &domain::Name, config: &Config) -> Result<(), SetError>;
|
fn set(&self, domain: &domain::Name, config: &Config) -> Result<(), SetError>;
|
||||||
|
fn all_domains(&self) -> AllDomainsResult<Vec<AllDomainsResult<domain::Name>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BoxedStore: Store + Send + Sync + Clone {}
|
pub trait BoxedStore: Store + Send + Sync + Clone {}
|
||||||
@ -89,6 +94,22 @@ impl Store for sync::Arc<FSStore> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn all_domains(&self) -> AllDomainsResult<Vec<AllDomainsResult<domain::Name>>> {
|
||||||
|
Ok(fs::read_dir(&self.dir_path)
|
||||||
|
.map_unexpected()?
|
||||||
|
.map(
|
||||||
|
|dir_entry_res: io::Result<fs::DirEntry>| -> AllDomainsResult<domain::Name> {
|
||||||
|
let domain = dir_entry_res.map_unexpected()?.file_name();
|
||||||
|
let domain = domain.to_str().ok_or_else(|| {
|
||||||
|
error::Unexpected::from("couldn't convert os string to &str")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(domain::Name::from_str(domain).map_unexpected()?)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -115,6 +115,8 @@ impl From<config::SetError> for SyncWithConfigError {
|
|||||||
|
|
||||||
pub type GetAcmeHttp01ChallengeKeyError = acme::manager::GetHttp01ChallengeKeyError;
|
pub type GetAcmeHttp01ChallengeKeyError = acme::manager::GetHttp01ChallengeKeyError;
|
||||||
|
|
||||||
|
pub type AllDomainsResult<T> = config::AllDomainsResult<T>;
|
||||||
|
|
||||||
#[mockall::automock(
|
#[mockall::automock(
|
||||||
type Origin=origin::MockOrigin;
|
type Origin=origin::MockOrigin;
|
||||||
type SyncWithConfigFuture=future::Ready<Result<(), SyncWithConfigError>>;
|
type SyncWithConfigFuture=future::Ready<Result<(), SyncWithConfigError>>;
|
||||||
@ -153,6 +155,8 @@ pub trait Manager {
|
|||||||
&self,
|
&self,
|
||||||
token: &str,
|
token: &str,
|
||||||
) -> Result<String, GetAcmeHttp01ChallengeKeyError>;
|
) -> Result<String, GetAcmeHttp01ChallengeKeyError>;
|
||||||
|
|
||||||
|
fn all_domains(&self) -> AllDomainsResult<Vec<AllDomainsResult<domain::Name>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BoxedManager: Manager + Send + Sync + Clone {}
|
pub trait BoxedManager: Manager + Send + Sync + Clone {}
|
||||||
@ -283,4 +287,8 @@ where
|
|||||||
|
|
||||||
Err(GetAcmeHttp01ChallengeKeyError::NotFound)
|
Err(GetAcmeHttp01ChallengeKeyError::NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn all_domains(&self) -> AllDomainsResult<Vec<AllDomainsResult<domain::Name>>> {
|
||||||
|
self.domain_config_store.all_domains()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
39
src/main.rs
39
src/main.rs
@ -158,7 +158,7 @@ fn main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let service = domiply::service::new(
|
let service = domiply::service::new(
|
||||||
manager,
|
manager.clone(),
|
||||||
config.domain_checker_target_a,
|
config.domain_checker_target_a,
|
||||||
config.passphrase,
|
config.passphrase,
|
||||||
config.http_domain.clone(),
|
config.http_domain.clone(),
|
||||||
@ -181,6 +181,7 @@ fn main() {
|
|||||||
|
|
||||||
wait_group.push({
|
wait_group.push({
|
||||||
let http_domain = config.http_domain.clone();
|
let http_domain = config.http_domain.clone();
|
||||||
|
let canceller = canceller.clone();
|
||||||
|
|
||||||
tokio_runtime.spawn(async move {
|
tokio_runtime.spawn(async move {
|
||||||
let addr = config.http_listen_addr;
|
let addr = config.http_listen_addr;
|
||||||
@ -205,9 +206,20 @@ fn main() {
|
|||||||
// if there's an acme manager then it means that https is enabled, and we should ensure that
|
// if there's an acme manager then it means that https is enabled, and we should ensure that
|
||||||
// the http domain for domiply itself has a valid certificate.
|
// the http domain for domiply itself has a valid certificate.
|
||||||
if let Some(domain_acme_manager) = domain_acme_manager {
|
if let Some(domain_acme_manager) = domain_acme_manager {
|
||||||
|
let manager = manager.clone();
|
||||||
|
let canceller = canceller.clone();
|
||||||
let http_domain = config.http_domain.clone();
|
let http_domain = config.http_domain.clone();
|
||||||
|
|
||||||
|
// Periodically refresh all domain certs
|
||||||
wait_group.push(tokio_runtime.spawn(async move {
|
wait_group.push(tokio_runtime.spawn(async move {
|
||||||
|
let mut interval = time::interval(time::Duration::from_secs(60 * 60));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
select! {
|
||||||
|
_ = interval.tick() => (),
|
||||||
|
_ = canceller.cancelled() => return,
|
||||||
|
}
|
||||||
|
|
||||||
_ = domain_acme_manager
|
_ = domain_acme_manager
|
||||||
.sync_domain(http_domain.clone())
|
.sync_domain(http_domain.clone())
|
||||||
.await
|
.await
|
||||||
@ -217,6 +229,31 @@ fn main() {
|
|||||||
http_domain.as_str()
|
http_domain.as_str()
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let domains_iter = manager.all_domains();
|
||||||
|
|
||||||
|
if let Err(err) = domains_iter {
|
||||||
|
println!("Got error calling all_domains: {err}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for domain in domains_iter.unwrap().into_iter() {
|
||||||
|
match domain {
|
||||||
|
Ok(domain) => {
|
||||||
|
let _ = domain_acme_manager
|
||||||
|
.sync_domain(domain.clone())
|
||||||
|
.await
|
||||||
|
.inspect_err(|err| {
|
||||||
|
println!(
|
||||||
|
"Error while getting cert for {}: {err}",
|
||||||
|
domain.as_str(),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(err) => println!("Error iterating through domains: {err}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user