diff --git a/src/daemon/ca/manager.rs b/src/daemon/ca/manager.rs index bda5b334..623ea096 100644 --- a/src/daemon/ca/manager.rs +++ b/src/daemon/ca/manager.rs @@ -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 diff --git a/src/daemon/ca/status.rs b/src/daemon/ca/status.rs index 81d83eb9..80e99005 100644 --- a/src/daemon/ca/status.rs +++ b/src/daemon/ca/status.rs @@ -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>> { + 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(()) diff --git a/src/daemon/krillserver.rs b/src/daemon/krillserver.rs index ab43a936..d5224602 100644 --- a/src/daemon/krillserver.rs +++ b/src/daemon/krillserver.rs @@ -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();