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...
This commit is contained in:
Brian Picciano 2024-01-14 15:34:13 +01:00
parent 70c78b823a
commit c95f4b9b39

View File

@ -182,12 +182,58 @@ impl ManagerImpl {
config, config,
}); });
const SYNC_PERIOD_SECS: u64 = 20 * 60; // 20 minutes
task_stack.push_spawn_periodically( task_stack.push_spawn_periodically(
manager.clone(), manager.clone(),
20 * 60, SYNC_PERIOD_SECS,
|_canceller, manager| async move { manager.sync_all_domains().await }, |_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 manager
} }
@ -200,99 +246,155 @@ impl ManagerImpl {
self.origin_store.sync(origin_descr) self.origin_store.sync(origin_descr)
} }
fn sync_domain_gemini_cert(&self, domain: &domain::Name) -> unexpected::Result<()> { async fn sync_origins(&self) -> unexpected::Result<()> {
if let Some(ref gemini_store) = self.gemini_store { let domains = self
log::info!("Syncing gemini certificate for domain {domain}"); .all_domains()
if gemini_store .or_unexpected_while("fetching all domains")?
.get_certificate(domain) .into_iter();
.or_unexpected()?
.is_some() for ManagedDomain { domain, .. } in domains {
let settings = match self
.get_settings(&domain)
.map_unexpected_while(|| format!("fetching settings for {domain}"))?
{ {
return Ok(()); GetSettingsResult::Stored(settings) => settings,
} GetSettingsResult::Builtin(config) => config.settings,
_ => continue,
};
// no cert/key stored for the domain, generate and store it self.sync_domain_origin(&domain, &settings.origin_descr)
let pkey = tls::PrivateKey::new(); .map_unexpected_while(|| {
let cert = tls::Certificate::new_self_signed(&pkey, domain) format!(
.or_unexpected_while("creating self-signed cert")?; "syncing origin {:?} for domain {domain}",
&settings.origin_descr,
gemini_store.set_certificate(domain, pkey, cert)?; )
})?;
} }
Ok(()) Ok(())
} }
async fn sync_domain_https_cert(&self, domain: &domain::Name) -> unexpected::Result<()> { fn can_sync_gemini_cert(&self) -> bool {
if let Some(ref acme_manager) = self.acme_manager { self.gemini_store.is_some()
log::info!("Syncing HTTPS certificate for domain {domain}"); }
acme_manager.sync_domain(domain.clone(), None).await?;
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(());
}
// 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_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(()) Ok(())
} }
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 {
match self
.get_settings(&domain)
.map_unexpected_while(|| format!("fetching settings for {domain}"))?
{
GetSettingsResult::Stored(_) => (),
GetSettingsResult::Builtin(_) => (),
GetSettingsResult::Proxied(config) => {
if config.https_disabled {
continue;
}
}
GetSettingsResult::Interface => (),
_ => continue,
};
self.sync_domain_https_cert(&domain)
.await
.map_unexpected_while(|| format!("syncing domain {domain}",))?;
}
Ok(())
}
fn can_sync_external_cert(&self) -> bool {
self.acme_manager.is_some()
}
async fn sync_external_domain( async fn sync_external_domain(
&self, &self,
domain: &domain::Name, domain: &domain::Name,
config: &domain::ConfigExternalDomain, config: &domain::ConfigExternalDomain,
) -> unexpected::Result<()> { ) -> unexpected::Result<()> {
if let Some(ref acme_manager) = self.acme_manager { log::info!("Syncing HTTPS certificate for external domain {domain}");
log::info!("Syncing HTTPS certificate for external domain {domain}"); self.acme_manager
acme_manager .as_ref()
.sync_domain(domain.clone(), Some(config.clone())) .unwrap()
.await?; .sync_domain(domain.clone(), Some(config.clone()))
} .await
Ok(())
} }
async fn sync_all_domains(&self) -> unexpected::Result<()> { async fn sync_external_certs(&self) -> unexpected::Result<()> {
let domains = self let domains = self
.all_domains() .all_domains()
.or_unexpected_while("fetching all domains")? .or_unexpected_while("fetching all domains")?
.into_iter(); .into_iter();
for ManagedDomain { domain, .. } in domains { for ManagedDomain { domain, .. } in domains {
let (settings, https_cert, gemini_cert) = match self if let GetSettingsResult::External(config) = self
.get_settings(&domain) .get_settings(&domain)
.map_unexpected_while(|| format!("fetching settings for {domain}"))? .map_unexpected_while(|| format!("fetching settings for {domain}"))?
{ {
GetSettingsResult::Stored(settings) => (Some(settings), true, true), self.sync_external_domain(&domain, &config)
GetSettingsResult::Builtin(config) => (Some(config.settings), true, true),
// 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),
GetSettingsResult::Interface => (None, true, false),
// 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;
}
};
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,
)
})?;
}
if gemini_cert {
self.sync_domain_gemini_cert(&domain)
.map_unexpected_while(|| format!("syncing gemini cert for domain {domain}"))?;
}
if https_cert {
self.sync_domain_https_cert(&domain)
.await .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_origin(&domain, &settings.origin_descr)?;
self.sync_domain_gemini_cert(&domain) if self.can_sync_gemini_cert() {
.or_unexpected_while("syncing domain gemini cert")?; self.sync_domain_gemini_cert(&domain)
.or_unexpected_while("syncing domain gemini cert")?;
}
self.sync_domain_https_cert(&domain) if self.can_sync_https_cert() {
.await self.sync_domain_https_cert(&domain)
.or_unexpected_while("syncing domain https cert")?; .await
.or_unexpected_while("syncing domain https cert")?;
}
self.domain_store.set(&domain, &settings)?; self.domain_store.set(&domain, &settings)?;