diff --git a/src/java/org/apache/cassandra/tools/nodetool/History.java b/src/java/org/apache/cassandra/tools/nodetool/History.java index 15ece16df2ba..a1d0149e6d58 100644 --- a/src/java/org/apache/cassandra/tools/nodetool/History.java +++ b/src/java/org/apache/cassandra/tools/nodetool/History.java @@ -25,12 +25,11 @@ import org.apache.cassandra.tools.NodeProbe; import org.apache.cassandra.tools.NodeTool; -import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.Option; @Command(name = "history", description = "Print previously executed nodetool commands") -public class History extends AbstractCommand +public class History extends AbstractCommand implements LocalCommand { @Option(paramLabel = "commands", names = { "-n", "--num", "--number-of-commands" }, @@ -50,12 +49,6 @@ protected void execute(NodeProbe probe) output.out.println(line); } - @Override - protected boolean shouldConnect() throws CommandLine.ExecutionException - { - return false; - } - File getHistoryFile() { return NodeTool.getHistoryFile(); diff --git a/src/java/org/apache/cassandra/tools/nodetool/LocalCommand.java b/src/java/org/apache/cassandra/tools/nodetool/LocalCommand.java new file mode 100644 index 000000000000..1cbd2c04a8d1 --- /dev/null +++ b/src/java/org/apache/cassandra/tools/nodetool/LocalCommand.java @@ -0,0 +1,34 @@ +/* + * 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.cassandra.tools.nodetool; + +/** + * Marker interface for nodetool commands that are known to run entirely locally, + * without requiring a JMX connection to the node. + *

+ * Commands that implement this interface will not display JMX connection options + * (host, port, username, password, etc.) in their help output, since those options + * are not applicable to local commands. + *

+ * Note: this is different from commands whose locality is determined at runtime + * (e.g. {@link Sjk}), which override {@link AbstractCommand#shouldConnect()} instead. + */ +public interface LocalCommand +{ +} diff --git a/src/java/org/apache/cassandra/tools/nodetool/layout/CassandraCliHelpLayout.java b/src/java/org/apache/cassandra/tools/nodetool/layout/CassandraCliHelpLayout.java index d99a7dd21bfa..d8be9890fa06 100644 --- a/src/java/org/apache/cassandra/tools/nodetool/layout/CassandraCliHelpLayout.java +++ b/src/java/org/apache/cassandra/tools/nodetool/layout/CassandraCliHelpLayout.java @@ -35,6 +35,7 @@ import org.apache.cassandra.tools.nodetool.CommandUtils; import org.apache.cassandra.tools.nodetool.JmxConnect; +import org.apache.cassandra.tools.nodetool.LocalCommand; import org.apache.cassandra.tools.nodetool.NodetoolCommand; import org.apache.cassandra.utils.Pair; @@ -65,9 +66,11 @@ * Help factory for the Cassandra nodetool to generate the help output in the format * of the airline help output, which is used as the default layout for the Cassandra nodetool. *

- * Note, that JMX connect options are always shown in the help output and are not hidden. The - * {@link JmxConnect} class is used to connect to a C* node via JMX, but the opttions are not - * part of the command hierarchy to allow reusage of the commands in other contexts. + * JMX connect options (host, port, username, password, etc.) are shown in the help output for + * all commands that require a JMX connection. Commands that implement {@link org.apache.cassandra.tools.nodetool.LocalCommand} + * are known at the metadata level to run locally, and their help output suppresses the JMX options. + * Commands whose locality is only determined at runtime (e.g. {@link org.apache.cassandra.tools.nodetool.Sjk}) + * continue to show JMX options since the decision cannot be made statically. */ public class CassandraCliHelpLayout extends CommandLine.Help { @@ -257,6 +260,10 @@ private static List parentCommandOptionsWithJmxOpt if (commandSpec.helpCommand()) return Collections.emptyList(); + // If the command is a LocalCommand, it runs locally and does not need JMX connection options + // in its help output. This is a static, metadata-level check based on the class hierarchy. + boolean shouldShowJmx = !(commandSpec.userObject() instanceof LocalCommand); + List hierarhy = new LinkedList<>(); CommandLine.Model.CommandSpec curr; CommandLine.Model.CommandSpec command = commandSpec; @@ -271,11 +278,16 @@ private static List parentCommandOptionsWithJmxOpt { for (CommandLine.Model.OptionSpec option : spec.options()) { - // JmxConnect and NodetoolCommand options are always shown in the help output for backwards compatibility. + // JmxConnect options are shown for online commands only; NodetoolCommand options are always shown for backwards compatibility. if (option.userObject() instanceof Field && (((Field) option.userObject()).getDeclaringClass().equals(JmxConnect.class) || ((Field) option.userObject()).getDeclaringClass().equals(NodetoolCommand.class))) + { + if (((Field) option.userObject()).getDeclaringClass().equals(JmxConnect.class) && !shouldShowJmx) + continue; + options.add(option); + } else { if (option.hidden() || option.scopeType() == CommandLine.ScopeType.LOCAL) diff --git a/test/resources/nodetool/help/history b/test/resources/nodetool/help/history index 76eee5d057ab..dfe1b6e017f7 100644 --- a/test/resources/nodetool/help/history +++ b/test/resources/nodetool/help/history @@ -2,27 +2,8 @@ NAME nodetool history - Print previously executed nodetool commands SYNOPSIS - nodetool [(-h | --host )] [(-p | --port )] - [(-pw | --password )] - [(-pwf | --password-file )] - [(-u | --username )] history - [(-n | --number-of-commands )] + nodetool history [(-n | --number-of-commands )] OPTIONS - -h , --host - Node hostname or ip address - -n , --num , --number-of-commands Number of commands to print, defaults to 1000. - - -p , --port - Remote jmx agent port number - - -pw , --password - Remote jmx agent password - - -pwf , --password-file - Path to the JMX password file - - -u , --username - Remote jmx agent username