This is an automated email from the ASF dual-hosted git repository.
sammichen 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 d12b34df43 HDDS-9046. [ozone-cert-rotation] cert clean is unable to
cleanup certificates LOCK error (#5157)
d12b34df43 is described below
commit d12b34df43a085a1f3f9b7b03b3f70e0b86ac075
Author: Galsza <[email protected]>
AuthorDate: Thu Aug 10 16:27:41 2023 +0200
HDDS-9046. [ozone-cert-rotation] cert clean is unable to cleanup
certificates LOCK error (#5157)
---
.../hadoop/hdds/protocol/SCMSecurityProtocol.java | 7 ++
.../SCMSecurityProtocolClientSideTranslatorPB.java | 14 ++-
.../certificate/authority/CertificateStore.java | 3 +-
.../x509/certificate/authority/MockCAStore.java | 4 +-
.../src/main/proto/ScmServerSecurityProtocol.proto | 12 +++
.../SCMSecurityProtocolServerSideTranslatorPB.java | 12 +++
.../hadoop/hdds/scm/server/SCMCertStore.java | 27 +++--
.../hdds/scm/server/SCMSecurityProtocolServer.java | 11 ++
.../hadoop/hdds/scm/cli/cert/CertCommands.java | 2 +-
.../hadoop/hdds/scm/cli/cert/CleanExpired.java | 117 ---------------------
...mmand.java => CleanExpiredCertsSubcommand.java} | 30 +++---
.../hadoop/hdds/scm/cli/cert/ListSubcommand.java | 21 +---
.../hdds/scm/cli/cert/ScmCertSubcommand.java | 30 ++++++
.../hadoop/hdds/scm/cli/cert/TestCleanExpired.java | 100 ------------------
.../cli/cert/TestCleanExpiredCertsSubcommand.java | 86 +++++++++++++++
15 files changed, 212 insertions(+), 264 deletions(-)
diff --git
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocol/SCMSecurityProtocol.java
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocol/SCMSecurityProtocol.java
index 1b88cee107..703deec76a 100644
---
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocol/SCMSecurityProtocol.java
+++
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocol/SCMSecurityProtocol.java
@@ -190,4 +190,11 @@ public interface SCMSecurityProtocol {
*/
List<String> getAllRootCaCertificates() throws IOException;
+ /**
+ * Remove all expired certificates from the SCM metadata store.
+ *
+ * @return list of the removed certificates
+ * @throws IOException
+ */
+ List<String> removeExpiredCertificates() throws IOException;
}
diff --git
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolClientSideTranslatorPB.java
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolClientSideTranslatorPB.java
index 4aa32f04cf..2ab5cc1c46 100644
---
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolClientSideTranslatorPB.java
+++
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolClientSideTranslatorPB.java
@@ -49,6 +49,7 @@ import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMRevoke
import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMSecurityRequest;
import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMSecurityRequest.Builder;
import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMSecurityResponse;
+import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMRemoveExpiredCertificatesRequestProto;
import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.Type;
import
org.apache.hadoop.hdds.scm.proxy.SCMSecurityProtocolFailoverProxyProvider;
import org.apache.hadoop.hdds.security.exception.SCMSecurityException;
@@ -87,8 +88,7 @@ public class SCMSecurityProtocolClientSideTranslatorPB
implements
/**
* Helper method to wrap the request and send the message.
*/
- private SCMSecurityResponse submitRequest(
- SCMSecurityProtocolProtos.Type type,
+ private SCMSecurityResponse submitRequest(Type type,
Consumer<Builder> builderConsumer) throws IOException {
final SCMSecurityResponse response;
try {
@@ -437,4 +437,14 @@ public class SCMSecurityProtocolClientSideTranslatorPB
implements
.getAllRootCaCertificatesResponseProto()
.getAllX509RootCaCertificatesList();
}
+
+ @Override
+ public List<String> removeExpiredCertificates() throws IOException {
+ SCMRemoveExpiredCertificatesRequestProto protoIns =
+ SCMRemoveExpiredCertificatesRequestProto.getDefaultInstance();
+ return submitRequest(Type.RemoveExpiredCertificates,
+ builder -> builder.setRemoveExpiredCertificatesRequestProto(protoIns))
+ .getRemoveExpiredCertificatesResponseProto()
+ .getRemovedExpiredCertificatesList();
+ }
}
diff --git
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/CertificateStore.java
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/CertificateStore.java
index e78206ca58..b5bfc54f33 100644
---
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/CertificateStore.java
+++
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/CertificateStore.java
@@ -109,10 +109,11 @@ public interface CertificateStore {
/**
* Deletes all non-revoked expired certificates from the store.
*
+ * @return The list of removed expired certificates
* @throws IOException - on failure
*/
@Replicate
- void removeAllExpiredCertificates() throws IOException;
+ List<X509Certificate> removeAllExpiredCertificates() throws IOException;
/**
* Retrieves a Certificate based on the Serial number of that certificate.
diff --git
a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/MockCAStore.java
b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/MockCAStore.java
index 650af970ca..9b3125c11b 100644
---
a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/MockCAStore.java
+++
b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/MockCAStore.java
@@ -29,6 +29,7 @@ import org.apache.hadoop.hdds.scm.metadata.SCMMetadataStore;
import java.io.IOException;
import java.math.BigInteger;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -72,7 +73,8 @@ public class MockCAStore implements CertificateStore {
}
@Override
- public void removeAllExpiredCertificates() {
+ public List<X509Certificate> removeAllExpiredCertificates() {
+ return new ArrayList<>();
}
@Override
diff --git
a/hadoop-hdds/interface-server/src/main/proto/ScmServerSecurityProtocol.proto
b/hadoop-hdds/interface-server/src/main/proto/ScmServerSecurityProtocol.proto
index dd3ef42308..adc2eee385 100644
---
a/hadoop-hdds/interface-server/src/main/proto/ScmServerSecurityProtocol.proto
+++
b/hadoop-hdds/interface-server/src/main/proto/ScmServerSecurityProtocol.proto
@@ -58,6 +58,8 @@ message SCMSecurityRequest {
optional SCMGetCertRequestProto getCertRequest = 13;
optional SCMGetAllRootCaCertificatesRequestProto
getAllRootCaCertificatesRequestProto = 14;
+ optional SCMRemoveExpiredCertificatesRequestProto
+ removeExpiredCertificatesRequestProto = 15;
}
message SCMSecurityResponse {
@@ -84,6 +86,8 @@ message SCMSecurityResponse {
optional SCMRevokeCertificatesResponseProto
revokeCertificatesResponseProto = 10;
optional SCMGetAllRootCaCertificatesResponseProto
allRootCaCertificatesResponseProto = 11;
+
+ optional SCMRemoveExpiredCertificatesResponseProto
removeExpiredCertificatesResponseProto = 12;
}
enum Type {
@@ -100,6 +104,7 @@ enum Type {
RevokeCertificates = 11;
GetCert = 12;
GetAllRootCaCertificates = 13;
+ RemoveExpiredCertificates = 14;
}
enum Status {
@@ -205,6 +210,10 @@ message SCMGetAllRootCaCertificatesResponseProto {
repeated string allX509RootCaCertificates = 1;
}
+message SCMRemoveExpiredCertificatesResponseProto {
+ repeated string removedExpiredCertificates = 1;
+}
+
message SCMGetRootCACertificateRequestProto {
}
@@ -258,6 +267,9 @@ message SCMRevokeCertificatesResponseProto {
optional int64 crlId = 1;
}
+message SCMRemoveExpiredCertificatesRequestProto {
+}
+
service SCMSecurityProtocolService {
rpc submitRequest (SCMSecurityRequest) returns (SCMSecurityResponse);
}
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/protocol/SCMSecurityProtocolServerSideTranslatorPB.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/protocol/SCMSecurityProtocolServerSideTranslatorPB.java
index aeb1fb6ea6..3fb32a2e26 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/protocol/SCMSecurityProtocolServerSideTranslatorPB.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/protocol/SCMSecurityProtocolServerSideTranslatorPB.java
@@ -35,6 +35,7 @@ import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetOMC
import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetSCMCertRequestProto;
import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMListCertificateRequestProto;
import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMListCertificateResponseProto;
+import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMRemoveExpiredCertificatesResponseProto;
import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMRevokeCertificatesRequestProto;
import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMRevokeCertificatesResponseProto;
import
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMSecurityRequest;
@@ -153,6 +154,11 @@ public class SCMSecurityProtocolServerSideTranslatorPB
return scmSecurityResponse
.setAllRootCaCertificatesResponseProto(getAllRootCa())
.build();
+ case RemoveExpiredCertificates:
+ return scmSecurityResponse
+ .setRemoveExpiredCertificatesResponseProto(
+ removeExpiredCertificates())
+ .build();
default:
throw new IllegalArgumentException(
@@ -414,4 +420,10 @@ public class SCMSecurityProtocolServerSideTranslatorPB
}
}
+ public SCMRemoveExpiredCertificatesResponseProto removeExpiredCertificates()
+ throws IOException {
+ return SCMRemoveExpiredCertificatesResponseProto.newBuilder()
+ .addAllRemovedExpiredCertificates(impl.removeExpiredCertificates())
+ .build();
+ }
}
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMCertStore.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMCertStore.java
index 539caf6d17..f2a753f9da 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMCertStore.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMCertStore.java
@@ -25,7 +25,6 @@ import java.math.BigInteger;
import java.security.cert.CRLException;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@@ -223,33 +222,41 @@ public final class SCMCertStore implements
CertificateStore {
}
@Override
- public void removeAllExpiredCertificates() throws IOException {
+ public List<X509Certificate> removeAllExpiredCertificates()
+ throws IOException {
+ List<X509Certificate> removedCerts = new ArrayList<>();
lock.lock();
try (BatchOperation batchOperation =
scmMetadataStore.getBatchHandler().initBatchOperation()) {
- addExpiredCertsToBeRemoved(batchOperation,
- scmMetadataStore.getValidCertsTable());
- addExpiredCertsToBeRemoved(batchOperation,
- scmMetadataStore.getValidSCMCertsTable());
+ removedCerts.addAll(addExpiredCertsToBeRemoved(batchOperation,
+ scmMetadataStore.getValidCertsTable()));
+ removedCerts.addAll(addExpiredCertsToBeRemoved(batchOperation,
+ scmMetadataStore.getValidSCMCertsTable()));
scmMetadataStore.getStore().commitBatchOperation(batchOperation);
} finally {
lock.unlock();
}
+ return removedCerts;
}
- private void addExpiredCertsToBeRemoved(BatchOperation batchOperation,
- Table<BigInteger, X509Certificate> certTable) throws IOException {
+ private List<X509Certificate> addExpiredCertsToBeRemoved(
+ BatchOperation batchOperation, Table<BigInteger,
+ X509Certificate> certTable) throws IOException {
+ List<X509Certificate> removedCerts = new ArrayList<>();
try (TableIterator<BigInteger, ? extends Table.KeyValue<BigInteger,
X509Certificate>> certsIterator = certTable.iterator()) {
- Instant now = Instant.now();
+ Date now = new Date();
while (certsIterator.hasNext()) {
Table.KeyValue<BigInteger, X509Certificate> certEntry =
certsIterator.next();
- if (certEntry.getValue().getNotAfter().toInstant().isBefore(now)) {
+ X509Certificate cert = certEntry.getValue();
+ if (cert.getNotAfter().before(now)) {
+ removedCerts.add(cert);
certTable.deleteWithBatch(batchOperation, certEntry.getKey());
}
}
}
+ return removedCerts;
}
@Override
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMSecurityProtocolServer.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMSecurityProtocolServer.java
index 180c4574a3..bec5a8dcff 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMSecurityProtocolServer.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMSecurityProtocolServer.java
@@ -508,6 +508,17 @@ public class SCMSecurityProtocolServer implements
SCMSecurityProtocol,
}
}
+ @Override
+ public List<String> removeExpiredCertificates() throws IOException {
+ storageContainerManager.checkAdminAccess(getRpcRemoteUser(), false);
+ List<String> pemEncodedCerts = new ArrayList<>();
+ for (X509Certificate cert : storageContainerManager.getCertificateStore()
+ .removeAllExpiredCertificates()) {
+ pemEncodedCerts.add(CertificateCodec.getPEMEncodedString(cert));
+ }
+ return pemEncodedCerts;
+ }
+
public SCMUpdateServiceGrpcServer getGrpcUpdateServer() {
return grpcUpdateServer;
}
diff --git
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/CertCommands.java
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/CertCommands.java
index 6b50cb451b..d466c9554a 100644
---
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/CertCommands.java
+++
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/CertCommands.java
@@ -40,7 +40,7 @@ import picocli.CommandLine.Spec;
subcommands = {
InfoSubcommand.class,
ListSubcommand.class,
- CleanExpired.class,
+ CleanExpiredCertsSubcommand.class,
})
@MetaInfServices(SubcommandWithParent.class)
diff --git
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/CleanExpired.java
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/CleanExpired.java
deleted file mode 100644
index b5a2ec523f..0000000000
---
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/CleanExpired.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.hadoop.hdds.scm.cli.cert;
-
-import com.google.common.annotations.VisibleForTesting;
-import org.apache.hadoop.hdds.cli.GenericParentCommand;
-import org.apache.hadoop.hdds.cli.HddsVersionProvider;
-import org.apache.hadoop.hdds.cli.SubcommandWithParent;
-import org.apache.hadoop.hdds.conf.OzoneConfiguration;
-import org.apache.hadoop.hdds.scm.metadata.SCMDBDefinition;
-import org.apache.hadoop.hdds.utils.HAUtils;
-import org.apache.hadoop.hdds.utils.db.DBStore;
-import org.apache.hadoop.hdds.utils.db.Table;
-import org.apache.hadoop.hdds.utils.db.TableIterator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import picocli.CommandLine;
-
-import java.io.File;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.security.cert.X509Certificate;
-import java.time.Instant;
-import java.util.concurrent.Callable;
-
-/**
- * This is the handler to clean SCM database from expired certificates.
- */
[email protected](
- name = "clean",
- description = "Clean expired certificates from the SCM metadata. " +
- "This command is only supported when the SCM is shutdown.",
- mixinStandardHelpOptions = true,
- versionProvider = HddsVersionProvider.class)
-public class CleanExpired implements Callable<Void>, SubcommandWithParent {
-
- private static final Logger LOG =
LoggerFactory.getLogger(CleanExpired.class);
-
- @CommandLine.Option(names = {"--db"},
- required = true,
- description = "Database file path")
- private String dbFilePath;
-
- @CommandLine.Spec
- private CommandLine.Model.CommandSpec spec;
-
- @Override
- public Void call() {
- GenericParentCommand parent =
- (GenericParentCommand) spec.root().userObject();
-
- OzoneConfiguration configuration = parent.createOzoneConfiguration();
-
- File db = new File(dbFilePath);
- if (!db.exists()) {
- LOG.error("DB path does not exist: " + dbFilePath);
- return null;
- }
- if (!db.isDirectory()) {
- LOG.error("DB path does not point to a directory: " + dbFilePath);
- return null;
- }
-
- try {
- DBStore dbStore = HAUtils.loadDB(
- configuration, db.getParentFile(),
- db.getName(), new SCMDBDefinition());
- removeExpiredCertificates(dbStore);
- } catch (Exception e) {
- LOG.error("Error trying to open file: " + dbFilePath +
- " failed with exception: " + e);
- }
- return null;
- }
-
- @VisibleForTesting
- void removeExpiredCertificates(DBStore dbStore) {
- try {
- Table<BigInteger, X509Certificate> certsTable =
- SCMDBDefinition.VALID_CERTS.getTable(dbStore);
- TableIterator<BigInteger, ? extends Table.KeyValue<BigInteger,
- X509Certificate>> tableIterator = certsTable.iterator();
- while (tableIterator.hasNext()) {
- Table.KeyValue<?, ?> certPair = tableIterator.next();
- X509Certificate certificate = (X509Certificate) certPair.getValue();
- if (Instant.now().isAfter(certificate.getNotAfter().toInstant())) {
- LOG.info("Certificate with id " + certPair.getKey() +
- " and value: " + certificate + "will be deleted");
- tableIterator.removeFromDB();
- }
- }
- } catch (IOException e) {
- LOG.error("Error when trying to open " +
- "certificate table from db: " + e);
- }
- }
-
- @Override
- public Class<?> getParentType() {
- return CertCommands.class;
- }
-}
diff --git
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/ScmCertSubcommand.java
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/CleanExpiredCertsSubcommand.java
similarity index 55%
copy from
hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/ScmCertSubcommand.java
copy to
hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/CleanExpiredCertsSubcommand.java
index 98bd76a284..cab7a29a4e 100644
---
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/ScmCertSubcommand.java
+++
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/CleanExpiredCertsSubcommand.java
@@ -17,28 +17,32 @@
*/
package org.apache.hadoop.hdds.scm.cli.cert;
+import org.apache.hadoop.hdds.cli.HddsVersionProvider;
import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol;
-import org.apache.hadoop.hdds.scm.cli.ScmOption;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import picocli.CommandLine;
import java.io.IOException;
-import java.util.concurrent.Callable;
+import java.util.List;
/**
- * Base class for admin commands that connect via SCM security client.
+ * This is the handler to clean SCM database from expired certificates.
*/
-public abstract class ScmCertSubcommand implements Callable<Void> {
[email protected](
+ name = "clean",
+ description = "Clean expired certificates from the SCM metadata.",
+ mixinStandardHelpOptions = true,
+ versionProvider = HddsVersionProvider.class)
+public class CleanExpiredCertsSubcommand extends ScmCertSubcommand {
- @CommandLine.Mixin
- private ScmOption scmOption;
-
- protected abstract void execute(SCMSecurityProtocol client)
- throws IOException;
+ private static final Logger LOG =
+ LoggerFactory.getLogger(CleanExpiredCertsSubcommand.class);
@Override
- public final Void call() throws Exception {
- SCMSecurityProtocol client = scmOption.createScmSecurityClient();
- execute(client);
- return null;
+ protected void execute(SCMSecurityProtocol client) throws IOException {
+ List<String> pemEncodedCerts = client.removeExpiredCertificates();
+ LOG.info("List of removed expired certificates:");
+ printCertList(LOG, pemEncodedCerts);
}
}
diff --git
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/ListSubcommand.java
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/ListSubcommand.java
index 857bf17cc8..c2e0bd7fad 100644
---
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/ListSubcommand.java
+++
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/ListSubcommand.java
@@ -81,9 +81,7 @@ public class ListSubcommand extends ScmCertSubcommand {
defaultValue = "false",
description = "Format output as JSON")
private boolean json;
-
- private static final String OUTPUT_FORMAT = "%-17s %-30s %-30s %-110s
%-110s";
-
+
private HddsProtos.NodeType parseCertRole(String r) {
if (r.equalsIgnoreCase("om")) {
return HddsProtos.NodeType.OM;
@@ -94,12 +92,6 @@ public class ListSubcommand extends ScmCertSubcommand {
}
}
- private void printCert(X509Certificate cert) {
- LOG.info(String.format(OUTPUT_FORMAT, cert.getSerialNumber(),
- cert.getNotBefore(), cert.getNotAfter(), cert.getSubjectDN(),
- cert.getIssuerDN()));
- }
-
@Override
protected void execute(SCMSecurityProtocol client) throws IOException {
boolean isRevoked = type.equalsIgnoreCase("revoked");
@@ -132,16 +124,7 @@ public class ListSubcommand extends ScmCertSubcommand {
LOG.info("Certificate list:(Type={}, BatchSize={}, CertCount={})",
type.toUpperCase(), count, certPemList.size());
- LOG.info(String.format(OUTPUT_FORMAT, "SerialNumber", "Valid From",
- "Expiry", "Subject", "Issuer"));
- for (String certPemStr : certPemList) {
- try {
- X509Certificate cert = CertificateCodec.getX509Certificate(certPemStr);
- printCert(cert);
- } catch (CertificateException ex) {
- LOG.error("Failed to parse certificate.");
- }
- }
+ printCertList(LOG, certPemList);
}
private static class BigIntJsonSerializer extends JsonSerializer<BigInteger>
{
diff --git
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/ScmCertSubcommand.java
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/ScmCertSubcommand.java
index 98bd76a284..d7ebb44e0f 100644
---
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/ScmCertSubcommand.java
+++
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/ScmCertSubcommand.java
@@ -19,9 +19,14 @@ package org.apache.hadoop.hdds.scm.cli.cert;
import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol;
import org.apache.hadoop.hdds.scm.cli.ScmOption;
+import org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateCodec;
+import org.slf4j.Logger;
import picocli.CommandLine;
import java.io.IOException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.List;
import java.util.concurrent.Callable;
/**
@@ -32,6 +37,31 @@ public abstract class ScmCertSubcommand implements
Callable<Void> {
@CommandLine.Mixin
private ScmOption scmOption;
+ private static final String OUTPUT_FORMAT = "%-17s %-30s %-30s %-110s
%-110s";
+
+ protected void printCertList(Logger log, List<String> pemEncodedCerts) {
+ if (pemEncodedCerts.isEmpty()) {
+ log.info("No certificates to list");
+ return;
+ }
+ log.info(String.format(OUTPUT_FORMAT, "SerialNumber", "Valid From",
+ "Expiry", "Subject", "Issuer"));
+ for (String certPemStr : pemEncodedCerts) {
+ try {
+ X509Certificate cert = CertificateCodec.getX509Certificate(certPemStr);
+ printCert(cert, log);
+ } catch (CertificateException e) {
+ log.error("Failed to parse certificate.", e);
+ }
+ }
+ }
+
+ protected void printCert(X509Certificate cert, Logger log) {
+ log.info(String.format(OUTPUT_FORMAT, cert.getSerialNumber(),
+ cert.getNotBefore(), cert.getNotAfter(), cert.getSubjectDN(),
+ cert.getIssuerDN()));
+ }
+
protected abstract void execute(SCMSecurityProtocol client)
throws IOException;
diff --git
a/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/cert/TestCleanExpired.java
b/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/cert/TestCleanExpired.java
deleted file mode 100644
index dc5705f670..0000000000
---
a/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/cert/TestCleanExpired.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.hadoop.hdds.scm.cli.cert;
-
-import org.apache.hadoop.hdds.scm.metadata.SCMDBDefinition;
-import org.apache.hadoop.hdds.utils.db.DBStore;
-import org.apache.hadoop.hdds.utils.db.Table;
-import org.apache.hadoop.hdds.utils.db.TableIterator;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.security.cert.X509Certificate;
-import java.sql.Date;
-import java.time.Duration;
-import java.time.Instant;
-
-/**
- * Test the cleaning tool for expired certificates.
- */
-public class TestCleanExpired {
-
- private CleanExpired cmd;
- private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
- private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
- private final PrintStream originalOut = System.out;
- private final PrintStream originalErr = System.err;
- private static final String DEFAULT_ENCODING = StandardCharsets.UTF_8.name();
-
- @Mock
- private DBStore dbStore;
- @Mock
- private Table<BigInteger, X509Certificate> mockTable;
- @Mock
- private TableIterator iterator;
- @Mock
- private Table.KeyValue<BigInteger, X509Certificate> kv;
- @Mock
- private Table.KeyValue<BigInteger, X509Certificate> kv2;
- @Mock
- private X509Certificate nonExpiredCert;
- @Mock
- private X509Certificate expiredCert;
-
- @BeforeEach
- public void setup() throws IOException {
- MockitoAnnotations.initMocks(this);
- cmd = new CleanExpired();
- System.setOut(new PrintStream(outContent, false, DEFAULT_ENCODING));
- System.setErr(new PrintStream(errContent, false, DEFAULT_ENCODING));
- }
-
- @AfterEach
- public void tearDown() {
- System.setOut(originalOut);
- System.setErr(originalErr);
- }
-
- @Test
- public void testOnlyExpiredCertsRemoved()
- throws Exception {
- Mockito.when(SCMDBDefinition.VALID_CERTS.getTable(dbStore))
- .thenReturn(mockTable);
- Mockito.when(mockTable.iterator()).thenReturn(iterator);
- Mockito.when(nonExpiredCert.getNotAfter())
- .thenReturn(Date.from(Instant.now().plus(Duration.ofDays(365))));
- Mockito.when(expiredCert.getNotAfter())
- .thenReturn(Date.from(Instant.now().minus(Duration.ofDays(365))));
- Mockito.when(iterator.hasNext()).thenReturn(true, true, false);
- Mockito.when(iterator.next()).thenReturn(kv, kv2);
- Mockito.when(kv.getValue()).thenReturn(expiredCert);
- Mockito.when(kv2.getValue()).thenReturn(nonExpiredCert);
-
- cmd.removeExpiredCertificates(dbStore);
- Mockito.verify(iterator, Mockito.times(1)).removeFromDB();
- }
-}
diff --git
a/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/cert/TestCleanExpiredCertsSubcommand.java
b/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/cert/TestCleanExpiredCertsSubcommand.java
new file mode 100644
index 0000000000..231d44542a
--- /dev/null
+++
b/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/cert/TestCleanExpiredCertsSubcommand.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.hadoop.hdds.scm.cli.cert;
+
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol;
+
+import static
org.apache.hadoop.hdds.security.x509.CertificateTestUtils.createSelfSignedCert;
+
+import org.apache.hadoop.hdds.security.x509.CertificateTestUtils;
+import org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateCodec;
+import org.hamcrest.core.StringContains;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyPair;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class TestCleanExpiredCertsSubcommand {
+
+ private SCMSecurityProtocol scmSecurityProtocolMock;
+ private CleanExpiredCertsSubcommand cmd;
+ private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
+ private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
+ private final PrintStream originalOut = System.out;
+ private final PrintStream originalErr = System.err;
+ private static final String DEFAULT_ENCODING = StandardCharsets.UTF_8.name();
+ private static final String OUTPUT_FORMAT = "%-17s %-30s %-30s %-110s
%-110s";
+
+ @BeforeEach
+ public void setup() throws IOException {
+ scmSecurityProtocolMock = mock(SCMSecurityProtocol.class);
+ System.setOut(new PrintStream(outContent, false, DEFAULT_ENCODING));
+ System.setErr(new PrintStream(errContent, false, DEFAULT_ENCODING));
+ }
+
+ @AfterEach
+ public void tearDown() {
+ System.setOut(originalOut);
+ System.setErr(originalErr);
+ }
+
+ @Test
+ public void testCleaningOneCertificate() throws Exception {
+ cmd = new CleanExpiredCertsSubcommand();
+ KeyPair keyPair = CertificateTestUtils.aKeyPair(new OzoneConfiguration());
+ X509Certificate cert = createSelfSignedCert(keyPair, "aCert");
+ ArrayList<String> certPemList = new ArrayList<>();
+ certPemList.add(CertificateCodec.getPEMEncodedString(cert));
+ when(scmSecurityProtocolMock.removeExpiredCertificates())
+ .thenReturn(certPemList);
+ cmd.execute(scmSecurityProtocolMock);
+ String cliOutPut = outContent.toString(DEFAULT_ENCODING);
+ String certInfo = String.format(OUTPUT_FORMAT, cert.getSerialNumber(),
+ cert.getNotBefore(), cert.getNotAfter(), cert.getSubjectDN(),
+ cert.getIssuerDN());
+ assertThat(cliOutPut, new StringContains(true, certInfo));
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]