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

szetszwo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ratis.git


The following commit(s) were added to refs/heads/master by this push:
     new ba7b24b  RATIS-1428. Add ratis-shell elect command (#531)
ba7b24b is described below

commit ba7b24b71c0df104f98f40f2b75c4daca7b9cf67
Author: maobaolong <[email protected]>
AuthorDate: Fri Nov 12 19:34:00 2021 +0800

    RATIS-1428. Add ratis-shell elect command (#531)
---
 .../shell/cli/sh/command/AbstractRatisCommand.java |  22 ++--
 .../ratis/shell/cli/sh/command/ElectCommand.java   | 130 +++++++++++++++++++++
 .../ratis/shell/cli/sh/command/InfoCommand.java    |   4 +-
 3 files changed, 141 insertions(+), 15 deletions(-)

diff --git 
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/AbstractRatisCommand.java
 
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/AbstractRatisCommand.java
index 07e76cf..6c8c8b6 100644
--- 
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/AbstractRatisCommand.java
+++ 
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/AbstractRatisCommand.java
@@ -17,6 +17,7 @@
  */
 package org.apache.ratis.shell.cli.sh.command;
 
+import org.apache.commons.cli.Option;
 import org.apache.ratis.protocol.*;
 import org.apache.ratis.protocol.exceptions.RaftException;
 import org.apache.ratis.shell.cli.Command;
@@ -80,10 +81,7 @@ public abstract class AbstractRatisCommand implements 
Command {
   @Override
   public int run(CommandLine cl) throws IOException {
     List<InetSocketAddress> addresses = new ArrayList<>();
-    String peersStr = "";
-    if (cl.hasOption(PEER_OPTION_NAME)) {
-      peersStr = cl.getOptionValue(PEER_OPTION_NAME);
-    }
+    String peersStr = cl.getOptionValue(PEER_OPTION_NAME);
     String[] peersArray = peersStr.split(",");
     for (int i = 0; i < peersArray.length; i++) {
       String[] hostPortPair = peersArray[i].split(":");
@@ -131,17 +129,15 @@ public abstract class AbstractRatisCommand implements 
Command {
   }
 
   @Override
-  public void validateArgs(CommandLine cl) throws IllegalArgumentException {
-    if (!cl.hasOption(PEER_OPTION_NAME)) {
-      throw new IllegalArgumentException(String.format(
-          "should provide [%s]", PEER_OPTION_NAME));
-    }
-  }
-
-  @Override
   public Options getOptions() {
     return new Options()
-            .addOption(PEER_OPTION_NAME, true, "Peer addresses seperated by 
comma")
+            .addOption(
+                Option.builder()
+                    .option(PEER_OPTION_NAME)
+                    .hasArg()
+                    .required()
+                    .desc("Peer addresses seperated by comma")
+                    .build())
             .addOption(GROUPID_OPTION_NAME, true, "Raft group id");
   }
 
diff --git 
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/ElectCommand.java
 
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/ElectCommand.java
new file mode 100644
index 0000000..6b7eb0e
--- /dev/null
+++ 
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/ElectCommand.java
@@ -0,0 +1,130 @@
+/*
+ * 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.ratis.shell.cli.sh.command;
+
+import org.apache.commons.cli.Option;
+import org.apache.ratis.shell.cli.RaftUtils;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.apache.ratis.client.RaftClient;
+import org.apache.ratis.protocol.RaftClientReply;
+import org.apache.ratis.protocol.RaftPeer;
+import org.apache.ratis.protocol.RaftPeerId;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Command for transferring the leadership to another peer.
+ */
+public class ElectCommand extends AbstractRatisCommand {
+  public static final String ADDRESS_OPTION_NAME = "address";
+
+  /**
+   * @param context command context
+   */
+  public ElectCommand(Context context) {
+    super(context);
+  }
+
+  @Override
+  public String getCommandName() {
+    return "elect";
+  }
+
+  @Override
+  public int run(CommandLine cl) throws IOException {
+    super.run(cl);
+
+    String strAddr = cl.getOptionValue(ADDRESS_OPTION_NAME);
+
+    RaftPeerId newLeaderId = null;
+    // update priorities to enable transfer
+    List<RaftPeer> peersWithNewPriorities = new ArrayList<>();
+    for (RaftPeer peer : getRaftGroup().getPeers()) {
+      peersWithNewPriorities.add(
+          RaftPeer.newBuilder(peer)
+              .setPriority(peer.getAddress().equals(strAddr) ? 2 : 1)
+              .build()
+      );
+      if (peer.getAddress().equals(strAddr)) {
+        newLeaderId = peer.getId();
+      }
+    }
+    if (newLeaderId == null) {
+      return -2;
+    }
+    try (RaftClient client = RaftUtils.createClient(getRaftGroup())) {
+      String stringPeers = "[" + 
peersWithNewPriorities.stream().map(RaftPeer::toString)
+          .collect(Collectors.joining(", ")) + "]";
+      printf("Applying new peer state before transferring leadership: %n%s%n", 
stringPeers);
+      RaftClientReply setConfigurationReply =
+          client.admin().setConfiguration(peersWithNewPriorities);
+      processReply(setConfigurationReply,
+          () -> "failed to set priorities before initiating election");
+      // transfer leadership
+      printf("Transferring leadership to server with address <%s> %n", 
strAddr);
+      try {
+        Thread.sleep(3_000);
+        RaftClientReply transferLeadershipReply =
+            client.admin().transferLeadership(newLeaderId, 60_000);
+        processReply(transferLeadershipReply, () -> "election failed");
+      } catch (Throwable t) {
+        printf("caught an error when executing transfer: %s%n", 
t.getMessage());
+        return -1;
+      }
+      println("Transferring leadership initiated");
+    }
+    return 0;
+  }
+
+  @Override
+  public String getUsage() {
+    return String.format("%s -%s <HOSTNAME:PORT>"
+        + " -%s 
<PEER0_HOST:PEER0_PORT,PEER1_HOST:PEER1_PORT,PEER2_HOST:PEER2_PORT>"
+        + " [-%s <RAFT_GROUP_ID>]",
+        getCommandName(), ADDRESS_OPTION_NAME, PEER_OPTION_NAME,
+        GROUPID_OPTION_NAME);
+  }
+
+  @Override
+  public String getDescription() {
+    return description();
+  }
+
+  @Override
+  public Options getOptions() {
+    return super.getOptions().addOption(
+        Option.builder()
+            .option(ADDRESS_OPTION_NAME)
+            .hasArg()
+            .required()
+            .desc("Server address that will take over as leader")
+            .build()
+    );
+  }
+
+  /**
+   * @return command's description
+   */
+  public static String description() {
+    return "Transfers leadership to the <hostname>:<port>";
+  }
+}
diff --git 
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/InfoCommand.java
 
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/InfoCommand.java
index 6e05a65..d9ab19c 100644
--- 
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/InfoCommand.java
+++ 
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/InfoCommand.java
@@ -59,8 +59,8 @@ public class InfoCommand extends AbstractRatisCommand {
   @Override
   public String getUsage() {
     return String.format("%s"
-        + " [-%s 
PEER0_HOST:PEER0_PORT,PEER1_HOST:PEER1_PORT,PEER2_HOST:PEER2_PORT]"
-        + " [-%s RAFT_GROUP_ID]",
+        + " -%s 
<PEER0_HOST:PEER0_PORT,PEER1_HOST:PEER1_PORT,PEER2_HOST:PEER2_PORT>"
+        + " [-%s <RAFT_GROUP_ID>]",
         getCommandName(), PEER_OPTION_NAME, GROUPID_OPTION_NAME);
   }
 

Reply via email to