This is an automated email from the ASF dual-hosted git repository.
pifta 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 2ac31e1bcb HDDS-7398. Tool to remove old certs from the scm db (#3972)
2ac31e1bcb is described below
commit 2ac31e1bcb6ad585774436e6967f277e09170964
Author: Galsza <[email protected]>
AuthorDate: Mon Dec 19 11:47:31 2022 +0100
HDDS-7398. Tool to remove old certs from the scm db (#3972)
---
hadoop-hdds/tools/pom.xml | 4 +
.../hadoop/hdds/scm/cli/cert/CertCommands.java | 1 +
.../hadoop/hdds/scm/cli/cert/CleanExpired.java | 117 +++++++++++++++++++++
.../hadoop/hdds/scm/cli/cert/TestCleanExpired.java | 100 ++++++++++++++++++
4 files changed, 222 insertions(+)
diff --git a/hadoop-hdds/tools/pom.xml b/hadoop-hdds/tools/pom.xml
index 29cbeaf0e1..43e8ef297e 100644
--- a/hadoop-hdds/tools/pom.xml
+++ b/hadoop-hdds/tools/pom.xml
@@ -99,5 +99,9 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
<artifactId>slf4j-reload4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.ozone</groupId>
+ <artifactId>hdds-server-scm</artifactId>
+ </dependency>
</dependencies>
</project>
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 21ba03599e..6b50cb451b 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,6 +40,7 @@ import picocli.CommandLine.Spec;
subcommands = {
InfoSubcommand.class,
ListSubcommand.class,
+ CleanExpired.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
new file mode 100644
index 0000000000..b5a2ec523f
--- /dev/null
+++
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/cert/CleanExpired.java
@@ -0,0 +1,117 @@
+/*
+ * 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/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
new file mode 100644
index 0000000000..b169e6359d
--- /dev/null
+++
b/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/cert/TestCleanExpired.java
@@ -0,0 +1,100 @@
+/*
+ * 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();
+ }
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]