Split domain manager "sync all domains" task into separate ones

Each new task corresponds to syncing a particular kind of thing for each
domain, e.g. origins, https certs, etc...
main
Brian Picciano 4 months ago
parent 70c78b823a
commit c95f4b9b39
  1. 244
      src/domain/manager.rs

@ -182,12 +182,58 @@ impl ManagerImpl {
config,
});
const SYNC_PERIOD_SECS: u64 = 20 * 60; // 20 minutes
task_stack.push_spawn_periodically(
manager.clone(),
20 * 60,
|_canceller, manager| async move { manager.sync_all_domains().await },
SYNC_PERIOD_SECS,
|_canceller, manager| async move {
manager
.sync_origins()
.await
.or_unexpected_while("syncing origins")
},
);
if manager.can_sync_gemini_cert() {
task_stack.push_spawn_periodically(
manager.clone(),
SYNC_PERIOD_SECS,
|_canceller, manager| async move {
manager
.sync_gemini_certs()
.await
.or_unexpected_while("syncing gemini certs")
},
);
}
if manager.can_sync_https_cert() {
task_stack.push_spawn_periodically(
manager.clone(),
SYNC_PERIOD_SECS,
|_canceller, manager| async move {
manager
.sync_https_certs()
.await
.or_unexpected_while("syncing https certs")
},
);
}
if manager.can_sync_external_cert() {
task_stack.push_spawn_periodically(
manager.clone(),
SYNC_PERIOD_SECS,
|_canceller, manager| async move {
manager
.sync_external_certs()
.await
.or_unexpected_while("syncing external certs")
},
);
}
manager
}
@ -200,99 +246,155 @@ impl ManagerImpl {
self.origin_store.sync(origin_descr)
}
fn sync_domain_gemini_cert(&self, domain: &domain::Name) -> unexpected::Result<()> {
if let Some(ref gemini_store) = self.gemini_store {
log::info!("Syncing gemini certificate for domain {domain}");
if gemini_store
.get_certificate(domain)
.or_unexpected()?
.is_some()
{
return Ok(());
}
async fn sync_origins(&self) -> unexpected::Result<()> {
let domains = self
.all_domains()
.or_unexpected_while("fetching all domains")?
.into_iter();
// no cert/key stored for the domain, generate and store it
let pkey = tls::PrivateKey::new();
let cert = tls::Certificate::new_self_signed(&pkey, domain)
.or_unexpected_while("creating self-signed cert")?;
for ManagedDomain { domain, .. } in domains {
let settings = match self
.get_settings(&domain)
.map_unexpected_while(|| format!("fetching settings for {domain}"))?
{
GetSettingsResult::Stored(settings) => settings,
GetSettingsResult::Builtin(config) => config.settings,
_ => continue,
};
gemini_store.set_certificate(domain, pkey, cert)?;
self.sync_domain_origin(&domain, &settings.origin_descr)
.map_unexpected_while(|| {
format!(
"syncing origin {:?} for domain {domain}",
&settings.origin_descr,
)
})?;
}
Ok(())
}
async fn sync_domain_https_cert(&self, domain: &domain::Name) -> unexpected::Result<()> {
if let Some(ref acme_manager) = self.acme_manager {
log::info!("Syncing HTTPS certificate for domain {domain}");
acme_manager.sync_domain(domain.clone(), None).await?;
fn can_sync_gemini_cert(&self) -> bool {
self.gemini_store.is_some()
}
fn sync_domain_gemini_cert(&self, domain: &domain::Name) -> unexpected::Result<()> {
let gemini_store = self.gemini_store.as_ref().unwrap();
log::info!("Syncing gemini certificate for domain {domain}");
if gemini_store
.get_certificate(domain)
.or_unexpected_while("checking if cert is already stored")?
.is_some()
{
return Ok(());
}
Ok(())
// no cert/key stored for the domain, generate and store it
let pkey = tls::PrivateKey::new();
let cert = tls::Certificate::new_self_signed(&pkey, domain)
.or_unexpected_while("creating self-signed cert")?;
gemini_store.set_certificate(domain, pkey, cert)
}
async fn sync_external_domain(
&self,
domain: &domain::Name,
config: &domain::ConfigExternalDomain,
) -> unexpected::Result<()> {
if let Some(ref acme_manager) = self.acme_manager {
log::info!("Syncing HTTPS certificate for external domain {domain}");
acme_manager
.sync_domain(domain.clone(), Some(config.clone()))
.await?;
async fn sync_gemini_certs(&self) -> unexpected::Result<()> {
let domains = self
.all_domains()
.or_unexpected_while("fetching all domains")?
.into_iter();
for ManagedDomain { domain, .. } in domains {
match self
.get_settings(&domain)
.map_unexpected_while(|| format!("fetching settings for {domain}"))?
{
GetSettingsResult::Stored(_) => (),
GetSettingsResult::Builtin(_) => (),
_ => continue,
};
self.sync_domain_gemini_cert(&domain)
.map_unexpected_while(|| format!("syncing domain {domain}"))?;
}
Ok(())
}
async fn sync_all_domains(&self) -> unexpected::Result<()> {
fn can_sync_https_cert(&self) -> bool {
self.acme_manager.is_some()
}
async fn sync_domain_https_cert(&self, domain: &domain::Name) -> unexpected::Result<()> {
log::info!("Syncing HTTPS certificate for domain {domain}");
self.acme_manager
.as_ref()
.unwrap()
.sync_domain(domain.clone(), None)
.await
}
async fn sync_https_certs(&self) -> unexpected::Result<()> {
let domains = self
.all_domains()
.or_unexpected_while("fetching all domains")?
.into_iter();
for ManagedDomain { domain, .. } in domains {
let (settings, https_cert, gemini_cert) = match self
match self
.get_settings(&domain)
.map_unexpected_while(|| format!("fetching settings for {domain}"))?
{
GetSettingsResult::Stored(settings) => (Some(settings), true, true),
GetSettingsResult::Builtin(config) => (Some(config.settings), true, true),
GetSettingsResult::Stored(_) => (),
GetSettingsResult::Builtin(_) => (),
GetSettingsResult::Proxied(config) => {
if config.https_disabled {
continue;
}
}
GetSettingsResult::Interface => (),
_ => continue,
};
// A proxied domain never needs gemini certs, since gemini requests will be
// transparently proxied to the backing server anyway.
GetSettingsResult::Proxied(config) => (None, !config.https_disabled, false),
self.sync_domain_https_cert(&domain)
.await
.map_unexpected_while(|| format!("syncing domain {domain}",))?;
}
GetSettingsResult::Interface => (None, true, false),
Ok(())
}
// External domains do their own thing, separate from the rest of this flow.
GetSettingsResult::External(config) => {
self.sync_external_domain(&domain, &config)
.await
.map_unexpected_while(|| format!("syncing external domain {domain}"))?;
continue;
}
};
fn can_sync_external_cert(&self) -> bool {
self.acme_manager.is_some()
}
if let Some(settings) = settings {
self.sync_domain_origin(&domain, &settings.origin_descr)
.map_unexpected_while(|| {
format!(
"syncing origin {:?} for domain {domain}",
&settings.origin_descr,
)
})?;
}
async fn sync_external_domain(
&self,
domain: &domain::Name,
config: &domain::ConfigExternalDomain,
) -> unexpected::Result<()> {
log::info!("Syncing HTTPS certificate for external domain {domain}");
self.acme_manager
.as_ref()
.unwrap()
.sync_domain(domain.clone(), Some(config.clone()))
.await
}
if gemini_cert {
self.sync_domain_gemini_cert(&domain)
.map_unexpected_while(|| format!("syncing gemini cert for domain {domain}"))?;
}
async fn sync_external_certs(&self) -> unexpected::Result<()> {
let domains = self
.all_domains()
.or_unexpected_while("fetching all domains")?
.into_iter();
if https_cert {
self.sync_domain_https_cert(&domain)
for ManagedDomain { domain, .. } in domains {
if let GetSettingsResult::External(config) = self
.get_settings(&domain)
.map_unexpected_while(|| format!("fetching settings for {domain}"))?
{
self.sync_external_domain(&domain, &config)
.await
.map_unexpected_while(|| format!("syncing https cert for domain {domain}",))?;
.map_unexpected_while(|| format!("syncing external {domain}"))?;
}
}
@ -376,12 +478,16 @@ impl Manager for ManagerImpl {
self.sync_domain_origin(&domain, &settings.origin_descr)?;
self.sync_domain_gemini_cert(&domain)
.or_unexpected_while("syncing domain gemini cert")?;
if self.can_sync_gemini_cert() {
self.sync_domain_gemini_cert(&domain)
.or_unexpected_while("syncing domain gemini cert")?;
}
self.sync_domain_https_cert(&domain)
.await
.or_unexpected_while("syncing domain https cert")?;
if self.can_sync_https_cert() {
self.sync_domain_https_cert(&domain)
.await
.or_unexpected_while("syncing domain https cert")?;
}
self.domain_store.set(&domain, &settings)?;

Loading…
Cancel
Save