Synchronize CaStatus and CAs on startup (#662)

This commit is contained in:
Tim Bruijnzeels
2021-09-16 10:49:24 +02:00
parent 8af6398b47
commit af99fcfda3
3 changed files with 78 additions and 5 deletions
+55
View File
@@ -387,6 +387,61 @@ impl CaManager {
Ok(())
}
/// Re-synchronize the CAs and CaStatus
///
/// - remove any surplus CA status entries
/// - create missing CA status entries
/// - check children for existing CAs:
/// - remove surplus from status
/// - add missing
pub async fn resync_ca_statuses(&self) -> KrillResult<()> {
let cas = self.ca_store.list()?;
let mut ca_statuses = self.status_store.lock().await.cas().await?;
// loop over existing CAs and get their status
for ca_handle in cas {
let ca = self.get_ca(&ca_handle).await?;
let status = match ca_statuses.remove(&ca_handle) {
Some(status) => status,
None => {
// Getting a missing status will ensure that a new empty status is generated.
self.status_store.lock().await.get_ca_status(&ca_handle).await?
}
};
let mut status_children = status.children().clone();
// add default status for missing children
for child in ca.children() {
if status_children.remove(child).is_none() {
self.status_store
.lock()
.await
.set_child_default_if_missing(&ca_handle, child)
.await?;
}
}
// remove surplus children status
for surplus_child in status_children.keys() {
self.status_store
.lock()
.await
.remove_child(&ca_handle, surplus_child)
.await?;
}
}
// remove the status for any left-over CAs with status
for surplus_ca in ca_statuses.keys() {
info!("Removing the cached status for a removed CA: {}", surplus_ca);
self.status_store.lock().await.remove_ca(surplus_ca).await?;
}
Ok(())
}
}
/// # CA History
+21 -5
View File
@@ -1,4 +1,4 @@
use std::{collections::HashMap, path::Path, sync::Arc};
use std::{collections::HashMap, path::Path, str::FromStr, sync::Arc};
use tokio::sync::RwLock;
@@ -96,6 +96,19 @@ impl StatusStore {
Ok(status)
}
/// Returns all CAs for which a status exists
pub async fn cas(&self) -> KrillResult<HashMap<Handle, Arc<CaStatus>>> {
let mut cas = HashMap::new();
for scope in self.store.scopes()? {
if let Ok(ca) = Handle::from_str(&scope) {
let status = self.get_ca_status(&ca).await?;
cas.insert(ca, status);
}
}
Ok(cas)
}
pub async fn set_parent_failure(
&self,
ca: &Handle,
@@ -177,6 +190,11 @@ impl StatusStore {
.await
}
/// Adds a child with default status values if the child is missing
pub async fn set_child_default_if_missing(&self, ca: &Handle, child: &ChildHandle) -> KrillResult<()> {
self.update_ca_child_status(ca, child, |_status| {}).await
}
/// Remove a CA from the saved status
/// This should be called when the CA is removed from Krill, but note that if this is done for a CA which still exists
/// a new empty default status will be re-generated when it is accessed for this CA.
@@ -186,11 +204,9 @@ impl StatusStore {
if !cache.contains_key(ca) {
Ok(()) // idempotent
} else {
let key = Self::status_key(ca);
// will fail if there is an I/O error, but come back ok if the key had been dropped already.
self.store.drop_key(&key)?;
let scope = ca.as_str();
self.store.drop_scope(scope)?; // idem potent; won't do anything if the scope does not exist.
cache.remove(ca);
Ok(())
+2
View File
@@ -141,6 +141,8 @@ impl KrillServer {
let ca_manager = Arc::new(ca::CaManager::build(config.clone(), event_queue.clone(), signer).await?);
ca_manager.resync_ca_statuses().await?;
if let Some(testbed) = config.testbed() {
let uris = testbed.publication_server_uris();