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 6451f9b3e RATIS-2155. Add a builder for RatisShell. (#1150)
6451f9b3e is described below
commit 6451f9b3ee3784620f6fb8984bf305f4df11a185
Author: Tsz-Wo Nicholas Sze <[email protected]>
AuthorDate: Tue Sep 17 22:13:38 2024 -0700
RATIS-2155. Add a builder for RatisShell. (#1150)
---
.../grpc/client/GrpcClientProtocolClient.java | 1 +
.../org/apache/ratis/grpc/server/GrpcService.java | 1 +
.../apache/ratis/grpc/MiniRaftClusterWithGrpc.java | 7 +-
.../java/org/apache/ratis/shell/cli/CliUtils.java | 33 +-----
.../org/apache/ratis/shell/cli/sh/RatisShell.java | 44 +++++++-
.../shell/cli/sh/command/AbstractCommand.java | 14 ++-
.../shell/cli/sh/command/AbstractRatisCommand.java | 6 +-
.../apache/ratis/shell/cli/sh/command/Context.java | 69 ++++++++++++
.../ratis/shell/cli/sh/election/PauseCommand.java | 3 +-
.../ratis/shell/cli/sh/election/ResumeCommand.java | 3 +-
.../shell/cli/sh/election/StepDownCommand.java | 3 +-
.../shell/cli/sh/election/TransferCommand.java | 3 +-
.../ratis/shell/cli/sh/group/GroupListCommand.java | 2 +-
.../apache/ratis/shell/cli/sh/peer/AddCommand.java | 2 +-
.../ratis/shell/cli/sh/peer/RemoveCommand.java | 3 +-
.../shell/cli/sh/peer/SetPriorityCommand.java | 3 +-
.../shell/cli/sh/snapshot/TakeSnapshotCommand.java | 3 +-
.../apache/ratis/security/SecurityTestUtils.java | 17 +++
.../ratis/shell/cli/sh/TestSecureRatisShell.java | 123 +++++++++++++++++++++
19 files changed, 283 insertions(+), 57 deletions(-)
diff --git
a/ratis-grpc/src/main/java/org/apache/ratis/grpc/client/GrpcClientProtocolClient.java
b/ratis-grpc/src/main/java/org/apache/ratis/grpc/client/GrpcClientProtocolClient.java
index a1f01a512..3b9d51268 100644
---
a/ratis-grpc/src/main/java/org/apache/ratis/grpc/client/GrpcClientProtocolClient.java
+++
b/ratis-grpc/src/main/java/org/apache/ratis/grpc/client/GrpcClientProtocolClient.java
@@ -132,6 +132,7 @@ public class GrpcClientProtocolClient implements Closeable {
channelBuilder.proxyDetector(uri -> null);
if (tlsConf != null) {
+ LOG.debug("Setting TLS for {}", address);
SslContextBuilder sslContextBuilder = GrpcSslContexts.forClient();
GrpcUtil.setTrustManager(sslContextBuilder, tlsConf.getTrustManager());
if (tlsConf.getMtlsEnabled()) {
diff --git
a/ratis-grpc/src/main/java/org/apache/ratis/grpc/server/GrpcService.java
b/ratis-grpc/src/main/java/org/apache/ratis/grpc/server/GrpcService.java
index ce434c5e8..510dfcaa2 100644
--- a/ratis-grpc/src/main/java/org/apache/ratis/grpc/server/GrpcService.java
+++ b/ratis-grpc/src/main/java/org/apache/ratis/grpc/server/GrpcService.java
@@ -198,6 +198,7 @@ public final class GrpcService extends
RaftServerRpcWithProxy<GrpcServerProtocol
.flowControlWindow(flowControlWindow.getSizeInt());
if (tlsConfig != null) {
+ LOG.info("Setting TLS for {}", address);
SslContextBuilder sslContextBuilder =
GrpcUtil.initSslContextBuilderForServer(tlsConfig.getKeyManager());
if (tlsConfig.getMtlsEnabled()) {
sslContextBuilder.clientAuth(ClientAuth.REQUIRE);
diff --git
a/ratis-grpc/src/test/java/org/apache/ratis/grpc/MiniRaftClusterWithGrpc.java
b/ratis-grpc/src/test/java/org/apache/ratis/grpc/MiniRaftClusterWithGrpc.java
index bd3b13750..47f9e1d4b 100644
---
a/ratis-grpc/src/test/java/org/apache/ratis/grpc/MiniRaftClusterWithGrpc.java
+++
b/ratis-grpc/src/test/java/org/apache/ratis/grpc/MiniRaftClusterWithGrpc.java
@@ -64,8 +64,11 @@ public class MiniRaftClusterWithGrpc extends
MiniRaftCluster.RpcBase {
public static final DelayLocalExecutionInjection
SEND_SERVER_REQUEST_INJECTION =
new DelayLocalExecutionInjection(GrpcService.GRPC_SEND_SERVER_REQUEST);
- protected MiniRaftClusterWithGrpc(String[] ids, String[] listenerIds,
RaftProperties properties,
- Parameters parameters) {
+ public MiniRaftClusterWithGrpc(String[] ids, RaftProperties properties,
Parameters parameters) {
+ this(ids, new String[0], properties, parameters);
+ }
+
+ public MiniRaftClusterWithGrpc(String[] ids, String[] listenerIds,
RaftProperties properties, Parameters parameters) {
super(ids, listenerIds, properties, parameters);
}
diff --git a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/CliUtils.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/CliUtils.java
index 98e21be2a..1cecc665c 100644
--- a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/CliUtils.java
+++ b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/CliUtils.java
@@ -18,17 +18,12 @@
package org.apache.ratis.shell.cli;
import org.apache.ratis.client.RaftClient;
-import org.apache.ratis.client.RaftClientConfigKeys;
-import org.apache.ratis.conf.RaftProperties;
import org.apache.ratis.protocol.GroupInfoReply;
import org.apache.ratis.protocol.RaftClientReply;
-import org.apache.ratis.protocol.RaftGroup;
import org.apache.ratis.protocol.RaftGroupId;
import org.apache.ratis.protocol.RaftPeer;
import org.apache.ratis.protocol.RaftPeerId;
import org.apache.ratis.protocol.exceptions.RaftException;
-import org.apache.ratis.retry.ExponentialBackoffRetry;
-import org.apache.ratis.util.TimeDuration;
import org.apache.ratis.util.function.CheckedFunction;
import java.io.IOException;
@@ -36,24 +31,16 @@ import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.concurrent.TimeUnit;
import java.util.List;
import java.util.Optional;
-import java.util.Properties;
+import java.util.UUID;
import java.util.function.Supplier;
import java.util.stream.Collectors;
-import java.util.UUID;
/**
* Utilities for command line interface.
*/
public final class CliUtils {
- private static final ExponentialBackoffRetry RETRY_POLICY =
ExponentialBackoffRetry.newBuilder()
- .setBaseSleepTime(TimeDuration.valueOf(1000, TimeUnit.MILLISECONDS))
- .setMaxAttempts(10)
- .setMaxSleepTime(TimeDuration.valueOf(100_000, TimeUnit.MILLISECONDS))
- .build();
-
private CliUtils() {
// prevent instantiation
}
@@ -68,24 +55,6 @@ public final class CliUtils {
return RaftPeerId.getRaftPeerId(host + "_" + port);
}
- /** Create a new {@link RaftClient} from the given group. */
- public static RaftClient newRaftClient(RaftGroup group) {
- RaftProperties properties = new RaftProperties();
- RaftClientConfigKeys.Rpc.setRequestTimeout(properties,
- TimeDuration.valueOf(15, TimeUnit.SECONDS));
-
- // Since ratis-shell support GENERIC_COMMAND_OPTIONS, here we should
- // merge these options to raft properties to make it work.
- final Properties sys = System.getProperties();
- sys.stringPropertyNames().forEach(key -> properties.set(key,
sys.getProperty(key)));
-
- return RaftClient.newBuilder()
- .setRaftGroup(group)
- .setProperties(properties)
- .setRetryPolicy(RETRY_POLICY)
- .build();
- }
-
/**
* Apply the given function to the given parameter a list.
*
diff --git
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/RatisShell.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/RatisShell.java
index 2e53e3191..cdad68301 100644
--- a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/RatisShell.java
+++ b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/RatisShell.java
@@ -17,6 +17,9 @@
*/
package org.apache.ratis.shell.cli.sh;
+import org.apache.ratis.conf.Parameters;
+import org.apache.ratis.conf.RaftProperties;
+import org.apache.ratis.retry.RetryPolicy;
import org.apache.ratis.shell.cli.AbstractShell;
import org.apache.ratis.shell.cli.Command;
import org.apache.ratis.shell.cli.sh.command.AbstractParentCommand;
@@ -60,7 +63,11 @@ public class RatisShell extends AbstractShell {
}
public RatisShell(PrintStream out) {
- super(new Context(out));
+ this(new Context(out));
+ }
+
+ private RatisShell(Context context) {
+ super(context);
}
@Override
@@ -73,4 +80,39 @@ public class RatisShell extends AbstractShell {
return allParentCommands(context).stream()
.collect(Collectors.toMap(Command::getCommandName,
Function.identity()));
}
+
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private PrintStream printStream = System.out;
+ private RetryPolicy retryPolicy;
+ private RaftProperties properties;
+ private Parameters parameters;
+
+ public Builder setPrintStream(PrintStream printStream) {
+ this.printStream = printStream;
+ return this;
+ }
+
+ public Builder setRetryPolicy(RetryPolicy retryPolicy) {
+ this.retryPolicy = retryPolicy;
+ return this;
+ }
+
+ public Builder setProperties(RaftProperties properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ public Builder setParameters(Parameters parameters) {
+ this.parameters = parameters;
+ return this;
+ }
+
+ public RatisShell build() {
+ return new RatisShell(new Context(printStream, false, retryPolicy,
properties, parameters));
+ }
+ }
}
diff --git
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/AbstractCommand.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/AbstractCommand.java
index f02761de4..e1d7f8e0b 100644
---
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/AbstractCommand.java
+++
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/AbstractCommand.java
@@ -26,21 +26,25 @@ import java.io.PrintStream;
*/
public abstract class AbstractCommand implements Command {
- private final PrintStream printStream;
+ private final Context context;
protected AbstractCommand(Context context) {
- printStream = context.getPrintStream();
+ this.context = context;
+ }
+
+ protected Context getContext() {
+ return context;
}
protected PrintStream getPrintStream() {
- return printStream;
+ return getContext().getPrintStream();
}
protected void printf(String format, Object... args) {
- printStream.printf(format, args);
+ getPrintStream().printf(format, args);
}
protected void println(Object message) {
- printStream.println(message);
+ getPrintStream().println(message);
}
}
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 a9d391f86..aea1f7c4b 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
@@ -66,7 +66,7 @@ public abstract class AbstractRatisCommand extends
AbstractCommand {
final RaftGroupId groupIdSpecified =
CliUtils.parseRaftGroupId(cl.getOptionValue(GROUPID_OPTION_NAME));
raftGroup = RaftGroup.valueOf(groupIdSpecified != null? groupIdSpecified:
RaftGroupId.randomId(), peers);
PrintStream printStream = getPrintStream();
- try (final RaftClient client = CliUtils.newRaftClient(raftGroup)) {
+ try (final RaftClient client = newRaftClient()) {
final RaftGroupId remoteGroupId = CliUtils.getGroupId(client, peers,
groupIdSpecified, printStream);
groupInfoReply = CliUtils.getGroupInfo(client, peers, remoteGroupId,
printStream);
raftGroup = groupInfoReply.getGroup();
@@ -74,6 +74,10 @@ public abstract class AbstractRatisCommand extends
AbstractCommand {
return 0;
}
+ protected RaftClient newRaftClient() {
+ return getContext().newRaftClient(getRaftGroup());
+ }
+
@Override
public Options getOptions() {
return new Options()
diff --git
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/Context.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/Context.java
index bae98dc0b..6f80256d4 100644
---
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/Context.java
+++
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/command/Context.java
@@ -17,27 +17,59 @@
*/
package org.apache.ratis.shell.cli.sh.command;
+import org.apache.ratis.client.RaftClient;
+import org.apache.ratis.client.RaftClientConfigKeys;
+import org.apache.ratis.conf.Parameters;
+import org.apache.ratis.conf.RaftProperties;
+import org.apache.ratis.protocol.RaftGroup;
+import org.apache.ratis.retry.ExponentialBackoffRetry;
+import org.apache.ratis.retry.RetryPolicy;
import org.apache.ratis.thirdparty.com.google.common.io.Closer;
+import org.apache.ratis.util.TimeDuration;
import java.io.Closeable;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Objects;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
/**
* A context for ratis-shell.
*/
public final class Context implements Closeable {
+ private static final TimeDuration DEFAULT_REQUEST_TIMEOUT =
TimeDuration.valueOf(15, TimeUnit.SECONDS);
+ private static final RetryPolicy DEFAULT_RETRY_POLICY =
ExponentialBackoffRetry.newBuilder()
+ .setBaseSleepTime(TimeDuration.valueOf(1000, TimeUnit.MILLISECONDS))
+ .setMaxAttempts(10)
+ .setMaxSleepTime(TimeDuration.valueOf(100_000, TimeUnit.MILLISECONDS))
+ .build();
+
private final PrintStream mPrintStream;
private final Closer mCloser;
+ private final boolean cli;
+ private final RetryPolicy retryPolicy;
+ private final RaftProperties properties;
+ private final Parameters parameters;
+
/**
* Build a context.
* @param printStream the print stream
*/
public Context(PrintStream printStream) {
+ this(printStream, true, DEFAULT_RETRY_POLICY, new RaftProperties(), null);
+ }
+
+ public Context(PrintStream printStream, boolean cli, RetryPolicy retryPolicy,
+ RaftProperties properties, Parameters parameters) {
mCloser = Closer.create();
mPrintStream = mCloser.register(Objects.requireNonNull(printStream,
"printStream == null"));
+
+ this.cli = cli;
+ this.retryPolicy = retryPolicy != null? retryPolicy : DEFAULT_RETRY_POLICY;
+ this.properties = properties != null? properties : new RaftProperties();
+ this.parameters = parameters;
}
/**
@@ -47,6 +79,43 @@ public final class Context implements Closeable {
return mPrintStream;
}
+ /** Is this from CLI? */
+ public boolean isCli() {
+ return cli;
+ }
+
+ public RetryPolicy getRetryPolicy() {
+ return retryPolicy;
+ }
+
+ public RaftProperties getProperties() {
+ return properties;
+ }
+
+ public Parameters getParameters() {
+ return parameters;
+ }
+
+ /** Create a new {@link RaftClient} from the given group. */
+ public RaftClient newRaftClient(RaftGroup group) {
+ final RaftProperties p = getProperties();
+ if (isCli()) {
+ RaftClientConfigKeys.Rpc.setRequestTimeout(p, DEFAULT_REQUEST_TIMEOUT);
+
+ // Since ratis-shell support GENERIC_COMMAND_OPTIONS, here we should
+ // merge these options to raft p to make it work.
+ final Properties sys = System.getProperties();
+ sys.stringPropertyNames().forEach(key -> p.set(key,
sys.getProperty(key)));
+ }
+
+ return RaftClient.newBuilder()
+ .setRaftGroup(group)
+ .setProperties(p)
+ .setParameters(getParameters())
+ .setRetryPolicy(getRetryPolicy())
+ .build();
+ }
+
@Override
public void close() throws IOException {
mCloser.close();
diff --git
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/PauseCommand.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/PauseCommand.java
index 242e1886a..f8a627a8f 100644
---
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/PauseCommand.java
+++
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/PauseCommand.java
@@ -24,7 +24,6 @@ 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 org.apache.ratis.shell.cli.CliUtils;
import org.apache.ratis.shell.cli.sh.command.AbstractRatisCommand;
import org.apache.ratis.shell.cli.sh.command.Context;
@@ -61,7 +60,7 @@ public class PauseCommand extends AbstractRatisCommand {
printf("Peer not found: %s", strAddr);
return -1;
}
- try(final RaftClient raftClient = CliUtils.newRaftClient(getRaftGroup())) {
+ try(final RaftClient raftClient = newRaftClient()) {
RaftClientReply reply =
raftClient.getLeaderElectionManagementApi(peerId).pause();
processReply(reply, () -> String.format("Failed to pause leader election
on peer %s", strAddr));
printf(String.format("Successful pause leader election on peer %s",
strAddr));
diff --git
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/ResumeCommand.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/ResumeCommand.java
index dbcee7bd3..1b5c80fac 100644
---
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/ResumeCommand.java
+++
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/ResumeCommand.java
@@ -24,7 +24,6 @@ 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 org.apache.ratis.shell.cli.CliUtils;
import org.apache.ratis.shell.cli.sh.command.AbstractRatisCommand;
import org.apache.ratis.shell.cli.sh.command.Context;
@@ -61,7 +60,7 @@ public class ResumeCommand extends AbstractRatisCommand {
printf("Can't find a sever with the address:%s", strAddr);
return -1;
}
- try(final RaftClient raftClient = CliUtils.newRaftClient(getRaftGroup())) {
+ try(final RaftClient raftClient = newRaftClient()) {
RaftClientReply reply =
raftClient.getLeaderElectionManagementApi(peerId).resume();
processReply(reply, () -> String.format("Failed to resume leader
election on peer %s", strAddr));
printf(String.format("Successful pause leader election on peer %s",
strAddr));
diff --git
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/StepDownCommand.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/StepDownCommand.java
index da641a07b..f18921e5e 100644
---
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/StepDownCommand.java
+++
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/StepDownCommand.java
@@ -21,7 +21,6 @@ import org.apache.commons.cli.CommandLine;
import org.apache.ratis.client.RaftClient;
import org.apache.ratis.protocol.RaftClientReply;
import org.apache.ratis.protocol.RaftPeerId;
-import org.apache.ratis.shell.cli.CliUtils;
import org.apache.ratis.shell.cli.sh.command.AbstractRatisCommand;
import org.apache.ratis.shell.cli.sh.command.Context;
@@ -48,7 +47,7 @@ public class StepDownCommand extends AbstractRatisCommand {
public int run(CommandLine cl) throws IOException {
super.run(cl);
- try (RaftClient client = CliUtils.newRaftClient(getRaftGroup())) {
+ try (RaftClient client = newRaftClient()) {
RaftPeerId leaderId =
RaftPeerId.valueOf(getLeader(getGroupInfoReply().getRoleInfoProto()).getId());
final RaftClientReply transferLeadershipReply =
client.admin().transferLeadership(null, leaderId, 60_000);
processReply(transferLeadershipReply, () -> "Failed to step down
leader");
diff --git
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/TransferCommand.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/TransferCommand.java
index 24eae7353..88cfec914 100644
---
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/TransferCommand.java
+++
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/election/TransferCommand.java
@@ -25,7 +25,6 @@ import org.apache.ratis.proto.RaftProtos.RaftPeerRole;
import org.apache.ratis.protocol.RaftClientReply;
import org.apache.ratis.protocol.RaftPeer;
import org.apache.ratis.protocol.exceptions.TransferLeadershipException;
-import org.apache.ratis.shell.cli.CliUtils;
import org.apache.ratis.shell.cli.sh.command.AbstractRatisCommand;
import org.apache.ratis.shell.cli.sh.command.Context;
import org.apache.ratis.util.TimeDuration;
@@ -74,7 +73,7 @@ public class TransferCommand extends AbstractRatisCommand {
printf("Peer with address %s not found.", strAddr);
return -2;
}
- try (RaftClient client = CliUtils.newRaftClient(getRaftGroup())) {
+ try (RaftClient client = newRaftClient()) {
// transfer leadership
if (!tryTransfer(client, newLeader, highestPriority,
timeout.orElse(timeoutDefault))) {
// legacy mode, transfer leadership by setting priority.
diff --git
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/group/GroupListCommand.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/group/GroupListCommand.java
index 5ee89c53c..214ed1507 100644
---
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/group/GroupListCommand.java
+++
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/group/GroupListCommand.java
@@ -69,7 +69,7 @@ public class GroupListCommand extends AbstractRatisCommand {
+ " options are missing.");
}
- try(final RaftClient raftClient = CliUtils.newRaftClient(getRaftGroup())) {
+ try(final RaftClient raftClient = newRaftClient()) {
GroupListReply reply = raftClient.getGroupManagementApi(peerId).list();
processReply(reply, () -> String.format("Failed to get group information
of peerId %s (server %s)",
peerId, address));
diff --git
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/peer/AddCommand.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/peer/AddCommand.java
index 62c6c5793..be8f78995 100644
---
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/peer/AddCommand.java
+++
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/peer/AddCommand.java
@@ -81,7 +81,7 @@ public class AddCommand extends AbstractRatisCommand {
"Both " + PEER_ID_OPTION_NAME + " and " + ADDRESS_OPTION_NAME + "
options are missing.");
}
- try (RaftClient client = CliUtils.newRaftClient(getRaftGroup())) {
+ try (RaftClient client = newRaftClient()) {
final Stream<RaftPeer> remaining = getPeerStream(RaftPeerRole.FOLLOWER);
final Stream<RaftPeer> adding = ids.stream().map(raftPeerId ->
RaftPeer.newBuilder()
.setId(raftPeerId)
diff --git
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/peer/RemoveCommand.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/peer/RemoveCommand.java
index e2aa786b3..904a89788 100644
---
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/peer/RemoveCommand.java
+++
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/peer/RemoveCommand.java
@@ -25,7 +25,6 @@ import org.apache.ratis.proto.RaftProtos.RaftPeerRole;
import org.apache.ratis.protocol.RaftClientReply;
import org.apache.ratis.protocol.RaftPeer;
import org.apache.ratis.protocol.RaftPeerId;
-import org.apache.ratis.shell.cli.CliUtils;
import org.apache.ratis.shell.cli.sh.command.AbstractRatisCommand;
import org.apache.ratis.shell.cli.sh.command.Context;
@@ -66,7 +65,7 @@ public class RemoveCommand extends AbstractRatisCommand {
throw new IllegalArgumentException(
"Both " + PEER_ID_OPTION_NAME + " and " + ADDRESS_OPTION_NAME + "
options are missing.");
}
- try (RaftClient client = CliUtils.newRaftClient(getRaftGroup())) {
+ try (RaftClient client = newRaftClient()) {
final List<RaftPeer> peers = getPeerStream(RaftPeerRole.FOLLOWER)
.filter(raftPeer ->
!ids.contains(raftPeer.getId())).collect(Collectors.toList());
final List<RaftPeer> listeners = getPeerStream(RaftPeerRole.LISTENER)
diff --git
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/peer/SetPriorityCommand.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/peer/SetPriorityCommand.java
index e2d4d1a53..2834ef5cc 100644
---
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/peer/SetPriorityCommand.java
+++
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/peer/SetPriorityCommand.java
@@ -24,7 +24,6 @@ import org.apache.ratis.client.RaftClient;
import org.apache.ratis.proto.RaftProtos.RaftPeerRole;
import org.apache.ratis.protocol.RaftClientReply;
import org.apache.ratis.protocol.RaftPeer;
-import org.apache.ratis.shell.cli.CliUtils;
import org.apache.ratis.shell.cli.sh.command.AbstractRatisCommand;
import org.apache.ratis.shell.cli.sh.command.Context;
@@ -63,7 +62,7 @@ public class SetPriorityCommand extends AbstractRatisCommand {
addressPriorityMap.put(str[0], Integer.parseInt(str[1]));
}
- try (RaftClient client = CliUtils.newRaftClient(getRaftGroup())) {
+ try (RaftClient client = newRaftClient()) {
final List<RaftPeer> peers =
getPeerStream(RaftPeerRole.FOLLOWER).map(peer -> {
final Integer newPriority = addressPriorityMap.get(peer.getAddress());
final int priority = newPriority != null ? newPriority :
peer.getPriority();
diff --git
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/snapshot/TakeSnapshotCommand.java
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/snapshot/TakeSnapshotCommand.java
index e76f215f4..521b22e4e 100644
---
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/snapshot/TakeSnapshotCommand.java
+++
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/snapshot/TakeSnapshotCommand.java
@@ -23,7 +23,6 @@ import org.apache.commons.cli.Options;
import org.apache.ratis.client.RaftClient;
import org.apache.ratis.protocol.RaftClientReply;
import org.apache.ratis.protocol.RaftPeerId;
-import org.apache.ratis.shell.cli.CliUtils;
import org.apache.ratis.shell.cli.sh.command.AbstractRatisCommand;
import org.apache.ratis.shell.cli.sh.command.Context;
@@ -58,7 +57,7 @@ public class TakeSnapshotCommand extends AbstractRatisCommand
{
} else {
timeout = 3000;
}
- try(final RaftClient raftClient = CliUtils.newRaftClient(getRaftGroup())) {
+ try(final RaftClient raftClient = newRaftClient()) {
if (cl.hasOption(PEER_ID_OPTION_NAME)) {
peerId =
RaftPeerId.getRaftPeerId(cl.getOptionValue(PEER_ID_OPTION_NAME));
} else {
diff --git
a/ratis-test/src/test/java/org/apache/ratis/security/SecurityTestUtils.java
b/ratis-test/src/test/java/org/apache/ratis/security/SecurityTestUtils.java
index c390f10f4..cbb8e1b79 100644
--- a/ratis-test/src/test/java/org/apache/ratis/security/SecurityTestUtils.java
+++ b/ratis-test/src/test/java/org/apache/ratis/security/SecurityTestUtils.java
@@ -54,6 +54,23 @@ public interface SecurityTestUtils {
ClassLoader CLASS_LOADER = SecurityTestUtils.class.getClassLoader();
+ TrustManager EMPTY_TRUST_MANAGER = new X509TrustManager() {
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
+ };
+
+ static TrustManager emptyTrustManager() {
+ return EMPTY_TRUST_MANAGER;
+ }
+
static File getResource(String name) {
final File file = Optional.ofNullable(CLASS_LOADER.getResource(name))
.map(URL::getFile)
diff --git
a/ratis-test/src/test/java/org/apache/ratis/shell/cli/sh/TestSecureRatisShell.java
b/ratis-test/src/test/java/org/apache/ratis/shell/cli/sh/TestSecureRatisShell.java
new file mode 100644
index 000000000..785cd2e82
--- /dev/null
+++
b/ratis-test/src/test/java/org/apache/ratis/shell/cli/sh/TestSecureRatisShell.java
@@ -0,0 +1,123 @@
+/*
+ * 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;
+
+import org.apache.ratis.BaseTest;
+import org.apache.ratis.client.RaftClientConfigKeys;
+import org.apache.ratis.conf.Parameters;
+import org.apache.ratis.conf.RaftProperties;
+import org.apache.ratis.grpc.GrpcConfigKeys;
+import org.apache.ratis.grpc.GrpcTlsConfig;
+import org.apache.ratis.grpc.MiniRaftClusterWithGrpc;
+import org.apache.ratis.netty.NettyUtils;
+import org.apache.ratis.protocol.RaftPeer;
+import org.apache.ratis.security.SecurityTestUtils;
+import org.apache.ratis.util.Slf4jUtils;
+import org.apache.ratis.util.TimeDuration;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.slf4j.event.Level;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.TrustManager;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.List;
+
+public class TestSecureRatisShell extends BaseTest {
+ {
+ Slf4jUtils.setLogLevel(NettyUtils.LOG, Level.DEBUG);
+ }
+
+ private static final Parameters SERVER_PARAMETERS = new Parameters();
+ private static final Parameters CLIENT_PARAMETERS = new Parameters();
+
+ static {
+ final TrustManager emptyTrustManager =
SecurityTestUtils.emptyTrustManager();
+ try {
+ final KeyManager serverKeyManager =
SecurityTestUtils.getKeyManager(SecurityTestUtils::getServerKeyStore);
+ final GrpcTlsConfig serverConfig = new GrpcTlsConfig(serverKeyManager,
emptyTrustManager, true);
+ GrpcConfigKeys.Server.setTlsConf(SERVER_PARAMETERS, serverConfig);
+ GrpcConfigKeys.Admin.setTlsConf(SERVER_PARAMETERS, serverConfig);
+ GrpcConfigKeys.Client.setTlsConf(SERVER_PARAMETERS, serverConfig);
+ } catch (Exception e) {
+ throw new IllegalStateException("Failed to init SERVER_PARAMETERS", e);
+ }
+
+ try {
+ final KeyManager clientKeyManager =
SecurityTestUtils.getKeyManager(SecurityTestUtils::getClientKeyStore);
+ final GrpcTlsConfig clientConfig = new GrpcTlsConfig(clientKeyManager,
emptyTrustManager, true);
+ GrpcConfigKeys.Admin.setTlsConf(CLIENT_PARAMETERS, clientConfig);
+ GrpcConfigKeys.Client.setTlsConf(CLIENT_PARAMETERS, clientConfig);
+ } catch (Exception e) {
+ throw new IllegalStateException("Failed to init CLIENT_PARAMETERS", e);
+ }
+ }
+
+ @Test
+ public void testRatisShell() throws Exception {
+ final String[] ids = {"s0"};
+ final RaftProperties properties = new RaftProperties();
+ RaftClientConfigKeys.Rpc.setRequestTimeout(properties,
TimeDuration.ONE_MINUTE);
+ GrpcConfigKeys.TLS.setEnabled(properties, true);
+ GrpcConfigKeys.TLS.setMutualAuthnEnabled(properties, true);
+
+ try(MiniRaftClusterWithGrpc cluster = new MiniRaftClusterWithGrpc(ids,
properties, SERVER_PARAMETERS)) {
+ cluster.start();
+
+ runTestRatisShell(cluster, true);
+ runTestRatisShell(cluster, false);
+ }
+ }
+
+ void runTestRatisShell(MiniRaftClusterWithGrpc cluster, boolean secure)
throws Exception {
+ try(ByteArrayOutputStream out = new ByteArrayOutputStream(1 << 16);
+ RatisShell shell = newRatisShell(out, cluster.getProperties(),
secure)) {
+ shell.run("group", "info", "-peers", toCliArg(cluster.getPeers()));
+ final String output = out.toString();
+ LOG.info("output (secure? {}):\n{}", secure, output);
+ final String gid = cluster.getGroup().getGroupId().getUuid().toString();
+ if (secure) {
+ Assertions.assertTrue(output.contains(gid), () -> gid + " not found
for secure shell");
+ } else {
+ Assertions.assertTrue(output.contains("Failed to get group ID"),
"Unexpected output for unsecure shell");
+ }
+ }
+ }
+
+ static RatisShell newRatisShell(OutputStream out, RaftProperties properties,
boolean secure) {
+ final PrintStream printStream = new PrintStream(out, true);
+ if (!secure) {
+ return new RatisShell(printStream);
+ }
+ return RatisShell.newBuilder()
+ .setPrintStream(printStream)
+ .setProperties(properties)
+ .setParameters(CLIENT_PARAMETERS)
+ .build();
+ }
+
+ static String toCliArg(List<RaftPeer> peers) {
+ final StringBuilder b = new StringBuilder();
+ for(RaftPeer peer : peers) {
+ b.append(peer.getAdminAddress()).append(",");
+ }
+ return b.substring(0, b.length() - 1);
+ }
+}