Return all domains from all_domains

This fixes an issue where the domain manager sync job wouldn't have
synced private builtin domains ever.
This commit is contained in:
Brian Picciano 2023-08-03 10:29:57 +02:00
parent 7f8e40c19f
commit e67cd6725a
3 changed files with 93 additions and 41 deletions

View File

@ -139,7 +139,9 @@ impl From<store::SetError> for SyncWithSettingsError {
pub type GetAcmeHttp01ChallengeKeyError = acme::manager::GetHttp01ChallengeKeyError; pub type GetAcmeHttp01ChallengeKeyError = acme::manager::GetHttp01ChallengeKeyError;
//#[mockall::automock] pub type StoredDomain = domain::store::StoredDomain;
#[mockall::automock]
pub trait Manager: Sync + Send { pub trait Manager: Sync + Send {
fn get_settings(&self, domain: &domain::Name) -> Result<GetSettingsResult, GetSettingsError>; fn get_settings(&self, domain: &domain::Name) -> Result<GetSettingsResult, GetSettingsError>;
@ -165,7 +167,7 @@ pub trait Manager: Sync + Send {
domain: &domain::Name, domain: &domain::Name,
) -> unexpected::Result<Option<String>>; ) -> unexpected::Result<Option<String>>;
fn all_domains(&self) -> Result<Vec<domain::Name>, unexpected::Error>; fn all_domains(&self) -> Result<Vec<StoredDomain>, unexpected::Error>;
} }
pub struct ManagerImpl { pub struct ManagerImpl {
@ -247,13 +249,13 @@ impl ManagerImpl {
} }
.into_iter(); .into_iter();
for domain in domains { for StoredDomain { domain, .. } in domains {
log::info!("Syncing domain {}", &domain); log::info!("Syncing domain {}", &domain);
let get_res = match self.domain_store.get(&domain) { let get_res = match self.domain_store.get(&domain) {
Ok(get_res) => get_res, Ok(get_res) => get_res,
Err(err) => { Err(err) => {
log::error!("Error syncing {domain}: {err}"); log::error!("Failed to fetch settings for domain {domain}: {err}");
return; return;
} }
}; };
@ -334,7 +336,7 @@ impl Manager for ManagerImpl {
self.domain_checker.get_challenge_token(domain) self.domain_checker.get_challenge_token(domain)
} }
fn all_domains(&self) -> Result<Vec<domain::Name>, unexpected::Error> { fn all_domains(&self) -> Result<Vec<StoredDomain>, unexpected::Error> {
self.domain_store.all_domains() self.domain_store.all_domains()
} }
} }

View File

@ -1,15 +1,21 @@
use std::{collections, fs, io, path, str::FromStr}; use std::{collections, fs, io, path};
use crate::domain; use crate::domain;
use crate::error::unexpected::{self, Intoable, Mappable}; use crate::error::unexpected::{self, Intoable, Mappable};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct GetResult { /// Extra information about a domain which is related to how its stored.
pub settings: domain::Settings, pub struct Metadata {
pub builtin: bool, pub builtin: bool,
pub public: bool, pub public: bool,
} }
#[derive(Debug, PartialEq)]
pub struct GetResult {
pub settings: domain::Settings,
pub metadata: Metadata,
}
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum GetError { pub enum GetError {
#[error("not found")] #[error("not found")]
@ -28,11 +34,16 @@ pub enum SetError {
Unexpected(#[from] unexpected::Error), Unexpected(#[from] unexpected::Error),
} }
pub struct StoredDomain {
pub domain: domain::Name,
pub metadata: Metadata,
}
#[mockall::automock] #[mockall::automock]
pub trait Store { pub trait Store {
fn get(&self, domain: &domain::Name) -> Result<GetResult, GetError>; fn get(&self, domain: &domain::Name) -> Result<GetResult, GetError>;
fn set(&self, domain: &domain::Name, settings: &domain::Settings) -> Result<(), SetError>; fn set(&self, domain: &domain::Name, settings: &domain::Settings) -> Result<(), SetError>;
fn all_domains(&self) -> Result<Vec<domain::Name>, unexpected::Error>; fn all_domains(&self) -> Result<Vec<StoredDomain>, unexpected::Error>;
} }
pub struct FSStore { pub struct FSStore {
@ -71,8 +82,10 @@ impl Store for FSStore {
Ok(GetResult { Ok(GetResult {
settings, settings,
public: true, metadata: Metadata {
builtin: false, public: true,
builtin: false,
},
}) })
} }
@ -91,18 +104,23 @@ impl Store for FSStore {
Ok(()) Ok(())
} }
fn all_domains(&self) -> Result<Vec<domain::Name>, unexpected::Error> { fn all_domains(&self) -> Result<Vec<StoredDomain>, unexpected::Error> {
fs::read_dir(&self.dir_path) fs::read_dir(&self.dir_path)
.or_unexpected()? .or_unexpected()?
.map( .map(
|dir_entry_res: io::Result<fs::DirEntry>| -> Result<domain::Name, unexpected::Error> { |dir_entry_res: io::Result<fs::DirEntry>| -> Result<StoredDomain, unexpected::Error> {
let domain = dir_entry_res.or_unexpected()?.file_name(); let domain = dir_entry_res.or_unexpected()?.file_name();
let domain = domain.to_str().ok_or(unexpected::Error::from( let domain = domain.to_str().ok_or(unexpected::Error::from(
"couldn't convert os string to &str", "couldn't convert os string to &str",
))?; ))?;
domain::Name::from_str(domain) Ok(StoredDomain{
.map_unexpected_while(|| format!("parsing {domain} as domain name")) domain: domain.parse().map_unexpected_while(|| format!("parsing {domain} as domain name"))?,
metadata: Metadata{
public: true,
builtin: false,
},
})
}, },
) )
.try_collect() .try_collect()
@ -131,8 +149,10 @@ impl<S: Store> Store for StoreWithBuiltin<S> {
if let Some(domain) = self.domains.get(domain) { if let Some(domain) = self.domains.get(domain) {
return Ok(GetResult { return Ok(GetResult {
settings: domain.settings.clone(), settings: domain.settings.clone(),
public: domain.public, metadata: Metadata {
builtin: true, public: domain.public,
builtin: true,
},
}); });
} }
self.inner.get(domain) self.inner.get(domain)
@ -145,13 +165,18 @@ impl<S: Store> Store for StoreWithBuiltin<S> {
self.inner.set(domain, settings) self.inner.set(domain, settings)
} }
fn all_domains(&self) -> Result<Vec<domain::Name>, unexpected::Error> { fn all_domains(&self) -> Result<Vec<StoredDomain>, unexpected::Error> {
let inner_domains = self.inner.all_domains()?; let inner_domains = self.inner.all_domains()?;
let mut domains: Vec<domain::Name> = self let mut domains: Vec<StoredDomain> = self
.domains .domains
.iter() .iter()
.filter(|(_, v)| v.public) .map(|(domain, v)| StoredDomain {
.map(|(k, _)| k.clone()) domain: domain.clone(),
metadata: Metadata {
public: v.public,
builtin: true,
},
})
.collect(); .collect();
domains.extend(inner_domains); domains.extend(inner_domains);
Ok(domains) Ok(domains)
@ -193,8 +218,10 @@ mod tests {
assert_eq!( assert_eq!(
GetResult { GetResult {
settings, settings,
public: true, metadata: Metadata {
builtin: false, public: true,
builtin: false,
},
}, },
store.get(&domain).expect("settings retrieved") store.get(&domain).expect("settings retrieved")
); );
@ -211,8 +238,10 @@ mod tests {
assert_eq!( assert_eq!(
GetResult { GetResult {
settings: new_settings, settings: new_settings,
public: true, metadata: Metadata {
builtin: false, public: true,
builtin: false,
},
}, },
store.get(&domain).expect("settings retrieved") store.get(&domain).expect("settings retrieved")
); );

View File

@ -210,6 +210,8 @@ impl Service {
} }
fn domain(&self, args: DomainArgs) -> Response<Body> { fn domain(&self, args: DomainArgs) -> Response<Body> {
use domain::store::Metadata;
#[derive(Serialize)] #[derive(Serialize)]
struct Data { struct Data {
domain: domain::Name, domain: domain::Name,
@ -217,24 +219,42 @@ impl Service {
} }
let settings = match self.domain_manager.get_settings(&args.domain) { let settings = match self.domain_manager.get_settings(&args.domain) {
Ok(domain::manager::GetSettingsResult {
metadata:
Metadata {
public: false,
builtin: _,
},
..
}) => None,
Ok(domain::manager::GetSettingsResult { Ok(domain::manager::GetSettingsResult {
settings, settings,
public, metadata:
builtin, Metadata {
}) => match (public, builtin) { public: true,
(false, _) => None, builtin: false,
(true, false) => Some(settings), },
(true, true) => { }) => Some(settings),
return self.render_error_page(
403, Ok(domain::manager::GetSettingsResult {
format!( metadata:
"Settings for domain {} cannot be viewed or modified", Metadata {
args.domain public: true,
) builtin: true,
.as_str(), },
..
}) => {
return self.render_error_page(
403,
format!(
"Settings for domain {} cannot be viewed or modified",
args.domain
) )
} .as_str(),
}, )
}
Err(domain::manager::GetSettingsError::NotFound) => None, Err(domain::manager::GetSettingsError::NotFound) => None,
Err(domain::manager::GetSettingsError::Unexpected(e)) => { Err(domain::manager::GetSettingsError::Unexpected(e)) => {
return self.internal_error( return self.internal_error(
@ -367,7 +387,8 @@ impl Service {
let mut domains: Vec<String> = domains let mut domains: Vec<String> = domains
.into_iter() .into_iter()
.map(|domain| domain.as_str().to_string()) .filter(|d| d.metadata.public)
.map(|d| d.domain.as_str().to_string())
.collect(); .collect();
domains.sort(); domains.sort();