This is an automated email from the ASF dual-hosted git repository.
adoroszlai pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 5fe740c2c12 HDDS-16047. Certificate renewal stops permanently after an
unexpected failure (#10915)
5fe740c2c12 is described below
commit 5fe740c2c1208b4b292931043115d847df7f4007
Author: Sergey Soldatov <[email protected]>
AuthorDate: Wed Aug 5 23:56:37 2026 -0700
HDDS-16047. Certificate renewal stops permanently after an unexpected
failure (#10915)
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
.../client/DefaultCertificateClient.java | 11 +++++
.../client/TestDefaultCertificateClient.java | 50 ++++++++++++++++++++++
2 files changed, 61 insertions(+)
diff --git
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/DefaultCertificateClient.java
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/DefaultCertificateClient.java
index 22bdf80a7aa..c2183b21c0a 100644
---
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/DefaultCertificateClient.java
+++
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/DefaultCertificateClient.java
@@ -1395,6 +1395,17 @@ public CertificateRenewerService(boolean forceRenewal,
@Override
public void run() {
+ try {
+ renewCertificateIfNeeded();
+ } catch (RuntimeException e) {
+ // This task is scheduled at a fixed rate: an exception escaping it
cancels every future
+ // execution, and the component stops renewing its certificate without
any further notice.
+ getLogger().error("Certificate renewal for {} failed unexpectedly,
keeping the renewal "
+ + "schedule.", component, e);
+ }
+ }
+
+ private void renewCertificateIfNeeded() {
// Lock to protect the certificate renew process, to make sure there is
// only one renew process is ongoing at one time.
// Certificate renew steps:
diff --git
a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/client/TestDefaultCertificateClient.java
b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/client/TestDefaultCertificateClient.java
index ee2a52b2f63..2a9d4490295 100644
---
a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/client/TestDefaultCertificateClient.java
+++
b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/client/TestDefaultCertificateClient.java
@@ -25,6 +25,7 @@
import static
org.apache.hadoop.hdds.security.x509.certificate.client.CertificateClient.InitResponse.FAILURE;
import static
org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateCodec.getPEMEncodedString;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
@@ -49,6 +50,7 @@
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.RandomStringUtils;
@@ -586,4 +588,52 @@ protected String
signAndStoreCertificate(CertificateSignRequest request, Path ce
.count();
assertThat(monitorThreadCount).isEqualTo(0L);
}
+
+ /**
+ * A renewal that fails with an unchecked exception must not let it escape
the renewer task.
+ * The task is scheduled at a fixed rate, so an escaping exception cancels
every further
+ * execution and the component stops renewing its certificate until it is
restarted.
+ */
+ @Test
+ public void testRenewerContainsUnexpectedFailure(@TempDir File metaDir)
+ throws Exception {
+ OzoneConfiguration ozoneConf = new OzoneConfiguration();
+ ozoneConf.set(HDDS_METADATA_DIR_NAME, metaDir.getPath());
+ SecurityConfig conf = new SecurityConfig(ozoneConf);
+ String compName = "test-unexpected-failure";
+
+ CertificateCodec certCodec = new CertificateCodec(conf, compName);
+ X509Certificate cert = generateX509Cert(null);
+ certCodec.writeCertificate(cert);
+ String certId = cert.getSerialNumber().toString();
+
+ AtomicInteger attempts = new AtomicInteger();
+ DefaultCertificateClient client = new DefaultCertificateClient(
+ conf, null, mock(Logger.class), certId, compName, "", null, null) {
+
+ @Override
+ protected SCMGetCertResponseProto sign(CertificateSignRequest request) {
+ return null;
+ }
+
+ @Override
+ protected String signAndStoreCertificate(CertificateSignRequest request,
Path certificatePath, boolean renew) {
+ return null;
+ }
+
+ @Override
+ public String renewAndStoreKeyAndCertificate(boolean force) {
+ attempts.incrementAndGet();
+ throw new IllegalStateException("renewal failed unexpectedly");
+ }
+ };
+
+ try {
+ // Runs exactly what the scheduled task runs.
+ assertDoesNotThrow(client.new CertificateRenewerService(true, () -> {
})::run);
+ assertThat(attempts.get()).isPositive();
+ } finally {
+ client.close();
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]