This is an automated email from the ASF dual-hosted git repository.
ivandika3 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 521e046314b HDDS-11839. Accept SCM node id in ozone admin scm transfer
(#11022)
521e046314b is described below
commit 521e046314bc3bef2e66c5c58e0f3d9a8c604fe8
Author: rjgoyln <[email protected]>
AuthorDate: Thu Aug 27 14:22:56 2026 +0800
HDDS-11839. Accept SCM node id in ozone admin scm transfer (#11022)
---
hadoop-hdds/docs/content/feature/SCM-HA.md | 3 +-
.../hadoop/hdds/scm/ha/SCMHANodeDetails.java | 7 +++
.../hdds/scm/server/SCMClientProtocolServer.java | 24 ++++++++-
.../hdds/scm/server/StorageContainerManager.java | 5 +-
.../admin/scm/TransferScmLeaderSubCommand.java | 2 +-
.../ozone/shell/TestTransferLeadershipShell.java | 60 +++++++++++++++++-----
6 files changed, 81 insertions(+), 20 deletions(-)
diff --git a/hadoop-hdds/docs/content/feature/SCM-HA.md
b/hadoop-hdds/docs/content/feature/SCM-HA.md
index 0703ccba2fd..d5d831f8610 100644
--- a/hadoop-hdds/docs/content/feature/SCM-HA.md
+++ b/hadoop-hdds/docs/content/feature/SCM-HA.md
@@ -104,7 +104,7 @@ ozone admin scm transfer -id <SCM_SERVICE_ID> -r
```
* `-id, --service-id`: Specifies the SCM Service ID.
-* `-n, --new-leader-id`: The SCM UUID (Raft peer ID) of the SCM to which
leadership will be transferred (e.g., `e6877ce5-56cd-4f0b-ad60-4c8ef9000882`).
+* `-n, --new-leader-id`: The SCM to which leadership will be transferred,
given either as the SCM UUID (Raft peer ID, e.g.
`e6877ce5-56cd-4f0b-ad60-4c8ef9000882`) or as the configured node id (e.g.
`scm1`).
* `-r, --random`: Randomly chooses a follower to transfer leadership to.
### Example
@@ -113,6 +113,7 @@ To transfer leadership to a specific SCM in a cluster with
service ID `cluster1`
```bash
ozone admin scm transfer -id cluster1 -n e6877ce5-56cd-4f0b-ad60-4c8ef9000882
+ozone admin scm transfer -id cluster1 -n scm1
```
To transfer leadership to a random follower:
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHANodeDetails.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHANodeDetails.java
index 9c038ac9ddf..60a4ca7325f 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHANodeDetails.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHANodeDetails.java
@@ -116,6 +116,13 @@ public List< SCMNodeDetails > getPeerNodeDetails() {
return peerNodeDetails;
}
+ /** Details of every SCM in the service, the local one included. */
+ public List<SCMNodeDetails> getAllNodeDetails() {
+ final List<SCMNodeDetails> allNodes = new ArrayList<>(peerNodeDetails);
+ allNodes.add(localNodeDetails);
+ return allNodes;
+ }
+
public static SCMHANodeDetails loadDefaultConfig(
OzoneConfiguration conf) throws IOException {
int ratisPort = conf.getInt(
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMClientProtocolServer.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMClientProtocolServer.java
index 96b9efce50f..8069971459e 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMClientProtocolServer.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMClientProtocolServer.java
@@ -89,6 +89,7 @@
import org.apache.hadoop.hdds.scm.events.SCMEvents;
import org.apache.hadoop.hdds.scm.exceptions.SCMException;
import org.apache.hadoop.hdds.scm.exceptions.SCMException.ResultCodes;
+import org.apache.hadoop.hdds.scm.ha.SCMNodeDetails;
import org.apache.hadoop.hdds.scm.ha.SCMRatisServer;
import org.apache.hadoop.hdds.scm.ha.SCMRatisServerImpl;
import org.apache.hadoop.hdds.scm.node.DatanodeInfo;
@@ -1002,7 +1003,7 @@ public void transferLeadership(String newLeaderId)
.orElseThrow(() -> new IOException("Cannot" +
" find a new leader to transfer leadership."));
} else {
- targetPeerId = RaftPeerId.valueOf(newLeaderId);
+ targetPeerId = resolveTargetPeerId(newLeaderId, group);
}
final GrpcTlsConfig tlsConfig =
createSCMRatisTLSConfig(new SecurityConfig(scm.getConfiguration()),
@@ -1019,6 +1020,27 @@ public void transferLeadership(String newLeaderId)
SCMAction.TRANSFER_LEADERSHIP, auditMap));
}
+ /** Resolves the transfer target, which may be given as an SCM UUID or as a
configured SCM node id. */
+ private RaftPeerId resolveTargetPeerId(String newLeaderId, RaftGroup group) {
+ final RaftPeerId peerId = RaftPeerId.valueOf(newLeaderId);
+ if (group.getPeer(peerId) != null) {
+ return peerId;
+ }
+ // Raft peer ids are SCM UUIDs, so a node id only matches through its
configured Ratis address.
+ for (SCMNodeDetails node : scm.getSCMHANodeDetails().getAllNodeDetails()) {
+ if (!newLeaderId.equals(node.getNodeId())) {
+ continue;
+ }
+ for (RaftPeer peer : group.getPeers()) {
+ if (node.getRatisHostPortStr().equals(peer.getAddress())) {
+ return peer.getId();
+ }
+ }
+ }
+ // Leave an unmatched id to RatisHelper, which reports the group it did
not match.
+ return peerId;
+ }
+
@Deprecated
@Override
public List<DeletedBlocksTransactionInfo> getFailedDeletedBlockTxn(int count,
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
index e2e9834607a..12665164c85 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
@@ -2210,10 +2210,7 @@ public String getPrimordialNode() {
String primordialNode = SCMHAUtils.getPrimordialSCM(configuration);
// primordialNode can be nodeId too . If it is then return hostname.
if (HddsUtils.getSCMNodeIds(configuration).contains(primordialNode)) {
- List<SCMNodeDetails> localAndPeerNodes =
- new ArrayList<>(scmHANodeDetails.getPeerNodeDetails());
- localAndPeerNodes.add(getSCMHANodeDetails().getLocalNodeDetails());
- for (SCMNodeDetails nodes : localAndPeerNodes) {
+ for (SCMNodeDetails nodes : scmHANodeDetails.getAllNodeDetails()) {
if (nodes.getNodeId().equals(primordialNode)) {
return nodes.getHostName();
}
diff --git
a/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/ozone/admin/scm/TransferScmLeaderSubCommand.java
b/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/ozone/admin/scm/TransferScmLeaderSubCommand.java
index 70f30e3d519..6cdc9a7e3ea 100644
---
a/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/ozone/admin/scm/TransferScmLeaderSubCommand.java
+++
b/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/ozone/admin/scm/TransferScmLeaderSubCommand.java
@@ -48,7 +48,7 @@ static class TransferOption {
@CommandLine.Option(
names = {"-n", "--new-leader-id"},
description = "The new leader id of SCM to transfer leadership. " +
- "Should be ScmId(UUID)."
+ "Either the ScmId(UUID) or the configured node id (e.g. scm1)."
)
private String scmId;
diff --git
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestTransferLeadershipShell.java
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestTransferLeadershipShell.java
index b187e3179fc..e866842ef22 100644
---
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestTransferLeadershipShell.java
+++
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestTransferLeadershipShell.java
@@ -19,12 +19,15 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Stream;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.ratis.RatisHelper;
import org.apache.hadoop.hdds.scm.ScmConfigKeys;
@@ -33,11 +36,16 @@
import org.apache.hadoop.ozone.MiniOzoneHAClusterImpl;
import org.apache.hadoop.ozone.admin.OzoneAdmin;
import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.ozone.test.GenericTestUtils;
import org.apache.ratis.protocol.RaftPeer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Named;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+import picocli.CommandLine.ExitCode;
/**
* Test transferLeadership with SCM HA setup.
@@ -100,29 +108,55 @@ public void testOmTransfer() throws Exception {
assertOMResetPriorities();
}
- @Test
- public void testScmTransfer() throws Exception {
- StorageContainerManager oldLeader = getScmLeader(cluster);
- List<StorageContainerManager> scmList = new ArrayList<>(cluster.
- getStorageContainerManagersList());
- assertThat(scmList).contains(oldLeader);
- scmList.remove(oldLeader);
- StorageContainerManager newLeader = scmList.get(0);
+ static Stream<Named<Function<StorageContainerManager, String>>>
scmTargetIdExtractors() {
+ return Stream.of(
+ Named.of("scmId", StorageContainerManager::getScmId),
+ Named.of("nodeId", StorageContainerManager::getSCMNodeId));
+ }
- String[] args1 = {"scm", "transfer", "-n", newLeader.getScmId()};
- ozoneAdmin.execute(args1);
+ @ParameterizedTest
+ @MethodSource("scmTargetIdExtractors")
+ public void testScmTransfer(Function<StorageContainerManager, String>
targetId) throws Exception {
+ StorageContainerManager newLeader = pickScmFollower();
+
+ String[] args = {"scm", "transfer", "-n", targetId.apply(newLeader)};
+ ozoneAdmin.execute(args);
cluster.waitForClusterToBeReady();
assertEquals(newLeader, getScmLeader(cluster));
assertSCMResetPriorities();
+ }
- oldLeader = getScmLeader(cluster);
- String[] args3 = {"scm", "transfer", "-r"};
- ozoneAdmin.execute(args3);
+ @Test
+ public void testScmTransferToRandomFollower() throws Exception {
+ StorageContainerManager oldLeader = getScmLeader(cluster);
+
+ String[] args = {"scm", "transfer", "-r"};
+ ozoneAdmin.execute(args);
cluster.waitForClusterToBeReady();
assertNotSame(oldLeader, getScmLeader(cluster));
assertSCMResetPriorities();
}
+ @Test
+ public void testScmTransferToUnknownIdFails() throws Exception {
+ StorageContainerManager leader = getScmLeader(cluster);
+
+ String[] args = {"scm", "transfer", "-n", "no-such-scm"};
+ try (GenericTestUtils.SystemErrCapturer capture = new
GenericTestUtils.SystemErrCapturer()) {
+ assertNotEquals(ExitCode.OK, ozoneAdmin.execute(args));
+ assertThat(capture.getOutput()).contains("Target no-such-scm not found
in group");
+ }
+ assertEquals(leader, getScmLeader(cluster));
+ }
+
+ private StorageContainerManager pickScmFollower() {
+ StorageContainerManager leader = getScmLeader(cluster);
+ List<StorageContainerManager> scmList = new
ArrayList<>(cluster.getStorageContainerManagersList());
+ assertThat(scmList).contains(leader);
+ scmList.remove(leader);
+ return scmList.get(0);
+ }
+
private void assertOMResetPriorities() {
final Collection<RaftPeer> raftPeers = cluster.getOMLeader()
.getOmRatisServer()
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]