mirror of
https://github.com/rustfs/rustfs.git
synced 2026-09-02 02:08:41 +00:00
fix(kms): restore persisted configuration after restart (#6821)
* fix(kms): restore persisted configuration after restart * docs(kms): cover the reload route and startup load states The admin contract matrix pins every dynamic KMS route for the rc and console handoff, so the new POST /kms/reload needs a row there, and the reload response reuses the configure snapshot shape rather than adding a wire type. The observability runbook gains the operator procedure the reload exists for: telling a load_failed startup apart from a server that was never configured, and recovering without resubmitting secrets.
This commit is contained in:
@@ -259,6 +259,25 @@ impl KmsServiceManager {
|
||||
(state.status.clone(), config)
|
||||
}
|
||||
|
||||
/// Publish an initialization failure when no usable KMS state exists yet.
|
||||
///
|
||||
/// Startup configuration discovery happens outside this crate. Recording
|
||||
/// its failure here keeps status truthful without allowing a late failure
|
||||
/// to replace an already configured or running service.
|
||||
pub async fn record_initialization_error(&self, message: impl Into<String>) {
|
||||
let _guard = self.lifecycle_mutex.lock().await;
|
||||
let current = self.state.load_full();
|
||||
if current.config.is_some() || current.current_service.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.state.store(Arc::new(RuntimeState {
|
||||
config: None,
|
||||
status: KmsServiceStatus::Error(message.into()),
|
||||
current_service: None,
|
||||
}));
|
||||
}
|
||||
|
||||
fn redact_config(config: &mut KmsConfig) {
|
||||
if let BackendConfig::Static(static_config) = &mut config.backend_config {
|
||||
use zeroize::Zeroize;
|
||||
@@ -849,6 +868,39 @@ mod tests {
|
||||
assert!(manager.get_encryption_service().await.is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn initialization_error_is_visible_until_configuration_succeeds() {
|
||||
let manager = KmsServiceManager::new();
|
||||
|
||||
manager
|
||||
.record_initialization_error("persisted configuration could not be loaded")
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
manager.get_status().await,
|
||||
KmsServiceStatus::Error("persisted configuration could not be loaded".to_string())
|
||||
);
|
||||
assert!(manager.get_config().await.is_none());
|
||||
|
||||
manager
|
||||
.configure(static_config("key-a", 0x11))
|
||||
.await
|
||||
.expect("configure after startup failure");
|
||||
assert_eq!(manager.get_status().await, KmsServiceStatus::Configured);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn initialization_error_never_replaces_a_running_service() {
|
||||
let manager = KmsServiceManager::new();
|
||||
manager.configure(static_config("key-a", 0x11)).await.expect("configure");
|
||||
manager.start().await.expect("start");
|
||||
|
||||
manager.record_initialization_error("late startup failure").await;
|
||||
|
||||
assert_eq!(manager.get_status().await, KmsServiceStatus::Running);
|
||||
assert!(manager.get_encryption_service().await.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn configure_rejects_running_service_without_changing_snapshot() {
|
||||
let manager = KmsServiceManager::new();
|
||||
|
||||
Reference in New Issue
Block a user