diff --git a/run_seed.sh b/run_seed.sh index 2053b3d2..4b7b62b5 100755 --- a/run_seed.sh +++ b/run_seed.sh @@ -95,6 +95,7 @@ else --cluster-rename new-name:foo.com:some-random-infra-id \ --hostname test.hostname \ --ip 192.168.126.99 \ + --etcd-defrag \ --install-config 'additionalTrustBundlePolicy: Proxyonly apiVersion: v1 baseDomain: ibo0.redhat.com diff --git a/src/config.rs b/src/config.rs index 74051f12..6f406a23 100644 --- a/src/config.rs +++ b/src/config.rs @@ -65,6 +65,7 @@ pub(crate) struct RecertConfig { pub(crate) regenerate_server_ssh_keys: Option, pub(crate) summary_file: Option, pub(crate) summary_file_clean: Option, + pub(crate) etcd_defrag: bool, #[serde(serialize_with = "config_file_raw_optionally_redacted")] pub(crate) config_file_raw: Option, @@ -130,6 +131,7 @@ impl RecertConfig { Ok(RecertConfig { dry_run: true, etcd_endpoint: None, + etcd_defrag: false, crypto_customizations: CryptoCustomizations { dirs: vec![], files: vec![], @@ -258,6 +260,11 @@ impl RecertConfig { .unwrap_or(Value::Bool(false)) .as_bool() .context("dry_run must be a boolean")?; + let etcd_defrag = value + .remove("etcd_defrag") + .unwrap_or(Value::Bool(false)) + .as_bool() + .context("etcd_defrag must be a boolean")?; let etcd_endpoint = match value.remove("etcd_endpoint") { Some(value) => Some(value.as_str().context("etcd_endpoint must be a string")?.to_string()), None => None, @@ -328,6 +335,7 @@ impl RecertConfig { cli_raw: None, config_file_raw: Some(String::from_utf8_lossy(config_bytes).to_string()), postprocess_only, + etcd_defrag, }; ensure!( @@ -344,6 +352,10 @@ impl RecertConfig { !(recert_config.dry_run && recert_config.crypto_customizations.extend_expiration), "dry_run and extend_expiration are mutually exclusive" ); + ensure!( + !(recert_config.dry_run && recert_config.etcd_defrag), + "dry_run and etcd_defrag are mutually exclusive" + ); Ok(recert_config) } @@ -351,6 +363,7 @@ impl RecertConfig { pub(crate) fn parse_from_cli(cli: Cli) -> Result { Ok(Self { dry_run: cli.dry_run, + etcd_defrag: cli.etcd_defrag, postprocess_only: cli.postprocess_only, etcd_endpoint: cli.etcd_endpoint, crypto_customizations: CryptoCustomizations { diff --git a/src/config/cli.rs b/src/config/cli.rs index 800079b0..916dd02b 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -192,4 +192,8 @@ pub(crate) struct Cli { /// those intentionally expired dates. #[clap(long, groups = &["dry", "expiration"])] pub(crate) force_expire: bool, + + /// Run etcd defragment command after recertification + #[clap(long, group = "dry")] + pub(crate) etcd_defrag: bool, } diff --git a/src/k8s_etcd.rs b/src/k8s_etcd.rs index e8255856..ddac5b24 100644 --- a/src/k8s_etcd.rs +++ b/src/k8s_etcd.rs @@ -206,6 +206,12 @@ impl InMemoryK8sEtcd { ); Ok(()) } + + pub(crate) async fn defragment(&self) -> Result<()> { + let etcd_client = self.etcd_client.as_ref().context("etcd client not configured")?; + etcd_client.maintenance_client().defragment().await.context("defragment etcd")?; + Ok(()) + } } fn is_too_many_requests_error(delete_response: &std::prelude::v1::Result) -> bool { diff --git a/src/recert.rs b/src/recert.rs index 6fc193fc..3f17c509 100644 --- a/src/recert.rs +++ b/src/recert.rs @@ -36,6 +36,7 @@ pub(crate) async fn run(recert_config: &RecertConfig, cluster_crypto: &mut Clust &recert_config.cluster_customizations, recert_config.regenerate_server_ssh_keys.as_deref(), recert_config.dry_run, + recert_config.etcd_defrag, ) .await .context("finalizing")?; @@ -115,6 +116,7 @@ async fn finalize( cluster_customizations: &ClusterCustomizations, regenerate_server_ssh_keys: Option<&Path>, dry_run: bool, + etcd_defrag: bool, ) -> Result { log::info!("Committing cryptographic objects to etcd and disk"); @@ -156,6 +158,12 @@ async fn finalize( .context("commiting etcd cache to actual etcd")?; } + // in case etcd maintenance flag was set we gonna run it after finishing all etcd work + if etcd_defrag { + log::info!("Defragmenting etcd"); + in_memory_etcd_client.defragment().await.context("defragmenting etcd")?; + } + let commit_to_actual_etcd_run_time = RunTime::since_start(start); Ok(FinalizeTiming {