This is an automated email from the ASF dual-hosted git repository.

duong pushed a commit to branch HDDS-7733-Symmetric-Tokens
in repository https://gitbox.apache.org/repos/asf/ozone.git

commit 07f0a19b2693cd5a3a869692abcfe5e8be7a2688
Author: tanvipenumudy <[email protected]>
AuthorDate: Thu Jun 8 10:50:05 2023 +0530

    HDDS-8677. Ozone admin OM CLI command for block tokens (#4760)
---
 .../symmetric/DefaultSecretKeySignerClient.java    |   8 +-
 .../security/symmetric/SecretKeySignerClient.java  |   3 +
 .../main/java/org/apache/hadoop/ozone/OmUtils.java |   1 +
 .../ozone/om/protocol/OzoneManagerProtocol.java    |   3 +
 ...OzoneManagerProtocolClientSideTranslatorPB.java |  17 ++
 .../hdds/scm/storage/TestContainerCommandsEC.java  |   2 +-
 .../org/apache/hadoop/ozone/TestBlockTokens.java   |   1 -
 .../apache/hadoop/ozone/TestBlockTokensCLI.java    | 237 +++++++++++++++++++++
 .../src/main/proto/OmClientProtocol.proto          |  11 +
 .../org/apache/hadoop/ozone/om/OzoneManager.java   |   6 +
 .../protocolPB/OzoneManagerRequestHandler.java     |  14 ++
 .../hadoop/ozone/admin/om/FetchKeySubCommand.java  |  56 +++++
 .../org/apache/hadoop/ozone/admin/om/OMAdmin.java  |   3 +-
 13 files changed, 358 insertions(+), 4 deletions(-)

diff --git 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/symmetric/DefaultSecretKeySignerClient.java
 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/symmetric/DefaultSecretKeySignerClient.java
index daabf74e37..d5e12689f9 100644
--- 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/symmetric/DefaultSecretKeySignerClient.java
+++ 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/symmetric/DefaultSecretKeySignerClient.java
@@ -60,6 +60,12 @@ public class DefaultSecretKeySignerClient implements 
SecretKeySignerClient {
         "SecretKey client must have been initialized already.");
   }
 
+  @Override
+  public void refetchSecretKey() {
+    // pass duration as ZERO to force a refresh.
+    checkAndRefresh(Duration.ZERO);
+  }
+
   @Override
   public void start(ConfigurationSource conf) throws IOException {
     final ManagedSecretKey initialKey =
@@ -103,7 +109,7 @@ public class DefaultSecretKeySignerClient implements 
SecretKeySignerClient {
         TimeUnit.MILLISECONDS);
   }
 
-  private void checkAndRefresh(Duration rotateDuration) {
+  private synchronized void checkAndRefresh(Duration rotateDuration) {
     ManagedSecretKey current = cache.get();
     Instant nextRotate = current.getCreationTime().plus(rotateDuration);
     // when the current key passes the rotation cycle, fetch the next one
diff --git 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/symmetric/SecretKeySignerClient.java
 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/symmetric/SecretKeySignerClient.java
index d05786db5c..0ae010545f 100644
--- 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/symmetric/SecretKeySignerClient.java
+++ 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/symmetric/SecretKeySignerClient.java
@@ -40,4 +40,7 @@ public interface SecretKeySignerClient {
    */
   default void stop() {
   }
+
+  default void refetchSecretKey() {
+  }
 }
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
index f366ae1875..03b2350143 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
@@ -258,6 +258,7 @@ public final class OmUtils {
     case TenantListUser:
     case ListSnapshot:
     case EchoRPC:
+    case RefetchSecretKey:
     case RangerBGSync:
       // RangerBGSync is a read operation in the sense that it doesn't directly
       // write to OM DB. And therefore it doesn't need a OMClientRequest.
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
index 1a9f3c6a0b..01d40de803 100644
--- 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
@@ -21,6 +21,7 @@ package org.apache.hadoop.ozone.om.protocol;
 import java.io.Closeable;
 import java.io.IOException;
 import java.util.List;
+import java.util.UUID;
 
 import org.apache.hadoop.hdds.scm.container.common.helpers.ExcludeList;
 import org.apache.hadoop.ozone.OzoneAcl;
@@ -1010,4 +1011,6 @@ public interface OzoneManagerProtocol
    */
   void setTimes(OmKeyArgs keyArgs, long mtime, long atime)
       throws IOException;
+
+  UUID refetchSecretKey() throws IOException;
 }
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
index 39206e5094..5423c504d5 100644
--- 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
@@ -22,6 +22,7 @@ import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 import java.util.stream.Collectors;
 
 import org.apache.commons.lang3.StringUtils;
@@ -155,6 +156,8 @@ import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Recover
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RecoverLeaseResponse;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RecoverTrashRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RecoverTrashResponse;
+import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RefetchSecretKeyRequest;
+import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RefetchSecretKeyResponse;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RemoveAclRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RemoveAclResponse;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RenameKeysArgs;
@@ -203,6 +206,7 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.protobuf.ByteString;
+import org.apache.hadoop.util.ProtobufUtils;
 
 import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes;
 import static 
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TOKEN_ERROR_OTHER;
@@ -1352,6 +1356,19 @@ public final class 
OzoneManagerProtocolClientSideTranslatorPB
     return S3VolumeContext.fromProtobuf(resp);
   }
 
+  @Override
+  public UUID refetchSecretKey() throws IOException {
+    final RefetchSecretKeyRequest.Builder requestBuilder =
+        RefetchSecretKeyRequest.newBuilder();
+    final OMRequest omRequest = createOMRequest(Type.RefetchSecretKey)
+        .setRefetchSecretKeyRequest(requestBuilder)
+        .build();
+    final OMResponse omResponse = submitRequest(omRequest);
+    final RefetchSecretKeyResponse resp =
+        handleError(omResponse).getRefetchSecretKeyResponse();
+    return ProtobufUtils.fromProtobuf(resp.getId());
+  }
+
   /**
    * Return the proxy object underlying this protocol translator.
    *
diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/storage/TestContainerCommandsEC.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/storage/TestContainerCommandsEC.java
index a2cbb598c6..d2e4f7a2ba 100644
--- 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/storage/TestContainerCommandsEC.java
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/storage/TestContainerCommandsEC.java
@@ -366,7 +366,7 @@ public class TestContainerCommandsEC {
     }
 
     try (ECReconstructionCoordinator coordinator =
-        new ECReconstructionCoordinator(config, certClient, null,
+        new ECReconstructionCoordinator(config, certClient, null, null,
             ECReconstructionMetrics.create())) {
 
       // Attempt to reconstruct the container.
diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestBlockTokens.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestBlockTokens.java
index a55e608fbf..6661c81b44 100644
--- 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestBlockTokens.java
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestBlockTokens.java
@@ -271,7 +271,6 @@ public final class TestBlockTokens {
     assertExceptionContains("Invalid token for user", ex);
   }
 
-
   private UUID extractSecretKeyId(OmKeyInfo keyInfo) throws IOException {
     OmKeyLocationInfo locationInfo =
         keyInfo.getKeyLocationVersions().get(0).getLocationList().get(0);
diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestBlockTokensCLI.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestBlockTokensCLI.java
new file mode 100644
index 0000000000..c53ef2ea18
--- /dev/null
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestBlockTokensCLI.java
@@ -0,0 +1,237 @@
+/*
+ * 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.ozone;
+
+import org.apache.hadoop.hdds.annotation.InterfaceAudience;
+import org.apache.hadoop.hdds.cli.OzoneAdmin;
+import org.apache.hadoop.hdds.conf.DefaultConfigManager;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.scm.ScmConfig;
+import org.apache.hadoop.hdds.scm.server.SCMHTTPServerConfig;
+import org.apache.hadoop.hdds.security.symmetric.SecretKeyManager;
+import org.apache.hadoop.hdds.utils.IOUtils;
+import org.apache.hadoop.minikdc.MiniKdc;
+import org.apache.hadoop.ozone.client.OzoneClient;
+import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.ozone.test.GenericTestUtils;
+import org.apache.ratis.util.ExitUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.Timeout;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.net.InetAddress;
+import java.util.Properties;
+import java.util.UUID;
+import java.util.concurrent.TimeoutException;
+
+import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION;
+import static 
org.apache.hadoop.hdds.DFSConfigKeysLegacy.DFS_DATANODE_KERBEROS_KEYTAB_FILE_KEY;
+import static 
org.apache.hadoop.hdds.DFSConfigKeysLegacy.DFS_DATANODE_KERBEROS_PRINCIPAL_KEY;
+import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_BLOCK_TOKEN_ENABLED;
+import static 
org.apache.hadoop.hdds.HddsConfigKeys.HDDS_CONTAINER_TOKEN_ENABLED;
+import static 
org.apache.hadoop.hdds.scm.ScmConfig.ConfigStrings.HDDS_SCM_KERBEROS_KEYTAB_FILE_KEY;
+import static 
org.apache.hadoop.hdds.scm.ScmConfig.ConfigStrings.HDDS_SCM_KERBEROS_PRINCIPAL_KEY;
+import static 
org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_CLIENT_ADDRESS_KEY;
+import static 
org.apache.hadoop.hdds.scm.server.SCMHTTPServerConfig.ConfigStrings.HDDS_SCM_HTTP_KERBEROS_KEYTAB_FILE_KEY;
+import static 
org.apache.hadoop.hdds.scm.server.SCMHTTPServerConfig.ConfigStrings.HDDS_SCM_HTTP_KERBEROS_PRINCIPAL_KEY;
+import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS;
+import static 
org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_SECURITY_ENABLED_KEY;
+import static 
org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_HTTP_KERBEROS_KEYTAB_FILE;
+import static 
org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_HTTP_KERBEROS_PRINCIPAL_KEY;
+import static 
org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_KERBEROS_KEYTAB_FILE_KEY;
+import static 
org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_KERBEROS_PRINCIPAL_KEY;
+import static 
org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod.KERBEROS;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Integration test class to verify block token CLI commands functionality in a
+ * secure cluster.
+ */
[email protected]
+public final class TestBlockTokensCLI {
+  private static final Logger LOG = LoggerFactory
+      .getLogger(TestBlockTokensCLI.class);
+
+  @Rule
+  public Timeout timeout = Timeout.seconds(180);
+
+  private static MiniKdc miniKdc;
+  private static OzoneAdmin ozoneAdmin;
+  private static OzoneConfiguration conf;
+  private static File workDir;
+  private static File ozoneKeytab;
+  private static File spnegoKeytab;
+  private static String host;
+  private static String clusterId;
+  private static String scmId;
+  private static String omServiceId;
+  private static String scmServiceId;
+  private static MiniOzoneHAClusterImpl cluster;
+  private static OzoneClient client;
+
+  @BeforeClass
+  public static void init() throws Exception {
+    conf = new OzoneConfiguration();
+    conf.set(OZONE_SCM_CLIENT_ADDRESS_KEY, "localhost");
+
+    ExitUtils.disableSystemExit();
+
+    workDir =
+        GenericTestUtils.getTestDir(TestBlockTokens.class.getSimpleName());
+    clusterId = UUID.randomUUID().toString();
+    scmId = UUID.randomUUID().toString();
+    omServiceId = "om-service-test";
+    scmServiceId = "scm-service-test";
+
+    startMiniKdc();
+    setSecureConfig();
+    createCredentialsInKDC();
+    setSecretKeysConfig();
+    startCluster();
+    client = cluster.newClient();
+    ozoneAdmin = new OzoneAdmin(conf);
+  }
+
+  @AfterClass
+  public static void stop() {
+    miniKdc.stop();
+    IOUtils.close(LOG, client);
+    if (cluster != null) {
+      cluster.stop();
+    }
+    DefaultConfigManager.clearDefaultConfigs();
+  }
+
+  private SecretKeyManager getScmSecretKeyManager() {
+    return cluster.getActiveSCM().getSecretKeyManager();
+  }
+
+  private static void setSecretKeysConfig() {
+    // enable tokens
+    conf.setBoolean(HDDS_BLOCK_TOKEN_ENABLED, true);
+    conf.setBoolean(HDDS_CONTAINER_TOKEN_ENABLED, true);
+  }
+
+  private static void createCredentialsInKDC() throws Exception {
+    ScmConfig scmConfig = conf.getObject(ScmConfig.class);
+    SCMHTTPServerConfig httpServerConfig =
+        conf.getObject(SCMHTTPServerConfig.class);
+    createPrincipal(ozoneKeytab, scmConfig.getKerberosPrincipal());
+    createPrincipal(spnegoKeytab, httpServerConfig.getKerberosPrincipal());
+  }
+
+  private static void createPrincipal(File keytab, String... principal)
+      throws Exception {
+    miniKdc.createPrincipal(keytab, principal);
+  }
+
+  private static void startMiniKdc() throws Exception {
+    Properties securityProperties = MiniKdc.createConf();
+    miniKdc = new MiniKdc(securityProperties, workDir);
+    miniKdc.start();
+  }
+
+  private static void setSecureConfig() throws IOException {
+    conf.setBoolean(OZONE_SECURITY_ENABLED_KEY, true);
+    host = InetAddress.getLocalHost().getCanonicalHostName()
+        .toLowerCase();
+
+    conf.set(HADOOP_SECURITY_AUTHENTICATION, KERBEROS.name());
+
+    String curUser = UserGroupInformation.getCurrentUser().getUserName();
+    conf.set(OZONE_ADMINISTRATORS, curUser);
+
+    String realm = miniKdc.getRealm();
+    String hostAndRealm = host + "@" + realm;
+    conf.set(HDDS_SCM_KERBEROS_PRINCIPAL_KEY, "scm/" + hostAndRealm);
+    conf.set(HDDS_SCM_HTTP_KERBEROS_PRINCIPAL_KEY, "HTTP_SCM/" + hostAndRealm);
+    conf.set(OZONE_OM_KERBEROS_PRINCIPAL_KEY, "scm/" + hostAndRealm);
+    conf.set(OZONE_OM_HTTP_KERBEROS_PRINCIPAL_KEY, "HTTP_OM/" + hostAndRealm);
+    conf.set(DFS_DATANODE_KERBEROS_PRINCIPAL_KEY, "scm/" + hostAndRealm);
+
+    ozoneKeytab = new File(workDir, "scm.keytab");
+    spnegoKeytab = new File(workDir, "http.keytab");
+
+    conf.set(HDDS_SCM_KERBEROS_KEYTAB_FILE_KEY,
+        ozoneKeytab.getAbsolutePath());
+    conf.set(HDDS_SCM_HTTP_KERBEROS_KEYTAB_FILE_KEY,
+        spnegoKeytab.getAbsolutePath());
+    conf.set(OZONE_OM_KERBEROS_KEYTAB_FILE_KEY,
+        ozoneKeytab.getAbsolutePath());
+    conf.set(OZONE_OM_HTTP_KERBEROS_KEYTAB_FILE,
+        spnegoKeytab.getAbsolutePath());
+    conf.set(DFS_DATANODE_KERBEROS_KEYTAB_FILE_KEY,
+        ozoneKeytab.getAbsolutePath());
+  }
+
+  @Test
+  public void testFetchKeyOMAdminCommand() throws UnsupportedEncodingException 
{
+    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+    PrintStream printStream = new PrintStream(outputStream, true, "UTF-8");
+    System.setOut(printStream);
+
+    String[] args =
+        new String[]{"om", "fetch-key", "--service-id=" + omServiceId};
+    ozoneAdmin.execute(args);
+
+    String actualOutput = outputStream.toString("UTF-8");
+    System.setOut(System.out);
+
+    String actualUUID = testFetchKeyOMAdminCommandUtil(actualOutput);
+    String expectedUUID =
+        getScmSecretKeyManager().getCurrentSecretKey().getId().toString();
+    assertEquals(expectedUUID, actualUUID);
+  }
+
+  private String testFetchKeyOMAdminCommandUtil(String output) {
+    // Extract the current secret key id from the output
+    String[] lines = output.split(System.lineSeparator());
+    for (String line : lines) {
+      if (line.startsWith("Current Secret Key ID: ")) {
+        return line.substring("Current Secret Key ID: ".length()).trim();
+      }
+    }
+    return null;
+  }
+
+  private static void startCluster()
+      throws IOException, TimeoutException, InterruptedException {
+    OzoneManager.setTestSecureOmFlag(true);
+    MiniOzoneCluster.Builder builder = MiniOzoneCluster.newHABuilder(conf)
+        .setClusterId(clusterId)
+        .setSCMServiceId(scmServiceId)
+        .setOMServiceId(omServiceId)
+        .setScmId(scmId)
+        .setNumDatanodes(3)
+        .setNumOfStorageContainerManagers(3)
+        .setNumOfOzoneManagers(1);
+
+    cluster = (MiniOzoneHAClusterImpl) builder.build();
+    cluster.waitForClusterToBeReady();
+  }
+}
diff --git 
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto 
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index 869713bf3c..1d9604b140 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -135,6 +135,7 @@ enum Type {
   SnapshotPurge = 118;
   RecoverLease = 119;
   SetTimes = 120;
+  RefetchSecretKey = 121;
 }
 
 message OMRequest {
@@ -254,6 +255,7 @@ message OMRequest {
 
   optional RecoverLeaseRequest              RecoverLeaseRequest            = 
119;
   optional SetTimesRequest                   SetTimesRequest               = 
120;
+  optional RefetchSecretKeyRequest          RefetchSecretKeyRequest        = 
121;
 }
 
 message OMResponse {
@@ -365,6 +367,7 @@ message OMResponse {
   optional SnapshotPurgeResponse              SnapshotPurgeResponse         = 
118;
   optional RecoverLeaseResponse              RecoverLeaseResponse          = 
119;
   optional SetTimesResponse                   SetTimesResponse             = 
120;
+  optional RefetchSecretKeyResponse          RefetchSecretKeyResponse      = 
121;
 }
 
 enum Status {
@@ -593,6 +596,14 @@ message SetVolumePropertyResponse {
     optional bool response = 1;
 }
 
+message RefetchSecretKeyRequest {
+
+}
+
+message RefetchSecretKeyResponse {
+    optional hdds.UUID id = 1;
+}
+
 /**
  * Checks if the user has specified permissions for the volume
  */
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
index 5f400ec1d4..623e9bbe2c 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
@@ -45,6 +45,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.Timer;
 import java.util.TimerTask;
+import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -1047,6 +1048,11 @@ public final class OzoneManager extends 
ServiceRuntimeInfoImpl
     }
   }
 
+  public UUID refetchSecretKey() {
+    secretKeyClient.refetchSecretKey();
+    return secretKeyClient.getCurrentSecretKey().getId();
+  }
+
   @VisibleForTesting
   public void startSecretManager() {
     try {
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
index 6dbe04e364..86a310b19a 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.UUID;
 import java.util.stream.Collectors;
 
 import com.google.protobuf.ByteString;
@@ -78,6 +79,7 @@ import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetFile
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetFileStatusResponse;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetKeyInfoRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetKeyInfoResponse;
+import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RefetchSecretKeyResponse;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.InfoBucketRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.InfoBucketResponse;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.InfoVolumeRequest;
@@ -137,6 +139,7 @@ import static 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.
 import static 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PartInfo;
 
 import org.apache.hadoop.ozone.upgrade.UpgradeFinalizer.StatusAndMessages;
+import org.apache.hadoop.util.ProtobufUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -311,6 +314,9 @@ public class OzoneManagerRequestHandler implements 
RequestHandler {
         responseBuilder.setTransferOmLeadershipResponse(transferLeadership(
             request.getTransferOmLeadershipRequest()));
         break;
+      case RefetchSecretKey:
+        responseBuilder.setRefetchSecretKeyResponse(refetchSecretKey());
+        break;
       default:
         responseBuilder.setSuccess(false);
         responseBuilder.setMessage("Unrecognized Command Type: " + cmdType);
@@ -946,6 +952,14 @@ public class OzoneManagerRequestHandler implements 
RequestHandler {
     return RangerBGSyncResponse.newBuilder().setRunSuccess(res).build();
   }
 
+  private RefetchSecretKeyResponse refetchSecretKey() {
+    UUID uuid = impl.refetchSecretKey();
+    RefetchSecretKeyResponse response =
+        RefetchSecretKeyResponse.newBuilder()
+            .setId(ProtobufUtils.toProtobuf(uuid)).build();
+    return response;
+  }
+
   @RequestFeatureValidator(
       conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
       processingPhase = RequestProcessingPhase.POST_PROCESS,
diff --git 
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/admin/om/FetchKeySubCommand.java
 
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/admin/om/FetchKeySubCommand.java
new file mode 100644
index 0000000000..ba0220292c
--- /dev/null
+++ 
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/admin/om/FetchKeySubCommand.java
@@ -0,0 +1,56 @@
+/**
+ * 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.ozone.admin.om;
+
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import org.apache.hadoop.hdds.cli.HddsVersionProvider;
+import org.apache.hadoop.ozone.om.protocol.OzoneManagerProtocol;
+import picocli.CommandLine;
+
+/**
+ * Handler of ozone admin om fetch-key command.
+ */
[email protected](
+    name = "fetch-key",
+    description = "CLI command to force OM to fetch the latest secret key " +
+        "from SCM.",
+    mixinStandardHelpOptions = true,
+    versionProvider = HddsVersionProvider.class
+)
+public class FetchKeySubCommand implements Callable<Void> {
+  @CommandLine.ParentCommand
+  private OMAdmin parent;
+
+  @CommandLine.Option(
+      names = {"-id", "--service-id"},
+      description = "Ozone Manager Service ID",
+      required = true
+  )
+  private String omServiceId;
+
+  @Override
+  public Void call() throws Exception {
+    try (OzoneManagerProtocol client = parent.createOmClient(omServiceId)) {
+      UUID uuid = client.refetchSecretKey();
+      System.out.println("Current Secret Key ID: " + uuid);
+    }
+    return null;
+  }
+}
+
diff --git 
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/admin/om/OMAdmin.java
 
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/admin/om/OMAdmin.java
index 9bb447669d..d3b36db6d8 100644
--- 
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/admin/om/OMAdmin.java
+++ 
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/admin/om/OMAdmin.java
@@ -59,7 +59,8 @@ import java.util.Collection;
         FinalizationStatusSubCommand.class,
         DecommissionOMSubcommand.class,
         UpdateRangerSubcommand.class,
-        TransferOmLeaderSubCommand.class
+        TransferOmLeaderSubCommand.class,
+        FetchKeySubCommand.class
     })
 @MetaInfServices(SubcommandWithParent.class)
 public class OMAdmin extends GenericCli implements SubcommandWithParent {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to