mirror of https://github.com/apache/cassandra
Migrate all nodetool commands from airline to picocli
Replace io.airlift:airline dependency with info.picocli:picocli across all nodetool command implementations. This migration includes: - Convert 160+ nodetool command classes from airline to picocli - Add AbstractCommand base class for commands and utility methods - Add NodetoolCommand top-level class for the cli utility - Update all command classes to use @Command, @Option, and @Parameters - Add plain text files to test command help output - Add mock test classes for improved test coverage and parse validation - Modify test infrastructure to work with picocli-based commands - Add new layouts for cli formatting to preserve backwards compatibility The migration maintains backward compatibility while providing improved command-line parsing, better help system, and more robust argument validation through picocli enhanced features. patch by Maxim Muzafarov; reviewed by Caleb Rackliffe, Dmitry Konstantinov, Stefan Miklosovic for CASSANDRA-17445
This commit is contained in:
parent
f18d5ad851
commit
94b251f3ce
|
|
@ -57,6 +57,7 @@
|
|||
<exclude name="test/conf/sstableloader_with_encryption.yaml"/>
|
||||
<exclude name="test/conf/unit-test-conf/test-native-port.yaml"/>
|
||||
<exclude name="test/resources/data/config/YamlConfigurationLoaderTest/*.yaml"/>
|
||||
<exclude name="test/resources/nodetool/help/**"/>
|
||||
<exclude name="tools/cqlstress-*.yaml"/>
|
||||
<!-- test data -->
|
||||
<exclude name="pylib/cqlshlib/test/test_authproviderhandling_config/*"/>
|
||||
|
|
|
|||
|
|
@ -98,6 +98,10 @@
|
|||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.java-diff-utils</groupId>
|
||||
<artifactId>java-diff-utils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ju-n.compile-command-annotations</groupId>
|
||||
<artifactId>compile-command-annotations</artifactId>
|
||||
|
|
|
|||
|
|
@ -121,8 +121,8 @@
|
|||
<artifactId>cassandra-accord</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>airline</artifactId>
|
||||
<groupId>info.picocli</groupId>
|
||||
<artifactId>picocli</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dropwizard.metrics</groupId>
|
||||
|
|
|
|||
|
|
@ -662,6 +662,12 @@
|
|||
<version>1.37</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.java-diff-utils</groupId>
|
||||
<artifactId>java-diff-utils</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.ant</groupId>
|
||||
<artifactId>ant-junit</artifactId>
|
||||
|
|
@ -752,15 +758,9 @@
|
|||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>airline</artifactId>
|
||||
<version>0.8</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<groupId>info.picocli</groupId>
|
||||
<artifactId>picocli</artifactId>
|
||||
<version>4.7.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
5.1
|
||||
* Migrate all nodetool commands from airline to picocli (CASSANDRA-17445)
|
||||
* Journal.TopologyUpdate should not store the local topology as it can be inferred from the global on (CASSANDRA-20785)
|
||||
* Accord: Topology serializer has a lot of repeated data, can dedup to shrink the cost (CASSANDRA-20715)
|
||||
* Stream individual files in their own transactions and hand over ownership to a parent transaction on completion (CASSANDRA-20728)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,12 @@ package org.apache.cassandra.config;
|
|||
|
||||
// checkstyle: suppress below 'blockSystemPropertyUsage'
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
|
||||
import static org.apache.cassandra.utils.LocalizeString.toUpperCaseLocalized;
|
||||
|
||||
public enum CassandraRelevantEnv
|
||||
{
|
||||
/**
|
||||
|
|
@ -28,8 +34,10 @@ public enum CassandraRelevantEnv
|
|||
*/
|
||||
JAVA_HOME ("JAVA_HOME"),
|
||||
CIRCLECI("CIRCLECI"),
|
||||
CASSANDRA_SKIP_SYNC("CASSANDRA_SKIP_SYNC")
|
||||
|
||||
CASSANDRA_SKIP_SYNC("CASSANDRA_SKIP_SYNC"),
|
||||
/** By default, the standard Cassandra CLI layout is used for backward compatibility, however,
|
||||
* the new Picocli layout can be enabled by setting this property to the {@code "picocli"}. */
|
||||
CASSANDRA_CLI_LAYOUT("CASSANDRA_CLI_LAYOUT"),
|
||||
;
|
||||
|
||||
CassandraRelevantEnv(String key)
|
||||
|
|
@ -56,4 +64,20 @@ public enum CassandraRelevantEnv
|
|||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public <T extends Enum<T>> T getEnum(boolean toUppercase, Class<T> enumClass, String defaultVal)
|
||||
{
|
||||
String value = System.getenv(key);
|
||||
value = value == null ? defaultVal : value;
|
||||
try
|
||||
{
|
||||
return Enum.valueOf(enumClass, toUppercase ? toUpperCaseLocalized(value) : value);
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
throw new ConfigurationException(String.format("Invalid value for environment variable '%s': " +
|
||||
"expected one of %s (case-insensitive) but was '%s'",
|
||||
key, Arrays.toString(enumClass.getEnumConstants()), value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.apache.cassandra.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
|
@ -87,6 +88,9 @@ public enum CassandraRelevantProperties
|
|||
CACHEABLE_MUTATION_SIZE_LIMIT("cassandra.cacheable_mutation_size_limit_bytes", convertToString(1_000_000)),
|
||||
CASSANDRA_ALLOW_SIMPLE_STRATEGY("cassandra.allow_simplestrategy"),
|
||||
CASSANDRA_AVAILABLE_PROCESSORS("cassandra.available_processors"),
|
||||
/** By default, the standard Cassandra CLI layout is used for backward compatibility, however,
|
||||
* the new Picocli layout can be enabled by setting this property to the {@code "picocli"}. */
|
||||
CASSANDRA_CLI_LAYOUT("cassandra.cli.layout", "airline"),
|
||||
/** The classpath storage configuration file. */
|
||||
CASSANDRA_CONFIG("cassandra.config", "cassandra.yaml"),
|
||||
/**
|
||||
|
|
@ -1002,8 +1006,17 @@ public enum CassandraRelevantProperties
|
|||
public <T extends Enum<T>> T getEnum(boolean toUppercase, Class<T> enumClass)
|
||||
{
|
||||
String value = System.getProperty(key, defaultVal);
|
||||
try
|
||||
{
|
||||
return Enum.valueOf(enumClass, toUppercase ? toUpperCaseLocalized(value) : value);
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
throw new ConfigurationException(String.format("Invalid value for system propery '%s': " +
|
||||
"expected one of %s (case-insensitive) but was '%s'",
|
||||
key, Arrays.toString(enumClass.getEnumConstants()), value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value into system properties.
|
||||
|
|
|
|||
|
|
@ -469,16 +469,16 @@ public class SSTableImporter
|
|||
|
||||
public static class Options
|
||||
{
|
||||
private final Set<String> srcPaths;
|
||||
private final boolean resetLevel;
|
||||
private final boolean clearRepaired;
|
||||
private final boolean verifySSTables;
|
||||
private final boolean verifyTokens;
|
||||
private final boolean invalidateCaches;
|
||||
private final boolean extendedVerify;
|
||||
private final boolean copyData;
|
||||
private final boolean failOnMissingIndex;
|
||||
public final boolean validateIndexChecksum;
|
||||
final Set<String> srcPaths;
|
||||
final boolean resetLevel;
|
||||
final boolean clearRepaired;
|
||||
final boolean verifySSTables;
|
||||
final boolean verifyTokens;
|
||||
final boolean invalidateCaches;
|
||||
final boolean extendedVerify;
|
||||
final boolean copyData;
|
||||
final boolean failOnMissingIndex;
|
||||
final boolean validateIndexChecksum;
|
||||
|
||||
public Options(Set<String> srcPaths, boolean resetLevel, boolean clearRepaired,
|
||||
boolean verifySSTables, boolean verifyTokens, boolean invalidateCaches,
|
||||
|
|
@ -523,9 +523,9 @@ public class SSTableImporter
|
|||
", verifyTokens=" + verifyTokens +
|
||||
", invalidateCaches=" + invalidateCaches +
|
||||
", extendedVerify=" + extendedVerify +
|
||||
", copyData= " + copyData +
|
||||
", failOnMissingIndex= " + failOnMissingIndex +
|
||||
", validateIndexChecksum= " + validateIndexChecksum +
|
||||
", copyData=" + copyData +
|
||||
", failOnMissingIndex=" + failOnMissingIndex +
|
||||
", validateIndexChecksum=" + validateIndexChecksum +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import java.util.function.BiConsumer;
|
|||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.inject.Inject;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
|
|
@ -62,14 +61,7 @@ import com.google.common.collect.Sets;
|
|||
import com.google.common.collect.Sets.SetView;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Cli;
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Help;
|
||||
import io.airlift.airline.HelpOption;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.config.YamlConfigurationLoader;
|
||||
import org.apache.cassandra.io.util.File;
|
||||
import org.apache.cassandra.io.util.FileInputStreamPlus;
|
||||
import org.apache.cassandra.utils.JsonUtils;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
|
|
@ -80,8 +72,14 @@ import org.yaml.snakeyaml.nodes.MappingNode;
|
|||
import org.yaml.snakeyaml.nodes.Node;
|
||||
import org.yaml.snakeyaml.nodes.Tag;
|
||||
import org.yaml.snakeyaml.representer.Representer;
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
public class JMXTool
|
||||
@Command(name = "jmxtool", description = "JMX tool for Apache Cassandra",
|
||||
mixinStandardHelpOptions = true,
|
||||
subcommands = { CommandLine.HelpCommand.class, JMXTool.Dump.class, JMXTool.Diff.class })
|
||||
public class JMXTool implements Callable<Void>
|
||||
{
|
||||
private static final List<String> METRIC_PACKAGES = Arrays.asList("org.apache.cassandra.metrics",
|
||||
"org.apache.cassandra.db",
|
||||
|
|
@ -109,16 +107,20 @@ public class JMXTool
|
|||
return rc;
|
||||
};
|
||||
|
||||
@Command(name = "dump", description = "Dump the Apache Cassandra JMX objects and metadata.")
|
||||
@Override
|
||||
public Void call() throws Exception
|
||||
{
|
||||
CommandLine.usage(this, System.out);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Command(name = "dump", description = "Dump the Apache Cassandra JMX objects and metadata.", mixinStandardHelpOptions = true)
|
||||
public static final class Dump implements Callable<Void>
|
||||
{
|
||||
@Inject
|
||||
private HelpOption helpOption;
|
||||
|
||||
@Option(title = "url", name = { "-u", "--url" }, description = "JMX url to target")
|
||||
@Option(paramLabel = "url", names = { "-u", "--url" }, description = "JMX url to target")
|
||||
private String targetUrl = "service:jmx:rmi:///jndi/rmi://localhost:7199/jmxrmi";
|
||||
|
||||
@Option(title = "format", name = { "-f", "--format" }, description = "What format to dump content as; supported values are console (default), json, and yaml")
|
||||
@Option(paramLabel = "format", names = { "-f", "--format" }, description = "What format to dump content as; supported values are console (default), json, and yaml")
|
||||
private Format format = Format.console;
|
||||
|
||||
public Void call() throws Exception
|
||||
|
|
@ -188,41 +190,32 @@ public class JMXTool
|
|||
}
|
||||
}
|
||||
|
||||
@Command(name = "diff", description = "Diff two jmx dump files and report their differences")
|
||||
@Command(name = "diff", description = "Diff two jmx dump files and report their differences", mixinStandardHelpOptions = true)
|
||||
public static final class Diff implements Callable<Void>
|
||||
{
|
||||
@Inject
|
||||
private HelpOption helpOption;
|
||||
@CommandLine.Parameters(description = "Files to diff")
|
||||
private List<String> files;
|
||||
|
||||
@Arguments(title = "files", usage = "<left> <right>", description = "Files to diff")
|
||||
private List<File> files;
|
||||
|
||||
@Option(title = "format", name = { "-f", "--format" }, description = "What format the files are in; only support json and yaml as format")
|
||||
@Option(paramLabel = "format", names = { "-f", "--format" }, description = "What format the files are in; only support json and yaml as format")
|
||||
private Format format = Format.yaml;
|
||||
|
||||
@Option(title = "ignore left", name = { "--ignore-missing-on-left" }, description = "Ignore results missing on the left")
|
||||
@Option(paramLabel = "ignore_left", names = { "--ignore-missing-on-left" }, description = "Ignore results missing on the left")
|
||||
private boolean ignoreMissingLeft;
|
||||
|
||||
@Option(title = "ignore right", name = { "--ignore-missing-on-right" }, description = "Ignore results missing on the right")
|
||||
@Option(paramLabel = "ignore_right", names = { "--ignore-missing-on-right" }, description = "Ignore results missing on the right")
|
||||
private boolean ignoreMissingRight;
|
||||
|
||||
@Option(title = "exclude objects", name = "--exclude-object", description
|
||||
= "Ignores processing specific objects. " +
|
||||
"Each usage should take a single object, " +
|
||||
"but can use this flag multiple times.")
|
||||
private List<CliPattern> excludeObjects = new ArrayList<>();
|
||||
@Option(paramLabel = "exclude_objects", names = "--exclude-object", converter = PatternConverter.class,
|
||||
description = "Ignores processing specific objects. Each usage should take a single object, but can use this flag multiple times.")
|
||||
private List<Pattern> excludeObjects = new ArrayList<>();
|
||||
|
||||
@Option(title = "exclude attributes", name = "--exclude-attribute", description
|
||||
= "Ignores processing specific attributes. " +
|
||||
"Each usage should take a single attribute, " +
|
||||
"but can use this flag multiple times.")
|
||||
private List<CliPattern> excludeAttributes = new ArrayList<>();
|
||||
@Option(paramLabel = "exclude_attributes", names = "--exclude-attribute", converter = PatternConverter.class,
|
||||
description = "Ignores processing specific attributes. Each usage should take a single attribute, but can use this flag multiple times.")
|
||||
private List<Pattern> excludeAttributes = new ArrayList<>();
|
||||
|
||||
@Option(title = "exclude operations", name = "--exclude-operation", description
|
||||
= "Ignores processing specific operations. " +
|
||||
"Each usage should take a single operation, " +
|
||||
"but can use this flag multiple times.")
|
||||
private List<CliPattern> excludeOperations = new ArrayList<>();
|
||||
@Option(paramLabel = "exclud_operations", names = "--exclude-operation", converter = PatternConverter.class,
|
||||
description = "Ignores processing specific operations. Each usage should take a single operation, but can use this flag multiple times.")
|
||||
private List<Pattern> excludeOperations = new ArrayList<>();
|
||||
|
||||
public Void call() throws Exception
|
||||
{
|
||||
|
|
@ -243,9 +236,9 @@ public class JMXTool
|
|||
private void diff(Map<String, Info> left, Map<String, Info> right)
|
||||
{
|
||||
DiffResult<String> objectNames = diff(left.keySet(), right.keySet(), name -> {
|
||||
for (CliPattern p : excludeObjects)
|
||||
for (Pattern p : excludeObjects)
|
||||
{
|
||||
if (p.pattern.matcher(name).matches())
|
||||
if (p.matcher(name).matches())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -280,9 +273,9 @@ public class JMXTool
|
|||
Info leftInfo = left.get(key);
|
||||
Info rightInfo = right.get(key);
|
||||
DiffResult<Attribute> attributes = diff(leftInfo.attributeSet(), rightInfo.attributeSet(), attribute -> {
|
||||
for (CliPattern p : excludeAttributes)
|
||||
for (Pattern p : excludeAttributes)
|
||||
{
|
||||
if (p.pattern.matcher(attribute.name).matches())
|
||||
if (p.matcher(attribute.name).matches())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -301,10 +294,10 @@ public class JMXTool
|
|||
}
|
||||
|
||||
DiffResult<Operation> operations = diff(leftInfo.operationSet(), rightInfo.operationSet(), operation -> {
|
||||
for (CliPattern p : excludeOperations)
|
||||
for (Pattern p : excludeOperations)
|
||||
{
|
||||
if (p.pattern.matcher(operation.name).matches() ||
|
||||
p.pattern.matcher(operation.toString().replaceAll(" +", "")).matches())
|
||||
if (p.matcher(operation.name).matches() ||
|
||||
p.matcher(operation.toString().replaceAll(" +", "")).matches())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -844,24 +837,18 @@ public class JMXTool
|
|||
}
|
||||
}
|
||||
|
||||
public static final class CliPattern
|
||||
public static class PatternConverter implements CommandLine.ITypeConverter<Pattern>
|
||||
{
|
||||
private final Pattern pattern;
|
||||
|
||||
public CliPattern(String pattern)
|
||||
@Override
|
||||
public Pattern convert(String pattern) throws Exception
|
||||
{
|
||||
this.pattern = Pattern.compile(pattern);
|
||||
return Pattern.compile(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
Cli.CliBuilder<Callable<Void>> builder = Cli.builder("jmxtool");
|
||||
builder.withDefaultCommand(Help.class);
|
||||
builder.withCommands(Help.class, Dump.class, Diff.class);
|
||||
|
||||
Cli<Callable<Void>> parser = builder.build();
|
||||
Callable<Void> command = parser.parse(args);
|
||||
command.call();
|
||||
CommandLine commandLine = new CommandLine(JMXTool.class);
|
||||
commandLine.execute(args);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,6 @@ import org.apache.cassandra.service.AutoRepairService;
|
|||
import org.apache.cassandra.service.AutoRepairServiceMBean;
|
||||
import org.apache.cassandra.service.CacheService;
|
||||
import org.apache.cassandra.service.CacheServiceMBean;
|
||||
import org.apache.cassandra.service.snapshot.SnapshotManagerMBean;
|
||||
import org.apache.cassandra.service.GCInspector;
|
||||
import org.apache.cassandra.service.GCInspectorMXBean;
|
||||
import org.apache.cassandra.service.StorageProxy;
|
||||
|
|
@ -126,6 +125,7 @@ import org.apache.cassandra.service.StorageProxyMBean;
|
|||
import org.apache.cassandra.service.StorageServiceMBean;
|
||||
import org.apache.cassandra.service.accord.AccordOperations;
|
||||
import org.apache.cassandra.service.accord.AccordOperationsMBean;
|
||||
import org.apache.cassandra.service.snapshot.SnapshotManagerMBean;
|
||||
import org.apache.cassandra.streaming.StreamManagerMBean;
|
||||
import org.apache.cassandra.streaming.StreamState;
|
||||
import org.apache.cassandra.streaming.management.StreamStateCompositeData;
|
||||
|
|
@ -133,7 +133,6 @@ import org.apache.cassandra.tcm.CMSOperations;
|
|||
import org.apache.cassandra.tcm.CMSOperationsMBean;
|
||||
import org.apache.cassandra.tools.RepairRunner.RepairCmd;
|
||||
import org.apache.cassandra.tools.nodetool.GetTimeout;
|
||||
import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
|
||||
import org.apache.cassandra.utils.NativeLibrary;
|
||||
|
||||
import static org.apache.cassandra.config.CassandraRelevantProperties.NODETOOL_JMX_NOTIFICATION_POLL_INTERVAL_SECONDS;
|
||||
|
|
@ -146,7 +145,7 @@ public class NodeProbe implements AutoCloseable
|
|||
{
|
||||
private static final String fmtUrl = "service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi";
|
||||
private static final String ssObjName = "org.apache.cassandra.db:type=StorageService";
|
||||
private static final int defaultPort = 7199;
|
||||
public static final int defaultPort = 7199;
|
||||
|
||||
static long JMX_NOTIFICATION_POLL_INTERVAL_SECONDS = NODETOOL_JMX_NOTIFICATION_POLL_INTERVAL_SECONDS.getLong();
|
||||
|
||||
|
|
@ -185,8 +184,7 @@ public class NodeProbe implements AutoCloseable
|
|||
protected RolesCacheMBean rcProxy;
|
||||
protected AutoRepairServiceMBean autoRepairProxy;
|
||||
protected GuardrailsMBean grProxy;
|
||||
protected Output output;
|
||||
private boolean failed;
|
||||
protected volatile Output output;
|
||||
|
||||
protected CIDRFilteringMetricsTableMBean cfmProxy;
|
||||
|
||||
|
|
@ -469,9 +467,8 @@ public class NodeProbe implements AutoCloseable
|
|||
jobName, ks);
|
||||
break;
|
||||
case 2:
|
||||
failed = true;
|
||||
out.printf("Failed marking some sstables compacting in keyspace %s, check server logs for more information.\n",
|
||||
ks);
|
||||
out.printf("Failed marking some sstables compacting in keyspace %s, check server logs for more information.\n", ks);
|
||||
throw new RuntimeException(String.format("Failed marking some sstables compacting in keyspace %s, check server logs for more information.\n", ks));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -479,8 +476,8 @@ public class NodeProbe implements AutoCloseable
|
|||
{
|
||||
if (garbageCollect(tombstoneOption, jobs, keyspaceName, tableNames) != 0)
|
||||
{
|
||||
failed = true;
|
||||
out.println("Aborted garbage collection for at least one table in keyspace " + keyspaceName + ", check server logs for more information.");
|
||||
throw new RuntimeException("Aborted garbage collection for at least one table in keyspace " + keyspaceName + ", check server logs for more information.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1819,16 +1816,6 @@ public class NodeProbe implements AutoCloseable
|
|||
ssProxy.reloadLocalSchema();
|
||||
}
|
||||
|
||||
public boolean isFailed()
|
||||
{
|
||||
return failed;
|
||||
}
|
||||
|
||||
public void failed()
|
||||
{
|
||||
this.failed = true;
|
||||
}
|
||||
|
||||
public long getReadRepairAttempted()
|
||||
{
|
||||
return spProxy.getReadRepairAttempted();
|
||||
|
|
@ -2546,21 +2533,6 @@ public class NodeProbe implements AutoCloseable
|
|||
return ssProxy.getDefaultKeyspaceReplicationFactor();
|
||||
}
|
||||
|
||||
public void printSet(PrintStream out, String colName, Set<String> values)
|
||||
{
|
||||
if (values == null || values.isEmpty())
|
||||
return;
|
||||
|
||||
TableBuilder table = new TableBuilder();
|
||||
|
||||
table.add(colName + ": ");
|
||||
|
||||
for (String value : values)
|
||||
table.add(value);
|
||||
|
||||
table.printTo(out);
|
||||
}
|
||||
|
||||
public void abortBootstrap(String nodeId, String endpoint)
|
||||
{
|
||||
ssProxy.abortBootstrap(nodeId, endpoint);
|
||||
|
|
|
|||
|
|
@ -17,54 +17,34 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools;
|
||||
|
||||
import java.io.Console;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Field;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Scanner;
|
||||
import java.util.SortedMap;
|
||||
import javax.inject.Inject;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import io.airlift.airline.Cli;
|
||||
import io.airlift.airline.Help;
|
||||
import io.airlift.airline.Option;
|
||||
import io.airlift.airline.OptionType;
|
||||
import io.airlift.airline.ParseArgumentsMissingException;
|
||||
import io.airlift.airline.ParseArgumentsUnexpectedException;
|
||||
import io.airlift.airline.ParseCommandMissingException;
|
||||
import io.airlift.airline.ParseCommandUnrecognizedException;
|
||||
import io.airlift.airline.ParseOptionConversionException;
|
||||
import io.airlift.airline.ParseOptionMissingException;
|
||||
import io.airlift.airline.ParseOptionMissingValueException;
|
||||
import org.apache.cassandra.config.CassandraRelevantEnv;
|
||||
import org.apache.cassandra.config.CassandraRelevantProperties;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.io.util.File;
|
||||
import org.apache.cassandra.io.util.FileWriter;
|
||||
import org.apache.cassandra.locator.EndpointSnitchInfoMBean;
|
||||
import org.apache.cassandra.tools.nodetool.*;
|
||||
import org.apache.cassandra.tools.nodetool.JmxConnect;
|
||||
import org.apache.cassandra.tools.nodetool.NodetoolCommand;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraCliHelpLayout;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import picocli.CommandLine;
|
||||
|
||||
import static com.google.common.base.Throwables.getStackTraceAsString;
|
||||
import static com.google.common.collect.Iterables.toArray;
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static java.lang.Integer.parseInt;
|
||||
import static java.lang.String.format;
|
||||
import static org.apache.cassandra.io.util.File.WriteMode.APPEND;
|
||||
import static org.apache.commons.lang3.ArrayUtils.EMPTY_STRING_ARRAY;
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
import static org.apache.commons.lang3.StringUtils.isEmpty;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
|
||||
import static org.apache.cassandra.utils.LocalizeString.toUpperCaseLocalized;
|
||||
|
||||
public class NodeTool
|
||||
{
|
||||
|
|
@ -89,237 +69,59 @@ public class NodeTool
|
|||
this.output = output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the command line utility with the given arguments via the JMX connection.
|
||||
*
|
||||
* @param args command line arguments
|
||||
* @return 0 on success, 1 on bad use, 2 on execution error
|
||||
*/
|
||||
public int execute(String... args)
|
||||
{
|
||||
List<Class<? extends NodeToolCmdRunnable>> commands = newArrayList(
|
||||
AbortBootstrap.class,
|
||||
AlterTopology.class,
|
||||
Assassinate.class,
|
||||
AutoRepairStatus.class,
|
||||
CassHelp.class,
|
||||
CIDRFilteringStats.class,
|
||||
Cleanup.class,
|
||||
ClearSnapshot.class,
|
||||
ClientStats.class,
|
||||
Compact.class,
|
||||
CompactionHistory.class,
|
||||
CompactionStats.class,
|
||||
DataPaths.class,
|
||||
Decommission.class,
|
||||
Decommission.Abort.class,
|
||||
DescribeCluster.class,
|
||||
DescribeRing.class,
|
||||
DisableAuditLog.class,
|
||||
DisableAutoCompaction.class,
|
||||
DisableBackup.class,
|
||||
DisableBinary.class,
|
||||
DisableFullQueryLog.class,
|
||||
DisableGossip.class,
|
||||
DisableHandoff.class,
|
||||
DisableHintsForDC.class,
|
||||
DisableOldProtocolVersions.class,
|
||||
Drain.class,
|
||||
DropCIDRGroup.class,
|
||||
EnableAuditLog.class,
|
||||
EnableAutoCompaction.class,
|
||||
EnableBackup.class,
|
||||
EnableBinary.class,
|
||||
EnableFullQueryLog.class,
|
||||
EnableGossip.class,
|
||||
EnableHandoff.class,
|
||||
EnableHintsForDC.class,
|
||||
EnableOldProtocolVersions.class,
|
||||
FailureDetectorInfo.class,
|
||||
Flush.class,
|
||||
GarbageCollect.class,
|
||||
GcStats.class,
|
||||
GetAuditLog.class,
|
||||
GetAuthCacheConfig.class,
|
||||
GetAutoRepairConfig.class,
|
||||
GetBatchlogReplayTrottle.class,
|
||||
GetCIDRGroupsOfIP.class,
|
||||
GetColumnIndexSize.class,
|
||||
GetCompactionThreshold.class,
|
||||
GetCompactionThroughput.class,
|
||||
GetConcurrency.class,
|
||||
GetConcurrentCompactors.class,
|
||||
GetConcurrentViewBuilders.class,
|
||||
GetDefaultKeyspaceRF.class,
|
||||
GetEndpoints.class,
|
||||
GetFullQueryLog.class,
|
||||
GuardrailsConfigCommand.GetGuardrailsConfig.class,
|
||||
GetInterDCStreamThroughput.class,
|
||||
GetLoggingLevels.class,
|
||||
GetMaxHintWindow.class,
|
||||
GetSSTables.class,
|
||||
GetSeeds.class,
|
||||
GetSnapshotThrottle.class,
|
||||
GetStreamThroughput.class,
|
||||
GetTimeout.class,
|
||||
GetTraceProbability.class,
|
||||
GossipInfo.class,
|
||||
Import.class,
|
||||
Info.class,
|
||||
InvalidateCIDRPermissionsCache.class,
|
||||
InvalidateCounterCache.class,
|
||||
InvalidateCredentialsCache.class,
|
||||
InvalidateJmxPermissionsCache.class,
|
||||
ReloadCIDRGroupsCache.class,
|
||||
InvalidateKeyCache.class,
|
||||
InvalidateNetworkPermissionsCache.class,
|
||||
InvalidatePermissionsCache.class,
|
||||
InvalidateRolesCache.class,
|
||||
InvalidateRowCache.class,
|
||||
Join.class,
|
||||
ListCIDRGroups.class,
|
||||
ListPendingHints.class,
|
||||
ListSnapshots.class,
|
||||
Move.class,
|
||||
Move.Abort.class,
|
||||
NetStats.class,
|
||||
PauseHandoff.class,
|
||||
ProfileLoad.class,
|
||||
ProxyHistograms.class,
|
||||
RangeKeySample.class,
|
||||
Rebuild.class,
|
||||
RebuildIndex.class,
|
||||
RecompressSSTables.class,
|
||||
Refresh.class,
|
||||
RefreshSizeEstimates.class,
|
||||
ReloadLocalSchema.class,
|
||||
ReloadSeeds.class,
|
||||
ReloadSslCertificates.class,
|
||||
ReloadTriggers.class,
|
||||
RelocateSSTables.class,
|
||||
RemoveNode.class,
|
||||
RemoveNode.Abort.class,
|
||||
Repair.class,
|
||||
ReplayBatchlog.class,
|
||||
ResetFullQueryLog.class,
|
||||
ResetLocalSchema.class,
|
||||
ResumeHandoff.class,
|
||||
Ring.class,
|
||||
Scrub.class,
|
||||
SetAuthCacheConfig.class,
|
||||
SetAutoRepairConfig.class,
|
||||
SetBatchlogReplayThrottle.class,
|
||||
SetCacheCapacity.class,
|
||||
SetCacheKeysToSave.class,
|
||||
SetColumnIndexSize.class,
|
||||
SetCompactionThreshold.class,
|
||||
SetCompactionThroughput.class,
|
||||
SetConcurrency.class,
|
||||
SetConcurrentCompactors.class,
|
||||
SetConcurrentViewBuilders.class,
|
||||
SetDefaultKeyspaceRF.class,
|
||||
GuardrailsConfigCommand.SetGuardrailsConfig.class,
|
||||
SetHintedHandoffThrottleInKB.class,
|
||||
SetInterDCStreamThroughput.class,
|
||||
SetLoggingLevel.class,
|
||||
SetMaxHintWindow.class,
|
||||
SetSnapshotThrottle.class,
|
||||
SetStreamThroughput.class,
|
||||
SetTimeout.class,
|
||||
SetTraceProbability.class,
|
||||
Sjk.class,
|
||||
Snapshot.class,
|
||||
SSTableRepairedSet.class,
|
||||
Status.class,
|
||||
StatusAutoCompaction.class,
|
||||
StatusBackup.class,
|
||||
StatusBinary.class,
|
||||
StatusGossip.class,
|
||||
StatusHandoff.class,
|
||||
Stop.class,
|
||||
StopDaemon.class,
|
||||
TableHistograms.class,
|
||||
TableStats.class,
|
||||
TopPartitions.class,
|
||||
TpStats.class,
|
||||
TruncateHints.class,
|
||||
UpdateCIDRGroup.class,
|
||||
UpgradeSSTable.class,
|
||||
Verify.class,
|
||||
Version.class,
|
||||
ViewBuildStatus.class,
|
||||
ForceCompact.class
|
||||
);
|
||||
|
||||
Cli.CliBuilder<NodeToolCmdRunnable> builder = Cli.builder("nodetool");
|
||||
|
||||
builder.withDescription("Manage your Cassandra cluster")
|
||||
.withDefaultCommand(CassHelp.class)
|
||||
.withCommands(commands);
|
||||
|
||||
// bootstrap commands
|
||||
builder.withGroup("bootstrap")
|
||||
.withDescription("Monitor/manage node's bootstrap process")
|
||||
.withDefaultCommand(CassHelp.class)
|
||||
.withCommand(BootstrapResume.class);
|
||||
|
||||
builder.withGroup("repair_admin")
|
||||
.withDescription("list and fail incremental repair sessions")
|
||||
.withDefaultCommand(RepairAdmin.ListCmd.class)
|
||||
.withCommand(RepairAdmin.ListCmd.class)
|
||||
.withCommand(RepairAdmin.CancelCmd.class)
|
||||
.withCommand(RepairAdmin.CleanupDataCmd.class)
|
||||
.withCommand(RepairAdmin.SummarizePendingCmd.class)
|
||||
.withCommand(RepairAdmin.SummarizeRepairedCmd.class);
|
||||
|
||||
builder.withGroup("cms")
|
||||
.withDescription("Manage cluster metadata")
|
||||
.withDefaultCommand(CMSAdmin.DescribeCMS.class)
|
||||
.withCommand(CMSAdmin.DescribeCMS.class)
|
||||
.withCommand(CMSAdmin.InitializeCMS.class)
|
||||
.withCommand(CMSAdmin.ReconfigureCMS.class)
|
||||
.withCommand(CMSAdmin.Snapshot.class)
|
||||
.withCommand(CMSAdmin.Unregister.class)
|
||||
.withCommand(CMSAdmin.AbortInitialization.class)
|
||||
.withCommand(CMSAdmin.DumpDirectory.class)
|
||||
.withCommand(CMSAdmin.DumpLog.class)
|
||||
.withCommand(CMSAdmin.ResumeDropAccordTable.class);
|
||||
|
||||
builder.withGroup("consensus_admin")
|
||||
.withDescription("List and mark ranges as migrating between consensus protocols")
|
||||
.withDefaultCommand(CassHelp.class)
|
||||
.withCommand(ConsensusMigrationAdmin.BeginMigration.class)
|
||||
.withCommands(ConsensusMigrationAdmin.ListCmd.class)
|
||||
.withCommands(ConsensusMigrationAdmin.FinishMigration.class);
|
||||
|
||||
builder.withGroup("accord")
|
||||
.withDescription("Manage the operation of Accord")
|
||||
.withDefaultCommand(AccordAdmin.Describe.class)
|
||||
.withCommand(AccordAdmin.Describe.class)
|
||||
.withCommand(AccordAdmin.MarkStale.class)
|
||||
.withCommand(AccordAdmin.MarkRejoining.class);
|
||||
|
||||
Cli<NodeToolCmdRunnable> parser = builder.build();
|
||||
|
||||
int status = 0;
|
||||
try
|
||||
{
|
||||
NodeToolCmdRunnable parse = parser.parse(args);
|
||||
printHistory(args);
|
||||
parse.run(nodeProbeFactory, output);
|
||||
} catch (IllegalArgumentException |
|
||||
IllegalStateException |
|
||||
ParseArgumentsMissingException |
|
||||
ParseArgumentsUnexpectedException |
|
||||
ParseOptionConversionException |
|
||||
ParseOptionMissingException |
|
||||
ParseOptionMissingValueException |
|
||||
ParseCommandMissingException |
|
||||
ParseCommandUnrecognizedException e)
|
||||
CommandLine commandLine = createCommandLine(new CassandraCliFactory(nodeProbeFactory, output));
|
||||
commandLine.setOut(new PrintWriter(output.out, true));
|
||||
commandLine.setErr(new PrintWriter(output.err, true));
|
||||
|
||||
configureCliLayout(commandLine);
|
||||
commandLine.setExecutionStrategy(JmxConnect::executionStrategy)
|
||||
.setExecutionExceptionHandler((ex, c, arg) -> {
|
||||
// Used for backward compatibility, some commands are validated when a command is run.
|
||||
if (ex instanceof IllegalArgumentException |
|
||||
ex instanceof IllegalStateException)
|
||||
{
|
||||
badUse(e);
|
||||
status = 1;
|
||||
} catch (Throwable throwable)
|
||||
{
|
||||
err(Throwables.getRootCause(throwable));
|
||||
status = 2;
|
||||
badUse(ex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return status;
|
||||
err(Throwables.getRootCause(ex));
|
||||
return 2;
|
||||
})
|
||||
.setParameterExceptionHandler((ex, arg) -> {
|
||||
badUse(ex);
|
||||
return 1;
|
||||
})
|
||||
// Some of the Cassandra commands don't comply with the POSIX standard, so we need to disable such options.
|
||||
// Example: ./nodetool -h localhost -p 7100 repair mykeyspayce -hosts 127.0.0.1,127.0.0.2
|
||||
//
|
||||
// This also means that option parameters must be separated from the option name by whitespace
|
||||
// or the = separator character, so -D key=value and -D=key=value will be recognized but
|
||||
// -Dkey=value will not.
|
||||
.setPosixClusteredShortOptionsAllowed(false);
|
||||
|
||||
printHistory(args);
|
||||
return commandLine.execute(args);
|
||||
}
|
||||
catch (ConfigurationException e)
|
||||
{
|
||||
badUse(e);
|
||||
return 1;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
err(Throwables.getRootCause(e));
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
private static void printHistory(String... args)
|
||||
|
|
@ -342,6 +144,59 @@ public class NodeTool
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static List<String> getCommandsWithoutRoot(String separator)
|
||||
{
|
||||
List<String> commands = new ArrayList<>();
|
||||
try
|
||||
{
|
||||
getCommandsWithoutRoot(createCommandLine(new CassandraCliFactory(new NodeProbeFactory(), Output.CONSOLE)), commands, separator);
|
||||
return commands;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException("Failed to initialize command line hierarchy", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void getCommandsWithoutRoot(CommandLine cli, List<String> commands, String separator)
|
||||
{
|
||||
String name = cli.getCommandSpec().qualifiedName(separator);
|
||||
// Skip the root command as it's not a real command.
|
||||
if (cli.getCommandSpec().root() != cli.getCommandSpec())
|
||||
commands.add(name.replace(cli.getCommandSpec().root().qualifiedName() + separator, ""));
|
||||
for (CommandLine sub : cli.getSubcommands().values())
|
||||
getCommandsWithoutRoot(sub, commands, separator);
|
||||
}
|
||||
|
||||
public static CommandLine createCommandLine(CommandLine.IFactory factory) throws Exception
|
||||
{
|
||||
return new CommandLine(new NodetoolCommand(), factory)
|
||||
.addMixin(JmxConnect.MIXIN_KEY, factory.create(JmxConnect.class));
|
||||
}
|
||||
|
||||
private static void configureCliLayout(CommandLine commandLine)
|
||||
{
|
||||
CliLayout defaultLayout = CliLayout.valueOf(toUpperCaseLocalized(CassandraRelevantProperties.CASSANDRA_CLI_LAYOUT.getDefaultValue()));
|
||||
CliLayout layoutEnv = CassandraRelevantEnv.CASSANDRA_CLI_LAYOUT.getEnum(true, CliLayout.class,
|
||||
CassandraRelevantProperties.CASSANDRA_CLI_LAYOUT.getDefaultValue());
|
||||
CliLayout layoutSys = CassandraRelevantProperties.CASSANDRA_CLI_LAYOUT.getEnum(true, CliLayout.class);
|
||||
CliLayout layout = layoutEnv != defaultLayout ? layoutEnv : layoutSys;
|
||||
|
||||
switch (layout)
|
||||
{
|
||||
case AIRLINE:
|
||||
commandLine.setHelpFactory(CassandraCliHelpLayout::new)
|
||||
.setUsageHelpWidth(CassandraCliHelpLayout.DEFAULT_USAGE_HELP_WIDTH)
|
||||
.setHelpSectionKeys(CassandraCliHelpLayout.cassandraHelpSectionKeys());
|
||||
break;
|
||||
case PICOCLI:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown CLI layout: " + layout);
|
||||
}
|
||||
}
|
||||
|
||||
protected void badUse(Exception e)
|
||||
{
|
||||
output.out.println("nodetool: " + e.getMessage());
|
||||
|
|
@ -359,208 +214,63 @@ public class NodeTool
|
|||
output.err.println(getStackTraceAsString(e));
|
||||
}
|
||||
|
||||
public static class CassHelp extends Help implements NodeToolCmdRunnable
|
||||
private enum CliLayout
|
||||
{
|
||||
public void run(INodeProbeFactory nodeProbeFactory, Output output)
|
||||
{
|
||||
run();
|
||||
}
|
||||
AIRLINE,
|
||||
PICOCLI
|
||||
}
|
||||
|
||||
interface NodeToolCmdRunnable
|
||||
private static class CassandraCliFactory implements CommandLine.IFactory
|
||||
{
|
||||
void run(INodeProbeFactory nodeProbeFactory, Output output);
|
||||
}
|
||||
private final CommandLine.IFactory fallback;
|
||||
private final INodeProbeFactory nodeProbeFactory;
|
||||
private final Output output;
|
||||
|
||||
public static abstract class NodeToolCmd implements NodeToolCmdRunnable
|
||||
{
|
||||
|
||||
@Option(type = OptionType.GLOBAL, name = {"-h", "--host"}, description = "Node hostname or ip address")
|
||||
private String host = "127.0.0.1";
|
||||
|
||||
@Option(type = OptionType.GLOBAL, name = {"-p", "--port"}, description = "Remote jmx agent port number")
|
||||
private String port = "7199";
|
||||
|
||||
@Option(type = OptionType.GLOBAL, name = {"-u", "--username"}, description = "Remote jmx agent username")
|
||||
private String username = EMPTY;
|
||||
|
||||
@Option(type = OptionType.GLOBAL, name = {"-pw", "--password"}, description = "Remote jmx agent password")
|
||||
private String password = EMPTY;
|
||||
|
||||
@Option(type = OptionType.GLOBAL, name = {"-pwf", "--password-file"}, description = "Path to the JMX password file")
|
||||
private String passwordFilePath = EMPTY;
|
||||
|
||||
@Option(type = OptionType.GLOBAL, name = { "-pp", "--print-port"}, description = "Operate in 4.0 mode with hosts disambiguated by port number", arity = 0)
|
||||
protected boolean printPort = false;
|
||||
|
||||
private INodeProbeFactory nodeProbeFactory;
|
||||
protected Output output;
|
||||
|
||||
@Override
|
||||
public void run(INodeProbeFactory nodeProbeFactory, Output output)
|
||||
public CassandraCliFactory(INodeProbeFactory nodeProbeFactory, Output output)
|
||||
{
|
||||
this.fallback = CommandLine.defaultFactory();
|
||||
this.nodeProbeFactory = nodeProbeFactory;
|
||||
this.output = output;
|
||||
runInternal();
|
||||
}
|
||||
|
||||
public void runInternal()
|
||||
public <K> K create(Class<K> cls)
|
||||
{
|
||||
if (isNotEmpty(username)) {
|
||||
if (isNotEmpty(passwordFilePath))
|
||||
password = readUserPasswordFromFile(username, passwordFilePath);
|
||||
|
||||
if (isEmpty(password))
|
||||
password = promptAndReadPassword();
|
||||
}
|
||||
|
||||
try (NodeProbe probe = connect())
|
||||
{
|
||||
execute(probe);
|
||||
if (probe.isFailed())
|
||||
throw new RuntimeException("nodetool failed, check server logs");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException("Error while closing JMX connection", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String readUserPasswordFromFile(String username, String passwordFilePath) {
|
||||
String password = EMPTY;
|
||||
|
||||
File passwordFile = new File(passwordFilePath);
|
||||
try (Scanner scanner = new Scanner(passwordFile.toJavaIOFile()).useDelimiter("\\s+"))
|
||||
{
|
||||
while (scanner.hasNextLine())
|
||||
{
|
||||
if (scanner.hasNext())
|
||||
{
|
||||
String jmxRole = scanner.next();
|
||||
if (jmxRole.equals(username) && scanner.hasNext())
|
||||
{
|
||||
password = scanner.next();
|
||||
break;
|
||||
}
|
||||
}
|
||||
scanner.nextLine();
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
private String promptAndReadPassword()
|
||||
{
|
||||
String password = EMPTY;
|
||||
|
||||
Console console = System.console();
|
||||
if (console != null)
|
||||
password = String.valueOf(console.readPassword("Password:"));
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
protected abstract void execute(NodeProbe probe);
|
||||
|
||||
private NodeProbe connect()
|
||||
{
|
||||
NodeProbe nodeClient = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (username.isEmpty())
|
||||
nodeClient = nodeProbeFactory.create(host, parseInt(port));
|
||||
else
|
||||
nodeClient = nodeProbeFactory.create(host, parseInt(port), username, password);
|
||||
|
||||
nodeClient.setOutput(output);
|
||||
} catch (IOException | SecurityException e)
|
||||
K bean = this.fallback.create(cls);
|
||||
Class<?> beanClass = bean.getClass();
|
||||
do
|
||||
{
|
||||
Throwable rootCause = Throwables.getRootCause(e);
|
||||
output.err.println(format("nodetool: Failed to connect to '%s:%s' - %s: '%s'.", host, port, rootCause.getClass().getSimpleName(), rootCause.getMessage()));
|
||||
System.exit(1);
|
||||
Field[] fields = beanClass.getDeclaredFields();
|
||||
for (Field field : fields)
|
||||
{
|
||||
if (!field.isAnnotationPresent(Inject.class))
|
||||
continue;
|
||||
if (field.getType().equals(INodeProbeFactory.class))
|
||||
{
|
||||
field.setAccessible(true);
|
||||
field.set(bean, nodeProbeFactory);
|
||||
}
|
||||
|
||||
return nodeClient;
|
||||
}
|
||||
|
||||
protected enum KeyspaceSet
|
||||
else if (field.getType().equals(Output.class))
|
||||
{
|
||||
ALL, NON_SYSTEM, NON_LOCAL_STRATEGY, ACCORD_MANAGED
|
||||
}
|
||||
|
||||
protected List<String> parseOptionalKeyspace(List<String> cmdArgs, NodeProbe nodeProbe)
|
||||
{
|
||||
return parseOptionalKeyspace(cmdArgs, nodeProbe, KeyspaceSet.ALL);
|
||||
}
|
||||
|
||||
protected List<String> parseOptionalKeyspace(List<String> cmdArgs, NodeProbe nodeProbe, KeyspaceSet defaultKeyspaceSet)
|
||||
{
|
||||
List<String> keyspaces = new ArrayList<>();
|
||||
|
||||
|
||||
if (cmdArgs == null || cmdArgs.isEmpty())
|
||||
{
|
||||
if (defaultKeyspaceSet == KeyspaceSet.NON_LOCAL_STRATEGY)
|
||||
keyspaces.addAll(keyspaces = nodeProbe.getNonLocalStrategyKeyspaces());
|
||||
else if (defaultKeyspaceSet == KeyspaceSet.NON_SYSTEM)
|
||||
keyspaces.addAll(keyspaces = nodeProbe.getNonSystemKeyspaces());
|
||||
else if (defaultKeyspaceSet == KeyspaceSet.ACCORD_MANAGED)
|
||||
keyspaces.addAll(nodeProbe.getAccordManagedKeyspaces());
|
||||
else
|
||||
keyspaces.addAll(nodeProbe.getKeyspaces());
|
||||
field.setAccessible(true);
|
||||
field.set(bean, output);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyspaces.add(cmdArgs.get(0));
|
||||
throw new RuntimeException("Unsupported injectable field type: " + field.getType() +
|
||||
" in class " + beanClass.getName() + ". " +
|
||||
"Only INodeProbeFactory and Output are supported.");
|
||||
}
|
||||
|
||||
for (String keyspace : keyspaces)
|
||||
}
|
||||
}
|
||||
while ((beanClass = beanClass.getSuperclass()) != null);
|
||||
return bean;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!nodeProbe.getKeyspaces().contains(keyspace))
|
||||
throw new IllegalArgumentException("Keyspace [" + keyspace + "] does not exist.");
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(keyspaces);
|
||||
}
|
||||
|
||||
protected String[] parseOptionalTables(List<String> cmdArgs)
|
||||
{
|
||||
return cmdArgs.size() <= 1 ? EMPTY_STRING_ARRAY : toArray(cmdArgs.subList(1, cmdArgs.size()), String.class);
|
||||
}
|
||||
|
||||
protected String[] parsePartitionKeys(List<String> cmdArgs)
|
||||
{
|
||||
return cmdArgs.size() <= 2 ? EMPTY_STRING_ARRAY : toArray(cmdArgs.subList(2, cmdArgs.size()), String.class);
|
||||
throw new CommandLine.InitializationException("Failed to create instance of " + cls, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static SortedMap<String, SetHostStatWithPort> getOwnershipByDcWithPort(NodeProbe probe, boolean resolveIp,
|
||||
Map<String, String> tokenToEndpoint,
|
||||
Map<String, Float> ownerships)
|
||||
{
|
||||
SortedMap<String, SetHostStatWithPort> ownershipByDc = Maps.newTreeMap();
|
||||
EndpointSnitchInfoMBean epSnitchInfo = probe.getEndpointSnitchInfoProxy();
|
||||
try
|
||||
{
|
||||
for (Entry<String, String> tokenAndEndPoint : tokenToEndpoint.entrySet())
|
||||
{
|
||||
String dc = epSnitchInfo.getDatacenter(tokenAndEndPoint.getValue());
|
||||
if (!ownershipByDc.containsKey(dc))
|
||||
ownershipByDc.put(dc, new SetHostStatWithPort(resolveIp));
|
||||
ownershipByDc.get(dc).add(tokenAndEndPoint.getKey(), tokenAndEndPoint.getValue(), ownerships);
|
||||
}
|
||||
}
|
||||
catch (UnknownHostException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return ownershipByDc;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,4 +32,14 @@ public class Output
|
|||
this.out = out;
|
||||
this.err = err;
|
||||
}
|
||||
|
||||
public void printInfo(String msg, Object... args)
|
||||
{
|
||||
out.printf(msg, args);
|
||||
}
|
||||
|
||||
public void printError(String msg, Object... args)
|
||||
{
|
||||
err.printf(msg, args);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,19 @@ package org.apache.cassandra.tools;
|
|||
import accord.local.RedundantBefore;
|
||||
import accord.primitives.Timestamp;
|
||||
import accord.primitives.TxnId;
|
||||
import io.airlift.airline.Cli;
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.cassandra.config.AccordSpec;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.config.DurationSpec;
|
||||
|
|
@ -44,17 +54,9 @@ import org.apache.cassandra.service.accord.JournalKey;
|
|||
import org.apache.cassandra.service.accord.serializers.Version;
|
||||
import org.apache.cassandra.tcm.ClusterMetadataService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
import static accord.api.Journal.Load.ALL;
|
||||
import static com.google.common.base.Throwables.getStackTraceAsString;
|
||||
|
|
@ -91,7 +93,11 @@ import static org.apache.cassandra.config.DatabaseDescriptor.setAccordJournalDir
|
|||
|
||||
*
|
||||
**/
|
||||
public class StandaloneJournalUtil
|
||||
@Command(name = "journal_util",
|
||||
mixinStandardHelpOptions = true,
|
||||
description = "Standalone Journal Util",
|
||||
subcommands = { StandaloneJournalUtil.DumpSegments.class, StandaloneJournalUtil.DumpJournal.class })
|
||||
public class StandaloneJournalUtil implements Runnable
|
||||
{
|
||||
private static final Output output = Output.CONSOLE;
|
||||
|
||||
|
|
@ -101,27 +107,22 @@ public class StandaloneJournalUtil
|
|||
DatabaseDescriptor.setPartitioner("org.apache.cassandra.dht.Murmur3Partitioner");
|
||||
AccordKeyspace.TABLES = Tables.of(AccordKeyspace.journalMetadata("journal", false));
|
||||
ClusterMetadataService.empty(Keyspaces.of(AccordKeyspace.metadata()));
|
||||
Cli.CliBuilder<Runnable> builder = Cli.builder("util");
|
||||
|
||||
builder.withDescription("Dump journal").withCommand(DumpSegments.class).withCommand(DumpJournal.class);
|
||||
|
||||
Cli<Runnable> parser = builder.build();
|
||||
|
||||
int status = 0;
|
||||
try
|
||||
{
|
||||
Runnable parse = parser.parse(args);
|
||||
parse.run();
|
||||
}
|
||||
catch (Throwable throwable)
|
||||
{
|
||||
err(throwable);
|
||||
status = 2;
|
||||
}
|
||||
|
||||
CommandLine cli = new CommandLine(StandaloneJournalUtil.class)
|
||||
.setExecutionExceptionHandler((ex, cmd, parseResult) -> {
|
||||
err(ex);
|
||||
return 2;
|
||||
});
|
||||
int status = cli.execute(args);
|
||||
System.exit(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
CommandLine.usage(this, output.out);
|
||||
}
|
||||
|
||||
protected static void err(Throwable e)
|
||||
{
|
||||
output.err.println("error: " + e.getMessage());
|
||||
|
|
@ -132,19 +133,19 @@ public class StandaloneJournalUtil
|
|||
@Command(name = "dump_segments", description = "Dump journal segments")
|
||||
public static class DumpSegments implements Runnable
|
||||
{
|
||||
@Option(name = {"-d", "--dir"}, description = "Directory to find journal segments")
|
||||
@Option(names = {"-d", "--dir"}, description = "Directory to find journal segments")
|
||||
public String dir;
|
||||
|
||||
@Option(name = {"-p", "--pattern"}, description = "Kind to filter by")
|
||||
@Option(names = {"-p", "--pattern"}, description = "Kind to filter by")
|
||||
public String pattern;
|
||||
|
||||
@Option(name = {"-k", "--kind"}, description = "Kind to filter by")
|
||||
@Option(names = {"-k", "--kind"}, description = "Kind to filter by")
|
||||
public String kind;
|
||||
|
||||
@Option(name = {"-t", "--txnid"}, description = "Transaction id to filter by")
|
||||
@Option(names = {"-t", "--txnid"}, description = "Transaction id to filter by")
|
||||
public String txnId;
|
||||
|
||||
@Option(name = {"-m", "--metadata-only"}, description = "Only dump metadata file contents")
|
||||
@Option(names = {"-m", "--metadata-only"}, description = "Only dump metadata file contents")
|
||||
public boolean metadataOnly;
|
||||
|
||||
public void run()
|
||||
|
|
@ -173,7 +174,8 @@ public class StandaloneJournalUtil
|
|||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
t.printStackTrace(output.err);
|
||||
throw new RuntimeException(String.format("Error reading key %s in segment %s at position %d: %s",
|
||||
key, segment1, position, t.getMessage()), t);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -189,28 +191,28 @@ public class StandaloneJournalUtil
|
|||
@Command(name = "dump_journal", description = "Dump journal")
|
||||
public static class DumpJournal implements Runnable
|
||||
{
|
||||
@Option(name = {"-s", "--sstables"}, description = "Path to sstables")
|
||||
@Option(names = {"-s", "--sstables"}, description = "Path to sstables")
|
||||
public String sstables;
|
||||
|
||||
@Option(name = {"-j", "--journal-segments"}, description = "Path to journal segments")
|
||||
@Option(names = {"-j", "--journal-segments"}, description = "Path to journal segments")
|
||||
public String journalSegments;
|
||||
|
||||
@Option(name = {"-k", "--kind"}, description = "Kind to filter by")
|
||||
@Option(names = {"-k", "--kind"}, description = "Kind to filter by")
|
||||
public String kind;
|
||||
|
||||
@Option(name = {"-t", "--txnid"}, description = "Transaction id to filter by")
|
||||
@Option(names = {"-t", "--txnid"}, description = "Transaction id to filter by")
|
||||
public String txnId;
|
||||
|
||||
@Option(name = {"--since"}, description = "Filter transactions since this timestamp (inclusive)")
|
||||
@Option(names = {"--since"}, description = "Filter transactions since this timestamp (inclusive)")
|
||||
public String since;
|
||||
|
||||
@Option(name = {"--until"}, description = "Filter transactions until this timestamp (inclusive)")
|
||||
@Option(names = {"--until"}, description = "Filter transactions until this timestamp (inclusive)")
|
||||
public String until;
|
||||
|
||||
@Option(name = {"-e", "--skip-errors"}, description = "Skip errors: 'true' to skip all, or comma-separated exception class names to skip specific types")
|
||||
@Option(names = {"-e", "--skip-errors"}, description = "Skip errors: 'true' to skip all, or comma-separated exception class names to skip specific types")
|
||||
public String skipErrors;
|
||||
|
||||
@Option(name = {"-c", "--construct"}, description = "Construct entry")
|
||||
@Option(names = {"-c", "--construct"}, description = "Construct entry")
|
||||
public boolean construct;
|
||||
|
||||
|
||||
|
|
@ -345,8 +347,7 @@ public class StandaloneJournalUtil
|
|||
if (!shouldSkip)
|
||||
throw t;
|
||||
|
||||
output.out.println(String.format("Got error reading key %s", key));
|
||||
t.printStackTrace();
|
||||
throw new RuntimeException(String.format("Error reading key %s: %s", key, t.getMessage()), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,25 +17,22 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
import static org.apache.commons.lang3.StringUtils.isEmpty;
|
||||
|
||||
@Command(name = "abortbootstrap", description = "Abort a failed bootstrap")
|
||||
public class AbortBootstrap extends NodeToolCmd
|
||||
public class AbortBootstrap extends AbstractCommand
|
||||
{
|
||||
@Option(title = "node id", name = "--node", description = "Node ID of the node that failed bootstrap", required = false)
|
||||
@Option(paramLabel = "node_id", names = "--node", description = "Node ID of the node that failed bootstrap")
|
||||
private String nodeId = EMPTY;
|
||||
|
||||
@Option(title = "ip", name = "--ip", description = "IP of the node that failed bootstrap", required = false)
|
||||
@Option(paramLabel = "ip", names = "--ip", description = "IP of the node that failed bootstrap")
|
||||
private String endpoint = EMPTY;
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.Output;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.ExecutionException;
|
||||
|
||||
/**
|
||||
* Abstract class for all nodetool commands, which provides common methods and fields
|
||||
* for running commands and outputting results.
|
||||
* <p>
|
||||
* The command is executed by calling {@link #execute(NodeProbe)}, in all other cases
|
||||
* it should not contain any fields or methods that are specific to a particular API
|
||||
* being executed, or common methods that are shared across multiple commands.
|
||||
* <p>
|
||||
* Commands must work only with the API provided by the {@link NodeProbe} instance.
|
||||
*/
|
||||
public abstract class AbstractCommand implements Runnable
|
||||
{
|
||||
@Inject
|
||||
protected Output output;
|
||||
|
||||
private NodeProbe probe;
|
||||
|
||||
public void probe(NodeProbe probe)
|
||||
{
|
||||
this.probe = probe;
|
||||
}
|
||||
|
||||
public NodeProbe probe()
|
||||
{
|
||||
return probe;
|
||||
}
|
||||
|
||||
public void logger(Output output)
|
||||
{
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
execute(probe());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a command for execution. This method is called before the command is executed and
|
||||
* can be used to perform any necessary setup or validation. If this method returns {@code false},
|
||||
* the command will not initiate connection and will be executed locally. The default implementation
|
||||
* returns {@code true} so that the command initiates connection to the node before execution.
|
||||
*
|
||||
* @return {@code true} if the command is required to connect to the node, {@code false} otherwise.
|
||||
* @throws ExecutionException if an error occurs during preparation and execution must be aborted.
|
||||
*/
|
||||
protected boolean shouldConnect() throws ExecutionException
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the command using the supplied {@link NodeProbe} instance, which is already connected
|
||||
* to the node and ready to use. If the {@link NodeProbe} is not {@code null}, it is guaranteed that it
|
||||
* is connected to the node, and the command can use it to perform operations on the node.
|
||||
* <p>
|
||||
* WARNING:
|
||||
* <p>
|
||||
* Due to the backwards compatibility with the previous Airline-based implementation of
|
||||
* the nodetool commands, for most of the commands this method is also used to validate the input
|
||||
* arguments and perform necessary checks before the command is executed. This implies that
|
||||
* the command <u>throws an exception during execution</u> to avoid unexpected behavior or errors,
|
||||
* instead of validating the input arguments within the Picocli framework on the Parser stage.
|
||||
* For this reason, the {@link CommandLine.Parameters#arity()} and {@link CommandLine.Option#arity()}
|
||||
* which are normally used to validate the input arguments, set to {@code "0..*"} or {@code "0..1"}
|
||||
* making the arguments optional, and passing the validation to the command's
|
||||
* {@code execute(NodeProbe probe)} method.
|
||||
* <p>
|
||||
* New commands should not rely on the behavior described above and should validate the input arguments
|
||||
* using Picocli annotations such as {@link CommandLine.Parameters} and {@link CommandLine.Option}.
|
||||
*
|
||||
* @param probe The {@link NodeProbe} instance to use, or {@code null} if no connection is required.
|
||||
*/
|
||||
protected abstract void execute(NodeProbe probe);
|
||||
}
|
||||
|
|
@ -21,15 +21,30 @@ package org.apache.cassandra.tools.nodetool;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
public abstract class AccordAdmin extends NodeTool.NodeToolCmd
|
||||
@Command(name = "accord",
|
||||
description = "Manage the operation of Accord",
|
||||
subcommands = {
|
||||
AccordAdmin.Describe.class,
|
||||
AccordAdmin.MarkStale.class,
|
||||
AccordAdmin.MarkRejoining.class
|
||||
})
|
||||
public class AccordAdmin extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
AbstractCommand cmd = new AccordAdmin.Describe();
|
||||
cmd.probe(probe);
|
||||
cmd.logger(output);
|
||||
cmd.run();
|
||||
}
|
||||
|
||||
@Command(name = "describe", description = "Describe current cluster metadata relating to Accord")
|
||||
public static class Describe extends NodeTool.NodeToolCmd
|
||||
public static class Describe extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
protected void execute(NodeProbe probe)
|
||||
|
|
@ -42,9 +57,9 @@ public abstract class AccordAdmin extends NodeTool.NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "mark_stale", description = "Mark a replica as being stale and no longer able to participate in durability status coordination")
|
||||
public static class MarkStale extends AccordAdmin
|
||||
public static class MarkStale extends AbstractCommand
|
||||
{
|
||||
@Arguments(required = true, description = "One or more node IDs to mark stale", usage = "<nodeId>+")
|
||||
@Parameters(arity = "1..*", description = "One or more node IDs to mark stale")
|
||||
public List<String> nodeIds;
|
||||
|
||||
@Override
|
||||
|
|
@ -55,9 +70,9 @@ public abstract class AccordAdmin extends NodeTool.NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "mark_rejoining", description = "Mark a stale replica as being allowed to participate in durability status coordination again")
|
||||
public static class MarkRejoining extends AccordAdmin
|
||||
public static class MarkRejoining extends AbstractCommand
|
||||
{
|
||||
@Arguments(required = true, description = "One or more node IDs to mark no longer stale", usage = "<nodeId>+")
|
||||
@Parameters(arity = "1", description = "One or more node IDs to mark no longer stale")
|
||||
public List<String> nodeIds;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -20,17 +20,16 @@ package org.apache.cassandra.tools.nodetool;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
@Command(name = "altertopology", description = "Modify the datacenter and/or rack of one or more nodes")
|
||||
public class AlterTopology extends NodeToolCmd
|
||||
public class AlterTopology extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "<node=dc:rack> [<node=dc:rack>...]", description = "One or more node identifiers, which may be either a node id, host id or broadcast address, each with a target dc:rack")
|
||||
@Parameters(description = { "One or more node identifiers, which may be either a node id, host id or broadcast address, each with a target dc:rack",
|
||||
"<node=dc:rack> [<node=dc:rack>...]" })
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,19 +17,18 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
|
||||
@Command(name = "assassinate", description = "Forcefully remove a dead node without re-replicating any data. Use as a last resort if you cannot removenode")
|
||||
public class Assassinate extends NodeToolCmd
|
||||
public class Assassinate extends AbstractCommand
|
||||
{
|
||||
@Arguments(title = "ip address", usage = "<ip_address>", description = "IP address of the endpoint to assassinate", required = true)
|
||||
@Parameters(paramLabel = "ip_address", description = "IP address of the endpoint to assassinate", arity = "1")
|
||||
private String endpoint = EMPTY;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -23,11 +23,10 @@ import java.util.Set;
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
|
|
@ -35,10 +34,10 @@ import static com.google.common.base.Preconditions.checkArgument;
|
|||
* Provides currently running auto-repair tasks.
|
||||
*/
|
||||
@Command(name = "autorepairstatus", description = "Print autorepair status")
|
||||
public class AutoRepairStatus extends NodeTool.NodeToolCmd
|
||||
public class AutoRepairStatus extends AbstractCommand
|
||||
{
|
||||
@VisibleForTesting
|
||||
@Option(title = "repair type", name = { "-t", "--repair-type" }, description = "Repair type")
|
||||
@Option(names = { "-t", "--repair-type" }, description = "Repair type")
|
||||
protected String repairType;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "bootstrap",
|
||||
subcommands = { BootstrapResume.class },
|
||||
description = "Monitor/manage node's bootstrap process")
|
||||
public class Bootstrap
|
||||
{
|
||||
}
|
||||
|
|
@ -17,24 +17,24 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
import static org.apache.cassandra.config.CassandraRelevantProperties.RESET_BOOTSTRAP_PROGRESS;
|
||||
|
||||
@Command(name = "resume", description = "Resume bootstrap streaming")
|
||||
public class BootstrapResume extends NodeToolCmd
|
||||
public class BootstrapResume extends AbstractCommand
|
||||
{
|
||||
@Option(title = "force",
|
||||
name = { "-f", "--force"},
|
||||
description = "Use --force to resume bootstrap regardless of cassandra.reset_bootstrap_progress environment variable. WARNING: This is potentially dangerous, see CASSANDRA-17679")
|
||||
boolean force = false;
|
||||
@Option(paramLabel = "force",
|
||||
names = { "-f", "--force" },
|
||||
description = { "Use --force to resume bootstrap regardless of ",
|
||||
"cassandra.reset_bootstrap_progress environment variable. WARNING:",
|
||||
"This is potentially dangerous, see CASSANDRA-17679" })
|
||||
private boolean force = false;
|
||||
|
||||
@Override
|
||||
protected void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -22,18 +22,17 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.db.virtual.CIDRFilteringMetricsTable.CIDRFilteringMetricsCountsTable;
|
||||
import org.apache.cassandra.db.virtual.CIDRFilteringMetricsTable.CIDRFilteringMetricsLatenciesTable;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
/**
|
||||
* Nodetool command to view stats related to CIDR filtering
|
||||
*/
|
||||
@Command(name = "cidrfilteringstats", description = "Print statistics on CIDR filtering")
|
||||
public class CIDRFilteringStats extends NodeToolCmd
|
||||
public class CIDRFilteringStats extends AbstractCommand
|
||||
{
|
||||
private void printCountsMetrics(NodeProbe probe, PrintStream out)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@ import java.util.Map;
|
|||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tcm.Epoch;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static org.apache.cassandra.tcm.CMSOperations.COMMITS_PAUSED;
|
||||
import static org.apache.cassandra.tcm.CMSOperations.EPOCH;
|
||||
|
|
@ -44,10 +44,29 @@ import static org.apache.cassandra.tcm.CMSOperations.NEEDS_RECONFIGURATION;
|
|||
import static org.apache.cassandra.tcm.CMSOperations.REPLICATION_FACTOR;
|
||||
import static org.apache.cassandra.tcm.CMSOperations.SERVICE_STATE;
|
||||
|
||||
public abstract class CMSAdmin extends NodeTool.NodeToolCmd
|
||||
@Command(name = "cms", description = "Manage cluster metadata",
|
||||
subcommands = { CMSAdmin.DescribeCMS.class,
|
||||
CMSAdmin.InitializeCMS.class,
|
||||
CMSAdmin.ReconfigureCMS.class,
|
||||
CMSAdmin.Snapshot.class,
|
||||
CMSAdmin.Unregister.class,
|
||||
CMSAdmin.AbortInitialization.class,
|
||||
CMSAdmin.DumpDirectory.class,
|
||||
CMSAdmin.DumpLog.class,
|
||||
CMSAdmin.ResumeDropAccordTable.class })
|
||||
public class CMSAdmin extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
AbstractCommand cmd = new DescribeCMS();
|
||||
cmd.probe(probe);
|
||||
cmd.logger(output);
|
||||
cmd.run();
|
||||
}
|
||||
|
||||
@Command(name = "describe", description = "Describe the current Cluster Metadata Service")
|
||||
public static class DescribeCMS extends NodeTool.NodeToolCmd
|
||||
public static class DescribeCMS extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
protected void execute(NodeProbe probe)
|
||||
|
|
@ -67,9 +86,9 @@ public abstract class CMSAdmin extends NodeTool.NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "initialize", description = "Upgrade from gossip and initialize CMS")
|
||||
public static class InitializeCMS extends NodeTool.NodeToolCmd
|
||||
public static class InitializeCMS extends AbstractCommand
|
||||
{
|
||||
@Option(title = "ignored endpoints", name = { "-i", "--ignore"}, description = "Hosts to ignore due to them being down")
|
||||
@Option(paramLabel = "ignored_endpoints", names = { "-i", "--ignore" }, description = "Hosts to ignore due to them being down")
|
||||
private List<String> endpoint = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
|
|
@ -80,24 +99,25 @@ public abstract class CMSAdmin extends NodeTool.NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "reconfigure", description = "Reconfigure replication factor of CMS")
|
||||
public static class ReconfigureCMS extends NodeTool.NodeToolCmd
|
||||
public static class ReconfigureCMS extends AbstractCommand
|
||||
{
|
||||
@Option(title = "status",
|
||||
name = {"--status"},
|
||||
@Option(paramLabel = "status",
|
||||
names = { "--status" },
|
||||
description = "Poll status of the reconfigure command. All other flags and arguments are ignored when this one is used.")
|
||||
private boolean status = false;
|
||||
|
||||
@Option(title = "resume",
|
||||
name = {"-r", "--resume"},
|
||||
@Option(paramLabel = "resume",
|
||||
names = { "-r", "--resume" },
|
||||
description = "Whether or not a previously interrupted sequence should be resumed")
|
||||
private boolean resume = false;
|
||||
|
||||
@Option(title = "cancel",
|
||||
name = {"-c", "--cancel"},
|
||||
@Option(paramLabel = "cancel",
|
||||
names = { "-c", "--cancel" },
|
||||
description = "Cancels any in progress CMS reconfiguration")
|
||||
private boolean cancel = false;
|
||||
|
||||
@Arguments(usage = "[<replication factor>] or <datacenter>:<replication_factor> ... ", description = "Replication factor of new CMS")
|
||||
@CassandraUsage(usage = "[<replication factor>] or <datacenter>:<replication_factor> ... ", description = "Replication factor of new CMS")
|
||||
@Parameters(paramLabel = "replication_factor", description = "Replication factors of new CMS in format <replication factor> or <datacenter>:<replication_factor>")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
|
|
@ -178,7 +198,7 @@ public abstract class CMSAdmin extends NodeTool.NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "snapshot", description = "Request a checkpointing snapshot of cluster metadata")
|
||||
public static class Snapshot extends NodeTool.NodeToolCmd
|
||||
public static class Snapshot extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
@ -188,10 +208,10 @@ public abstract class CMSAdmin extends NodeTool.NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "unregister", description = "Unregister nodes in LEFT state")
|
||||
public static class Unregister extends NodeTool.NodeToolCmd
|
||||
public static class Unregister extends AbstractCommand
|
||||
{
|
||||
@Arguments(required = true, title = "Unregister nodes in LEFT state", description = "One or more nodeIds to unregister, they all need to be in LEFT state", usage = "<nodeId>+")
|
||||
public List<String> nodeIds;
|
||||
@Parameters(paramLabel = "nodeId", description = "One or more nodeIds to unregister, they all need to be in LEFT state", arity = "1..*")
|
||||
private List<String> nodeIds;
|
||||
|
||||
@Override
|
||||
protected void execute(NodeProbe probe)
|
||||
|
|
@ -201,9 +221,9 @@ public abstract class CMSAdmin extends NodeTool.NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "abortinitialization", description = "Abort an incomplete initialization")
|
||||
public static class AbortInitialization extends NodeTool.NodeToolCmd
|
||||
public static class AbortInitialization extends AbstractCommand
|
||||
{
|
||||
@Option(required = true, name = "--initiator", title = "Initiator", description = "The address of the node where `cms initialize` was run.")
|
||||
@Option(required = true, names = { "--initiator" }, description = "The address of the node where `cms initialize` was run.")
|
||||
public String initiator;
|
||||
|
||||
@Override
|
||||
|
|
@ -214,10 +234,11 @@ public abstract class CMSAdmin extends NodeTool.NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "dumpdirectory", description = "Dump the directory from the current ClusterMetadata")
|
||||
public static class DumpDirectory extends NodeTool.NodeToolCmd
|
||||
public static class DumpDirectory extends AbstractCommand
|
||||
{
|
||||
@Option(name = "--tokens", title = "Include tokens", description = "Include tokens in output")
|
||||
@Option(names = { "--tokens" }, description = "Include tokens in output")
|
||||
public boolean tokens = false;
|
||||
|
||||
@Override
|
||||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
|
|
@ -226,12 +247,13 @@ public abstract class CMSAdmin extends NodeTool.NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "dumplog", description = "Dump the metadata log")
|
||||
public static class DumpLog extends NodeTool.NodeToolCmd
|
||||
public static class DumpLog extends AbstractCommand
|
||||
{
|
||||
@Option(name = "--start", title = "Start epoch")
|
||||
@Option(names = { "--start" }, description = "Start epoch")
|
||||
long startEpoch = Epoch.FIRST.getEpoch();
|
||||
@Option(name = "--end", title = "End epoch")
|
||||
@Option(names = { "--end" }, description = "End epoch")
|
||||
long endEpoch = Long.MAX_VALUE;
|
||||
|
||||
@Override
|
||||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
|
|
@ -259,10 +281,11 @@ public abstract class CMSAdmin extends NodeTool.NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "resumedropaccordtable", description = "Resume a drop accord table operation which has stalled")
|
||||
public static class ResumeDropAccordTable extends NodeTool.NodeToolCmd
|
||||
public static class ResumeDropAccordTable extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[tableId]", description = "Table id of the table being dropped")
|
||||
@Parameters(description = "Table id of the table being dropped")
|
||||
private String tableId;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,32 +17,43 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.schema.SchemaConstants;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.concatArgs;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalKeyspaceNonLocal;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalTables;
|
||||
|
||||
@Command(name = "cleanup", description = "Triggers the immediate cleanup of keys no longer belonging to a node. By default, clean all keyspaces")
|
||||
public class Cleanup extends NodeToolCmd
|
||||
public class Cleanup extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
@CassandraUsage(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Option(title = "jobs",
|
||||
name = {"-j", "--jobs"},
|
||||
@Parameters(index = "0", description = "The keyspace followed by one or many tables", arity = "0..1")
|
||||
private String keyspace;
|
||||
|
||||
@Parameters (index = "1..*", description = "The tables to cleanup", arity = "0..*")
|
||||
private String[] tables;
|
||||
|
||||
@Option(paramLabel = "jobs",
|
||||
names = {"-j", "--jobs"},
|
||||
description = "Number of sstables to cleanup simultanously, set to 0 to use all available compaction threads")
|
||||
private int jobs = 2;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
List<String> keyspaces = parseOptionalKeyspace(args, probe, KeyspaceSet.NON_LOCAL_STRATEGY);
|
||||
args = concatArgs(keyspace, tables);
|
||||
|
||||
List<String> keyspaces = parseOptionalKeyspaceNonLocal(args, probe);
|
||||
String[] tableNames = parseOptionalTables(args);
|
||||
|
||||
for (String keyspace : keyspaces)
|
||||
|
|
|
|||
|
|
@ -17,13 +17,6 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import static com.google.common.collect.Iterables.toArray;
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
import static org.apache.commons.lang3.StringUtils.join;
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeParseException;
|
||||
|
|
@ -34,24 +27,32 @@ import java.util.Map;
|
|||
|
||||
import org.apache.cassandra.config.DurationSpec;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static com.google.common.collect.Iterables.toArray;
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
import static org.apache.commons.lang3.StringUtils.join;
|
||||
|
||||
@Command(name = "clearsnapshot", description = "Remove the snapshot with the given name from the given keyspaces")
|
||||
public class ClearSnapshot extends NodeToolCmd
|
||||
public class ClearSnapshot extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<keyspaces>...] ", description = "Remove snapshots from the given keyspaces")
|
||||
@CassandraUsage(usage = "[<keyspaces>...]", description = "Remove snapshots from the given keyspaces")
|
||||
@Parameters(description = "Remove snapshots from the given keyspaces", arity = "0..*")
|
||||
private List<String> keyspaces = new ArrayList<>();
|
||||
|
||||
@Option(title = "snapshot_name", name = "-t", description = "Remove the snapshot with a given name")
|
||||
@Option(paramLabel = "snapshot_name", names = "-t", description = "Remove the snapshot with a given name")
|
||||
private String snapshotName = EMPTY;
|
||||
|
||||
@Option(title = "clear_all_snapshots", name = "--all", description = "Removes all snapshots")
|
||||
@Option(paramLabel = "clear_all_snapshots", names = "--all", description = "Removes all snapshots")
|
||||
private boolean clearAllSnapshots = false;
|
||||
|
||||
@Option(title = "older_than", name = "--older-than", description = "Clear snapshots older than specified time period.")
|
||||
@Option(paramLabel = "older_than", names = "--older-than", description = "Clear snapshots older than specified time period.")
|
||||
private String olderThan;
|
||||
|
||||
@Option(title = "older_than_timestamp", name = "--older-than-timestamp",
|
||||
@Option(paramLabel = "older_than_timestamp", names = "--older-than-timestamp",
|
||||
description = "Clear snapshots older than specified timestamp. It has to be a string in ISO format, for example '2022-12-03T10:15:30Z'")
|
||||
private String olderThanTimestamp;
|
||||
|
||||
|
|
@ -121,7 +122,8 @@ public class ClearSnapshot extends NodeToolCmd
|
|||
parameters.put("older_than_timestamp", olderThanTimestamp);
|
||||
|
||||
probe.clearSnapshot(parameters, snapshotName, toArray(keyspaces, String.class));
|
||||
} catch (IOException e)
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException("Error during clearing snapshots", e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,30 +26,30 @@ import java.util.Map.Entry;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
|
||||
import org.apache.cassandra.transport.ClientStat;
|
||||
import org.apache.cassandra.transport.ConnectedClient;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "clientstats", description = "Print information about connected clients")
|
||||
public class ClientStats extends NodeToolCmd
|
||||
public class ClientStats extends AbstractCommand
|
||||
{
|
||||
@Option(title = "list_connections", name = "--all", description = "Lists all connections")
|
||||
@Option(paramLabel = "list_connections", names = "--all", description = "Lists all connections")
|
||||
private boolean listConnections = false;
|
||||
|
||||
@Option(title = "by_protocol", name = "--by-protocol", description = "Lists most recent client connections by protocol version")
|
||||
@Option(paramLabel = "by_protocol", names = "--by-protocol", description = "Lists most recent client connections by protocol version")
|
||||
private boolean connectionsByProtocolVersion = false;
|
||||
|
||||
@Option(title = "clear_history", name = "--clear-history", description = "Clear the history of connected clients")
|
||||
@Option(paramLabel = "clear_history", names = "--clear-history", description = "Clear the history of connected clients")
|
||||
private boolean clearConnectionHistory = false;
|
||||
|
||||
@Option(title = "list_connections_with_client_options", name = "--client-options", description = "Lists all connections and the client options")
|
||||
@Option(paramLabel = "list_connections_with_client_options", names = "--client-options", description = "Lists all connections and the client options")
|
||||
private boolean clientOptions = false;
|
||||
|
||||
@Option(title = "verbose", name = "--verbose", description = "Lists all connections with additional details (client options, authenticator-specific metadata and more)")
|
||||
@Option(paramLabel = "verbose", names = "--verbose", description = "Lists all connections with additional details (client options, authenticator-specific metadata and more)")
|
||||
private boolean verbose = false;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import org.apache.cassandra.locator.EndpointSnitchInfoMBean;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import org.apache.cassandra.utils.Pair;
|
||||
|
||||
import static com.google.common.collect.Iterables.toArray;
|
||||
import static java.util.stream.Stream.concat;
|
||||
import static java.util.stream.Stream.ofNullable;
|
||||
import static org.apache.commons.lang3.ArrayUtils.EMPTY_STRING_ARRAY;
|
||||
|
||||
/**
|
||||
* Utility methods for nodetool commands.
|
||||
*/
|
||||
public final class CommandUtils
|
||||
{
|
||||
private CommandUtils() {}
|
||||
|
||||
public static int maxLength(Collection<?> any)
|
||||
{
|
||||
int result = 0;
|
||||
for (Object value : any)
|
||||
result = Math.max(result, String.valueOf(value).length());
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Pair<String, String> findCassandraBackwardCompatibleArgument(Object userObject)
|
||||
{
|
||||
Class<?> clazz = userObject.getClass();
|
||||
do
|
||||
{
|
||||
for (Field field : clazz.getDeclaredFields())
|
||||
{
|
||||
if (field.isAnnotationPresent(CassandraUsage.class))
|
||||
{
|
||||
CassandraUsage ann = field.getAnnotation(CassandraUsage.class);
|
||||
return Pair.create(ann.usage(), ann.description());
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((clazz = clazz.getSuperclass()) != null);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] sortShortestFirst(String[] names)
|
||||
{
|
||||
Arrays.sort(names, Comparator.comparing(String::length));
|
||||
return names;
|
||||
}
|
||||
|
||||
public static List<String> concatArgs(String first, String second)
|
||||
{
|
||||
return concat(ofNullable(first), ofNullable(second)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<String> concatArgs(String first, String second, String third)
|
||||
{
|
||||
return concat(ofNullable(first), concatArgs(second, third).stream()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<String> concatArgs(String first, String second, String third, String fourth)
|
||||
{
|
||||
return concat(ofNullable(first), concatArgs(second, third, fourth).stream()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<String> concatArgs(String first, String[] second)
|
||||
{
|
||||
return concat(ofNullable(first), (second == null ? Stream.empty() : Arrays.stream(second))).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<String> concatArgs(String first, List<String> second)
|
||||
{
|
||||
return concat(ofNullable(first), (second == null ? Stream.empty() : second.stream())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<String> concatArgs(String first, String second, String[] third)
|
||||
{
|
||||
return concat(ofNullable(first), concatArgs(second, third).stream()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<String> concatArgs(String first, String second, List<String> third)
|
||||
{
|
||||
return concat(ofNullable(first), concatArgs(second, third).stream()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<String> concatArgs(String first, String second, String third, String[] fourth)
|
||||
{
|
||||
return concat(ofNullable(first), concatArgs(second, third, fourth).stream()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static void printSet(PrintStream out, String colName, Set<String> values)
|
||||
{
|
||||
if (values == null || values.isEmpty())
|
||||
return;
|
||||
|
||||
TableBuilder table = new TableBuilder();
|
||||
|
||||
table.add(colName + ": ");
|
||||
|
||||
for (String value : values)
|
||||
table.add(value);
|
||||
|
||||
table.printTo(out);
|
||||
}
|
||||
|
||||
public static List<String> parseOptionalKeyspaceAccordManaged(List<String> cmdArgs, NodeProbe nodeProbe)
|
||||
{
|
||||
return parseOptionalKeyspace(cmdArgs, nodeProbe, KeyspaceSet.ACCORD_MANAGED);
|
||||
}
|
||||
|
||||
public static List<String> parseOptionalKeyspace(List<String> cmdArgs, NodeProbe nodeProbe)
|
||||
{
|
||||
return parseOptionalKeyspace(cmdArgs, nodeProbe, KeyspaceSet.ALL);
|
||||
}
|
||||
|
||||
public static List<String> parseOptionalKeyspaceNonLocal(List<String> cmdArgs, NodeProbe nodeProbe)
|
||||
{
|
||||
return parseOptionalKeyspace(cmdArgs, nodeProbe, KeyspaceSet.NON_LOCAL_STRATEGY);
|
||||
}
|
||||
|
||||
private static List<String> parseOptionalKeyspace(List<String> cmdArgs, NodeProbe nodeProbe, KeyspaceSet defaultKeyspaceSet)
|
||||
{
|
||||
List<String> keyspaces = new ArrayList<>();
|
||||
|
||||
|
||||
if (cmdArgs == null || cmdArgs.isEmpty())
|
||||
{
|
||||
if (defaultKeyspaceSet == KeyspaceSet.NON_LOCAL_STRATEGY)
|
||||
keyspaces.addAll(keyspaces = nodeProbe.getNonLocalStrategyKeyspaces());
|
||||
else if (defaultKeyspaceSet == KeyspaceSet.NON_SYSTEM)
|
||||
keyspaces.addAll(keyspaces = nodeProbe.getNonSystemKeyspaces());
|
||||
else if (defaultKeyspaceSet == KeyspaceSet.ACCORD_MANAGED)
|
||||
keyspaces.addAll(nodeProbe.getAccordManagedKeyspaces());
|
||||
|
||||
else
|
||||
keyspaces.addAll(nodeProbe.getKeyspaces());
|
||||
}
|
||||
else
|
||||
{
|
||||
keyspaces.add(cmdArgs.get(0));
|
||||
}
|
||||
|
||||
for (String keyspace : keyspaces)
|
||||
{
|
||||
if (!nodeProbe.getKeyspaces().contains(keyspace))
|
||||
throw new IllegalArgumentException("Keyspace [" + keyspace + "] does not exist.");
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(keyspaces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the optional table names from the command arguments for nodetool commands.
|
||||
* <p>
|
||||
* The nodetool commands can operate on either all tables within a keyspace, or on a specific
|
||||
* subset of tables. This method extracts the table names from the provided cli arguments, assuming
|
||||
* the first argument is the keyspace name and any subsequent arguments are table names.
|
||||
* <p>
|
||||
* If no table names are provided (e.g. only the keyspace is specified), this method returns
|
||||
* an empty array, which signals to the MBeans that the operation should apply to all tables
|
||||
* in the keyspace. This approach provides flexibility to target either all tables or specific
|
||||
* tables as needed.
|
||||
*
|
||||
* @param cmdArgs the list of command arguments, where the first argument is typically the
|
||||
* keyspace name (ignored), and any subsequent arguments are table names
|
||||
* @return an array of table names, or an empty array (meaning 'all tables') if no extra args are specified.
|
||||
*/
|
||||
public static String[] parseOptionalTables(List<String> cmdArgs)
|
||||
{
|
||||
return cmdArgs.size() <= 1 ? EMPTY_STRING_ARRAY : toArray(cmdArgs.subList(1, cmdArgs.size()), String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the optional partition key values from the command arguments for nodetool commands.
|
||||
* <p>
|
||||
* Some nodetool commands can operate on a specific partition within a table, which requires
|
||||
* specifying the partition key values after the keyspace and table names in the cli arguments.
|
||||
* This method extracts the partition keys from the provided command arguments, assuming
|
||||
* the first argument is the keyspace name, the second is the table name, and any subsequent
|
||||
* arguments are partition key values.
|
||||
* <p>
|
||||
* If no partition key values are provided (e.g. only keyspace and table are specified), this
|
||||
* method returns an empty array, which signals to the MBeans or command logic that the operation
|
||||
* should apply to all partitions.
|
||||
*
|
||||
* @param cmdArgs the list of command arguments, where the first argument is the keyspace name,
|
||||
* the second is the table name, and any subsequent arguments are partition key values
|
||||
* @return an array of partition key values, or an empty array if none are specified (meaning 'all partitions').
|
||||
*/
|
||||
public static String[] parsePartitionKeys(List<String> cmdArgs)
|
||||
{
|
||||
return cmdArgs.size() <= 2 ? EMPTY_STRING_ARRAY : toArray(cmdArgs.subList(2, cmdArgs.size()), String.class);
|
||||
}
|
||||
|
||||
public static SortedMap<String, SetHostStatWithPort> getOwnershipByDcWithPort(NodeProbe probe, boolean resolveIp,
|
||||
Map<String, String> tokenToEndpoint,
|
||||
Map<String, Float> ownerships)
|
||||
{
|
||||
SortedMap<String, SetHostStatWithPort> ownershipByDc = Maps.newTreeMap();
|
||||
EndpointSnitchInfoMBean epSnitchInfo = probe.getEndpointSnitchInfoProxy();
|
||||
try
|
||||
{
|
||||
for (Map.Entry<String, String> tokenAndEndPoint : tokenToEndpoint.entrySet())
|
||||
{
|
||||
String dc = epSnitchInfo.getDatacenter(tokenAndEndPoint.getValue());
|
||||
if (!ownershipByDc.containsKey(dc))
|
||||
ownershipByDc.put(dc, new SetHostStatWithPort(resolveIp));
|
||||
ownershipByDc.get(dc).add(tokenAndEndPoint.getKey(), tokenAndEndPoint.getValue(), ownerships);
|
||||
}
|
||||
}
|
||||
catch (UnknownHostException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return ownershipByDc;
|
||||
}
|
||||
|
||||
private enum KeyspaceSet
|
||||
{
|
||||
ALL, NON_SYSTEM, NON_LOCAL_STRATEGY, ACCORD_MANAGED
|
||||
}
|
||||
}
|
||||
|
|
@ -17,41 +17,46 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalKeyspace;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalTables;
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
|
||||
// TODO CASSANDRA-20793 Types of input aguments shouldn't be mixed in the same command. The keyspace, table and SSTable file arguments should have their own commands.
|
||||
@Command(name = "compact", description = "Force a (major) compaction on one or more tables or user-defined compaction on given SSTables")
|
||||
public class Compact extends NodeToolCmd
|
||||
public class Compact extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<keyspace> <tables>...] or <SSTable file>...", description = "The keyspace followed by one or many tables or list of SSTable data files when using --user-defined")
|
||||
@CassandraUsage(usage = "[<keyspace> <tables>...] or <SSTable file>...",
|
||||
description = "The keyspace followed by one or many tables or list of SSTable data files when using --user-defined")
|
||||
@Parameters(index = "0..*", description = "The keyspace followed by one or many tables or " +
|
||||
"list of SSTable data files when using --user-defined")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Option(title = "split_output", name = {"-s", "--split-output"}, description = "Use -s to not create a single big file")
|
||||
@Option(paramLabel = "split_output", names = { "-s", "--split-output" }, description = "Use -s to not create a single big file")
|
||||
private boolean splitOutput = false;
|
||||
|
||||
@Option(title = "user-defined", name = {"--user-defined"}, description = "Use --user-defined to submit listed files for user-defined compaction")
|
||||
@Option(paramLabel = "user_defined", names = { "--user-defined" }, description = "Use --user-defined to submit listed files for user-defined compaction")
|
||||
private boolean userDefined = false;
|
||||
|
||||
@Option(title = "start_token", name = {"-st", "--start-token"}, description = "Use -st to specify a token at which the compaction range starts (inclusive)")
|
||||
@Option(paramLabel = "start_token", names = { "-st", "--start-token" }, description = "Use -st to specify a token at which the compaction range starts (inclusive)")
|
||||
private String startToken = EMPTY;
|
||||
|
||||
@Option(title = "end_token", name = {"-et", "--end-token"}, description = "Use -et to specify a token at which compaction range ends (inclusive)")
|
||||
@Option(paramLabel = "end_token", names = { "-et", "--end-token" }, description = "Use -et to specify a token at which compaction range ends (inclusive)")
|
||||
private String endToken = EMPTY;
|
||||
|
||||
@Option(title = "partition_key", name = {"--partition"}, description = "String representation of the partition key")
|
||||
@Option(paramLabel = "partition_key", names = { "--partition" }, description = "String representation of the partition key")
|
||||
private String partitionKey = EMPTY;
|
||||
|
||||
@Option(title = "jobs",
|
||||
name = {"-j", "--jobs"},
|
||||
@Option(paramLabel = "jobs",
|
||||
names = {"-j", "--jobs"},
|
||||
description = "Use -j to specify the maximum number of threads to use for parallel compaction. " +
|
||||
"If not set, up to half the compaction threads will be used. " +
|
||||
"If set to 0, the major compaction will use all threads and will not permit other compactions to run until it completes (use with caution).")
|
||||
|
|
|
|||
|
|
@ -17,25 +17,24 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.stats.CompactionHistoryHolder;
|
||||
import org.apache.cassandra.tools.nodetool.stats.CompactionHistoryPrinter;
|
||||
import org.apache.cassandra.tools.nodetool.stats.StatsHolder;
|
||||
import org.apache.cassandra.tools.nodetool.stats.StatsPrinter;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "compactionhistory", description = "Print history of compaction")
|
||||
public class CompactionHistory extends NodeToolCmd
|
||||
public class CompactionHistory extends AbstractCommand
|
||||
{
|
||||
@Option(title = "format",
|
||||
name = {"-F", "--format"},
|
||||
@Option(paramLabel = "format",
|
||||
names = { "-F", "--format" },
|
||||
description = "Output format (json, yaml)")
|
||||
private String outputFormat = "";
|
||||
|
||||
@Option(title = "human_readable",
|
||||
name = {"-H", "--human-readable"},
|
||||
@Option(paramLabel = "human_readable",
|
||||
names = { "-H", "--human-readable" },
|
||||
description = "Display bytes in human readable form, i.e. KiB, MiB, GiB, TiB")
|
||||
private boolean humanReadable = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,29 +24,27 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
|
||||
import org.apache.cassandra.db.compaction.CompactionInfo;
|
||||
import org.apache.cassandra.db.compaction.CompactionInfo.Unit;
|
||||
import org.apache.cassandra.io.util.FileUtils;
|
||||
import org.apache.cassandra.metrics.CassandraMetricsRegistry;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
@Command(name = "compactionstats", description = "Print statistics on compactions")
|
||||
public class CompactionStats extends NodeToolCmd
|
||||
public class CompactionStats extends AbstractCommand
|
||||
{
|
||||
@Option(title = "human_readable",
|
||||
name = {"-H", "--human-readable"},
|
||||
@Option(paramLabel = "human_readable",
|
||||
names = { "-H", "--human-readable" },
|
||||
description = "Display bytes in human readable form, i.e. KiB, MiB, GiB, TiB")
|
||||
private boolean humanReadable = false;
|
||||
|
||||
@Option(title = "vtable_output",
|
||||
name = {"-V", "--vtable"},
|
||||
@Option(paramLabel = "vtable_output",
|
||||
names = { "-V", "--vtable" },
|
||||
description = "Display fields matching vtable output")
|
||||
private boolean vtableOutput = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,35 +24,53 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.service.consensus.migration.ConsensusMigrationTarget;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
import org.apache.cassandra.tools.RepairRunner.RepairCmd;
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static java.util.Collections.singleton;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalKeyspaceAccordManaged;
|
||||
|
||||
/**
|
||||
* For managing migration from one consensus protocol to another.
|
||||
*
|
||||
* Mark ranges as migrating, and list the migrating ranges.
|
||||
*/
|
||||
public abstract class ConsensusMigrationAdmin extends NodeTool.NodeToolCmd
|
||||
@CommandLine.Command(name = "consensus_admin", description = "List and mark ranges as migrating between consensus protocols",
|
||||
subcommands = { ConsensusMigrationAdmin.BeginMigration.class,
|
||||
ConsensusMigrationAdmin.FinishMigration.class,
|
||||
ConsensusMigrationAdmin.ListCmd.class })
|
||||
public class ConsensusMigrationAdmin extends AbstractCommand
|
||||
{
|
||||
@Command(name = "list", description = "List migrating tables and ranges")
|
||||
public static class ListCmd extends ConsensusMigrationAdmin
|
||||
@Override
|
||||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
@Arguments(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
private List<String> schemaArgs = new ArrayList<>();
|
||||
AbstractCommand cmd = new CMSAdmin.DescribeCMS();
|
||||
cmd.probe(probe);
|
||||
cmd.logger(output);
|
||||
cmd.run();
|
||||
}
|
||||
|
||||
@Option(title = "format", name = {"-f", "--format"}, description = "Output format, YAML and JSON are the only supported formats, default YAML, prefix with `minified-` to turn off pretty printing")
|
||||
@Command(name = "list", description = "List migrating tables and ranges")
|
||||
public static class ListCmd extends AbstractCommand
|
||||
{
|
||||
@Parameters(index = "0", arity = "0..1", description = "The keyspace followed by one or many tables")
|
||||
public String keyspace;
|
||||
|
||||
@Parameters(index = "1..*", arity = "0..*", description = "The tables")
|
||||
public String[] tables;
|
||||
|
||||
@Option(names = {"-f", "--format"}, description = "Output format, YAML and JSON are the only supported formats, default YAML, prefix with `minified-` to turn off pretty printing")
|
||||
private String format = "yaml";
|
||||
|
||||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
List<String> schemaArgs = CommandUtils.concatArgs(keyspace, tables);
|
||||
Set<String> keyspaceNames = schemaArgs.size() > 0 ? singleton(schemaArgs.get(0)) : null;
|
||||
Set<String> tableNames = schemaArgs.size() > 1 ? new HashSet<>(schemaArgs.subList(1, schemaArgs.size())) : null;
|
||||
String output = probe.getStorageService().listConsensusMigrations(keyspaceNames, tableNames, format);
|
||||
|
|
@ -61,22 +79,26 @@ public abstract class ConsensusMigrationAdmin extends NodeTool.NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "begin-migration", description = "Mark the range as migrating for the specified token range and tables")
|
||||
public static class BeginMigration extends ConsensusMigrationAdmin
|
||||
public static class BeginMigration extends AbstractCommand
|
||||
{
|
||||
@Option(title = "start_token", name = {"-st", "--start-token"}, description = "Use -st to specify a token at which the repair range starts")
|
||||
@Option(paramLabel = "start_token", names = { "-st", "--start-token" }, description = "Use -st to specify a token at which the repair range starts")
|
||||
private String startToken = null;
|
||||
|
||||
@Option(title = "end_token", name = {"-et", "--end-token"}, description = "Use -et to specify a token at which repair range ends")
|
||||
@Option(paramLabel = "end_token", names = { "-et", "--end-token" }, description = "Use -et to specify a token at which repair range ends")
|
||||
private String endToken = null;
|
||||
|
||||
@Arguments(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
private List<String> schemaArgs = new ArrayList<>();
|
||||
@Parameters(index = "0", arity = "0..1", description = "The keyspace followed by one or many tables")
|
||||
private String keyspace;
|
||||
|
||||
@Parameters(index = "1..*", arity = "0..*", description = "The tables")
|
||||
private String[] tables;
|
||||
|
||||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
checkArgument((endToken != null && startToken != null) || (endToken == null && startToken == null), "Must specify start and end token together");
|
||||
List<String> schemaArgs = CommandUtils.concatArgs(keyspace, tables);
|
||||
String maybeRangesStr = startToken != null ? startToken + ":" + endToken : null;
|
||||
List<String> keyspaceNames = parseOptionalKeyspace(schemaArgs, probe, KeyspaceSet.ACCORD_MANAGED);
|
||||
List<String> keyspaceNames = parseOptionalKeyspaceAccordManaged(schemaArgs, probe);
|
||||
List<String> maybeTableNames = schemaArgs.size() > 1 ? schemaArgs.subList(1, schemaArgs.size()) : null;
|
||||
probe.getStorageService().migrateConsensusProtocol(keyspaceNames, maybeTableNames, maybeRangesStr);
|
||||
probe.output().out.println("Marked requested ranges as migrating. Repair needs to be run in order to complete the migration");
|
||||
|
|
@ -84,16 +106,19 @@ public abstract class ConsensusMigrationAdmin extends NodeTool.NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "finish-migration", description = "Complete the migration for a range that has already begun migration")
|
||||
public static class FinishMigration extends ConsensusMigrationAdmin
|
||||
public static class FinishMigration extends AbstractCommand
|
||||
{
|
||||
@Option(title = "start_token", name = {"-st", "--start-token"}, description = "Use -st to specify a token at which the repair range starts (exclusive)")
|
||||
@Option(paramLabel = "start_token", names = {"-st", "--start-token"}, description = "Use -st to specify a token at which the repair range starts (exclusive)")
|
||||
private String startToken = null;
|
||||
|
||||
@Option(title = "end_token", name = {"-et", "--end-token"}, description = "Use -et to specify a token at which repair range ends (inclusive)")
|
||||
@Option(paramLabel = "end_token", names = {"-et", "--end-token"}, description = "Use -et to specify a token at which repair range ends (inclusive)")
|
||||
private String endToken = null;
|
||||
|
||||
@Arguments(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
private List<String> schemaArgs = new ArrayList<>();
|
||||
@Parameters(index = "0", arity = "0..1", description = "The keyspace followed by one or many tables")
|
||||
private String keyspace;
|
||||
|
||||
@Parameters(index = "1..*", arity = "0..*", description = "The tables")
|
||||
private String[] tables;
|
||||
|
||||
private static class FinishMigrationRepairCommand extends RepairCmd
|
||||
{
|
||||
|
|
@ -123,8 +148,9 @@ public abstract class ConsensusMigrationAdmin extends NodeTool.NodeToolCmd
|
|||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
checkArgument((endToken != null) == (startToken != null), "Start and end token must be specified together");
|
||||
List<String> schemaArgs = CommandUtils.concatArgs(keyspace, tables);
|
||||
String maybeRangesStr = startToken != null ? startToken + ":" + endToken : null;
|
||||
List<String> keyspaceNames = parseOptionalKeyspace(schemaArgs, probe, KeyspaceSet.ACCORD_MANAGED);
|
||||
List<String> keyspaceNames = parseOptionalKeyspaceAccordManaged(schemaArgs, probe);
|
||||
List<String> maybeTableNames = schemaArgs.size() > 1 ? schemaArgs.subList(1, schemaArgs.size()) : null;
|
||||
List<RepairCmd> repairCmds = new ArrayList<>(keyspaceNames.size() * 2);
|
||||
// Finish can't actually finish with one set of repairs when migrating from Paxos -> Accord
|
||||
|
|
|
|||
|
|
@ -20,22 +20,23 @@ package org.apache.cassandra.tools.nodetool;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import org.apache.cassandra.tools.nodetool.stats.DataPathsHolder;
|
||||
import org.apache.cassandra.tools.nodetool.stats.DataPathsPrinter;
|
||||
import org.apache.cassandra.tools.nodetool.stats.StatsPrinter;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
@Command(name = "datapaths", description = "Print all directories where data of tables are stored")
|
||||
public class DataPaths extends NodeToolCmd
|
||||
public class DataPaths extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<keyspace.table>...]", description = "List of table (or keyspace) names")
|
||||
@CassandraUsage(usage = "[<keyspace.table>...]", description = "List of table (or keyspace) names")
|
||||
@Parameters(paramLabel = "keyspace.table", description = "List of table (or keyspace) names")
|
||||
private List<String> tableNames = new ArrayList<>();
|
||||
|
||||
@Option(title = "format", name = {"-F", "--format"}, description = "Output format (json, yaml)")
|
||||
@Option(paramLabel = "format", names = { "-F", "--format" }, description = "Output format (json, yaml)")
|
||||
private String outputFormat = "";
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,17 +17,16 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "decommission", description = "Decommission the *node I am connecting to*")
|
||||
public class Decommission extends NodeToolCmd
|
||||
public class Decommission extends AbstractCommand
|
||||
{
|
||||
@Option(title = "force",
|
||||
name = {"-f", "--force"},
|
||||
|
||||
@Option(paramLabel = "force",
|
||||
names = { "-f", "--force" },
|
||||
description = "Force decommission of this node even when it reduces the number of replicas to below configured RF")
|
||||
private boolean force = false;
|
||||
|
||||
|
|
@ -57,9 +56,9 @@ public class Decommission extends NodeToolCmd
|
|||
}
|
||||
|
||||
@Command(name = "abortdecommission", description = "Abort an ongoing, failed decommission")
|
||||
public static class Abort extends NodeToolCmd
|
||||
public static class Abort extends AbstractCommand
|
||||
{
|
||||
@Option(title = "node id", name = "--node")
|
||||
@Option(paramLabel = "nodeId", names = { "--node" })
|
||||
private String nodeId;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -25,16 +25,14 @@ import java.util.SortedMap;
|
|||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.locator.DynamicEndpointSnitch;
|
||||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.locator.LocationInfoMBean;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "describecluster", description = "Print the name, snitch, partitioner and schema version of a cluster")
|
||||
public class DescribeCluster extends NodeToolCmd
|
||||
public class DescribeCluster extends WithPortDisplayAbstractCommand
|
||||
{
|
||||
private boolean resolveIp = false;
|
||||
private String keyspace = null;
|
||||
|
|
@ -114,7 +112,7 @@ public class DescribeCluster extends NodeToolCmd
|
|||
System.exit(1);
|
||||
}
|
||||
|
||||
SortedMap<String, SetHostStatWithPort> dcs = NodeTool.getOwnershipByDcWithPort(probe, resolveIp, tokensToEndpoints, ownerships);
|
||||
SortedMap<String, SetHostStatWithPort> dcs = CommandUtils.getOwnershipByDcWithPort(probe, resolveIp, tokensToEndpoints, ownerships);
|
||||
|
||||
out.println("\nData Centers: ");
|
||||
for (Map.Entry<String, SetHostStatWithPort> dc : dcs.entrySet())
|
||||
|
|
|
|||
|
|
@ -17,21 +17,20 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
|
||||
@Command(name = "describering", description = "Shows the token ranges info of a given keyspace")
|
||||
public class DescribeRing extends NodeToolCmd
|
||||
public class DescribeRing extends WithPortDisplayAbstractCommand
|
||||
{
|
||||
@Arguments(description = "The keyspace name", required = true)
|
||||
String keyspace = EMPTY;
|
||||
@Parameters(description = "The keyspace name", arity = "1")
|
||||
private String keyspace = EMPTY;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "disableauditlog", description = "Disable the audit log")
|
||||
public class DisableAuditLog extends NodeToolCmd
|
||||
public class DisableAuditLog extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,25 +17,36 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalKeyspace;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalTables;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.concatArgs;
|
||||
|
||||
@Command(name = "disableautocompaction", description = "Disable autocompaction for the given keyspace and table")
|
||||
public class DisableAutoCompaction extends NodeToolCmd
|
||||
public class DisableAutoCompaction extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
@CassandraUsage(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Parameters(index = "0", description = "The keyspace name", arity = "0..1")
|
||||
private String keyspace;
|
||||
|
||||
@Parameters(index = "1..*", description = "The table names", arity = "0..*")
|
||||
private String[] tables;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
args = concatArgs(keyspace, tables);
|
||||
|
||||
List<String> keyspaces = parseOptionalKeyspace(args, probe);
|
||||
String[] tablenames = parseOptionalTables(args);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "disablebackup", description = "Disable incremental backup")
|
||||
public class DisableBackup extends NodeToolCmd
|
||||
public class DisableBackup extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,15 +17,14 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "disablebinary", description = "Disable native transport (binary protocol)")
|
||||
public class DisableBinary extends NodeToolCmd
|
||||
public class DisableBinary extends AbstractCommand
|
||||
{
|
||||
@Option(title = "force", name = { "-f", "--force"}, description = "Use -f to interrupt client requests that have already started")
|
||||
@Option(paramLabel = "force", names = { "-f", "--force" }, description = "Use -f to interrupt client requests that have already started")
|
||||
private boolean force = false;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "disablefullquerylog", description = "Disable the full query log")
|
||||
public class DisableFullQueryLog extends NodeToolCmd
|
||||
public class DisableFullQueryLog extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "disablegossip", description = "Disable gossip (effectively marking the node down)")
|
||||
public class DisableGossip extends NodeToolCmd
|
||||
public class DisableGossip extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "disablehandoff", description = "Disable storing hinted handoffs")
|
||||
public class DisableHandoff extends NodeToolCmd
|
||||
public class DisableHandoff extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -20,17 +20,17 @@ package org.apache.cassandra.tools.nodetool;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
@Command(name = "disablehintsfordc", description = "Disable hints for a data center")
|
||||
public class DisableHintsForDC extends NodeTool.NodeToolCmd
|
||||
public class DisableHintsForDC extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "<datacenter>", description = "The data center to disable")
|
||||
@Parameters(paramLabel = "datacenter", description = "The data center to disable")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "disableoldprotocolversions", description = "Disable old protocol versions")
|
||||
public class DisableOldProtocolVersions extends NodeTool.NodeToolCmd
|
||||
public class DisableOldProtocolVersions extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,16 +17,15 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "drain", description = "Drain the node (stop accepting writes and flush all tables)")
|
||||
public class Drain extends NodeToolCmd
|
||||
public class Drain extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,34 +17,26 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.auth.AuthKeyspace;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
/**
|
||||
* Nodetool command to drop a CIDR group and associated mapping from the table {@link AuthKeyspace#CIDR_GROUPS}
|
||||
*/
|
||||
@Command(name = "dropcidrgroup", description = "Drop an existing cidr group")
|
||||
public class DropCIDRGroup extends NodeToolCmd
|
||||
public class DropCIDRGroup extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "<cidrGroup>", description = "Requires a cidr group name")
|
||||
private List<String> args = new ArrayList<>();
|
||||
@Parameters(paramLabel = "cidrGroup", description = "Requires a cidr group name", index = "0", arity = "1")
|
||||
private String cidrGroup;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
checkArgument(args.size() == 1, "dropcidrgroup command requires a cidr group name");
|
||||
probe.dropCidrGroup(cidrGroup);
|
||||
|
||||
String cidrGroupName = args.get(0);
|
||||
probe.dropCidrGroup(cidrGroupName);
|
||||
|
||||
probe.output().out.println("Deleted CIDR group " + cidrGroupName);
|
||||
probe.output().out.println("Deleted CIDR group " + cidrGroup);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,54 +20,53 @@ package org.apache.cassandra.tools.nodetool;
|
|||
|
||||
import java.util.Collections;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "enableauditlog", description = "Enable the audit log")
|
||||
public class EnableAuditLog extends NodeToolCmd
|
||||
public class EnableAuditLog extends AbstractCommand
|
||||
{
|
||||
@Option(title = "logger", name = { "--logger" }, description = "Logger name to be used for AuditLogging. Default BinAuditLogger. If not set the value from cassandra.yaml will be used")
|
||||
@Option(paramLabel = "logger", names = { "--logger" }, description = "Logger name to be used for AuditLogging. Default BinAuditLogger. If not set the value from cassandra.yaml will be used")
|
||||
private String logger = null;
|
||||
|
||||
@Option(title = "included_keyspaces", name = { "--included-keyspaces" }, description = "Comma separated list of keyspaces to be included for audit log. If not set the value from cassandra.yaml will be used")
|
||||
@Option(paramLabel = "included_keyspaces", names = { "--included-keyspaces" }, description = "Comma separated list of keyspaces to be included for audit log. If not set the value from cassandra.yaml will be used")
|
||||
private String included_keyspaces = null;
|
||||
|
||||
@Option(title = "excluded_keyspaces", name = { "--excluded-keyspaces" }, description = "Comma separated list of keyspaces to be excluded for audit log. If not set the value from cassandra.yaml will be used")
|
||||
@Option(paramLabel = "excluded_keyspaces", names = { "--excluded-keyspaces" }, description = "Comma separated list of keyspaces to be excluded for audit log. If not set the value from cassandra.yaml will be used")
|
||||
private String excluded_keyspaces = null;
|
||||
|
||||
@Option(title = "included_categories", name = { "--included-categories" }, description = "Comma separated list of Audit Log Categories to be included for audit log. If not set the value from cassandra.yaml will be used")
|
||||
@Option(paramLabel = "included_categories", names = { "--included-categories" }, description = "Comma separated list of Audit Log Categories to be included for audit log. If not set the value from cassandra.yaml will be used")
|
||||
private String included_categories = null;
|
||||
|
||||
@Option(title = "excluded_categories", name = { "--excluded-categories" }, description = "Comma separated list of Audit Log Categories to be excluded for audit log. If not set the value from cassandra.yaml will be used")
|
||||
@Option(paramLabel = "excluded_categories", names = { "--excluded-categories" }, description = "Comma separated list of Audit Log Categories to be excluded for audit log. If not set the value from cassandra.yaml will be used")
|
||||
private String excluded_categories = null;
|
||||
|
||||
@Option(title = "included_users", name = { "--included-users" }, description = "Comma separated list of users to be included for audit log. If not set the value from cassandra.yaml will be used")
|
||||
@Option(paramLabel = "included_users", names = { "--included-users" }, description = "Comma separated list of users to be included for audit log. If not set the value from cassandra.yaml will be used")
|
||||
private String included_users = null;
|
||||
|
||||
@Option(title = "excluded_users", name = { "--excluded-users" }, description = "Comma separated list of users to be excluded for audit log. If not set the value from cassandra.yaml will be used")
|
||||
@Option(paramLabel = "excluded_users", names = { "--excluded-users" }, description = "Comma separated list of users to be excluded for audit log. If not set the value from cassandra.yaml will be used")
|
||||
private String excluded_users = null;
|
||||
|
||||
@Option(title = "roll_cycle", name = {"--roll-cycle"}, description = "How often to roll the log file (MINUTELY, HOURLY, DAILY).")
|
||||
@Option(paramLabel = "roll_cycle", names = { "--roll-cycle" }, description = "How often to roll the log file (MINUTELY, HOURLY, DAILY).")
|
||||
private String rollCycle = null;
|
||||
|
||||
@Option(title = "blocking", name = {"--blocking"}, description = "If the queue is full whether to block producers or drop samples [true|false].")
|
||||
@Option(paramLabel = "blocking", names = { "--blocking" }, description = "If the queue is full whether to block producers or drop samples [true|false].")
|
||||
private String blocking = null;
|
||||
|
||||
@Option(title = "max_queue_weight", name = {"--max-queue-weight"}, description = "Maximum number of bytes of query data to queue to disk before blocking or dropping samples.")
|
||||
@Option(paramLabel = "max_queue_weight", names = { "--max-queue-weight" }, description = "Maximum number of bytes of query data to queue to disk before blocking or dropping samples.")
|
||||
private int maxQueueWeight = Integer.MIN_VALUE;
|
||||
|
||||
@Option(title = "max_log_size", name = {"--max-log-size"}, description = "How many bytes of log data to store before dropping segments. Might not be respected if a log file hasn't rolled so it can be deleted.")
|
||||
@Option(paramLabel = "max_log_size", names = { "--max-log-size" }, description = "How many bytes of log data to store before dropping segments. Might not be respected if a log file hasn't rolled so it can be deleted.")
|
||||
private long maxLogSize = Long.MIN_VALUE;
|
||||
|
||||
@Option(title = "archive_command", name = {"--archive-command"}, description = "Command that will handle archiving rolled audit log files." +
|
||||
" Format is \"/path/to/script.sh %path\" where %path will be replaced with the file to archive" +
|
||||
@Option(paramLabel = "archive_command", names = { "--archive-command" }, description = "Command that will handle archiving rolled audit log files." +
|
||||
" Format is \"/path/to/script.sh %%path\" where %%path will be replaced with the file to archive" +
|
||||
" Enable this by setting the audit_logging_options.allow_nodetool_archive_command: true in the config.")
|
||||
|
||||
private String archiveCommand = null;
|
||||
|
||||
@Option(title = "archive_retries", name = {"--max-archive-retries"}, description = "Max number of archive retries.")
|
||||
@Option(paramLabel = "archive_retries", names = { "--max-archive-retries" }, description = "Max number of archive retries.")
|
||||
private int archiveRetries = Integer.MIN_VALUE;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,25 +17,37 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalKeyspace;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalTables;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.concatArgs;
|
||||
|
||||
@Command(name = "enableautocompaction", description = "Enable autocompaction for the given keyspace and table")
|
||||
public class EnableAutoCompaction extends NodeToolCmd
|
||||
public class EnableAutoCompaction extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
@CassandraUsage(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Parameters(index = "0", description = "The keyspace to enable auto-compaction on", arity = "0..1")
|
||||
private String keyspace;
|
||||
|
||||
@Parameters(index = "1..*", description = "The tables to enable auto-compaction on", arity = "0..*")
|
||||
private String[] tables;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
args = concatArgs(keyspace, tables);
|
||||
|
||||
List<String> keyspaces = parseOptionalKeyspace(args, probe);
|
||||
String[] tableNames = parseOptionalTables(args);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "enablebackup", description = "Enable incremental backup")
|
||||
public class EnableBackup extends NodeToolCmd
|
||||
public class EnableBackup extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "enablebinary", description = "Reenable native transport (binary protocol)")
|
||||
public class EnableBinary extends NodeToolCmd
|
||||
public class EnableBinary extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -18,35 +18,34 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "enablefullquerylog", description = "Enable full query logging, defaults for the options are configured in cassandra.yaml")
|
||||
public class EnableFullQueryLog extends NodeToolCmd
|
||||
public class EnableFullQueryLog extends AbstractCommand
|
||||
{
|
||||
@Option(title = "roll_cycle", name = {"--roll-cycle"}, description = "How often to roll the log file (MINUTELY, HOURLY, DAILY).")
|
||||
@Option(paramLabel = "roll_cycle", names = { "--roll-cycle" }, description = "How often to roll the log file (MINUTELY, HOURLY, DAILY).")
|
||||
private String rollCycle = null;
|
||||
|
||||
@Option(title = "blocking", name = {"--blocking"}, description = "If the queue is full whether to block producers or drop samples [true|false].")
|
||||
@Option(paramLabel = "blocking", names = { "--blocking" }, description = "If the queue is full whether to block producers or drop samples [true|false].")
|
||||
private String blocking = null;
|
||||
|
||||
@Option(title = "max_queue_weight", name = {"--max-queue-weight"}, description = "Maximum number of bytes of query data to queue to disk before blocking or dropping samples.")
|
||||
@Option(paramLabel = "max_queue_weight", names = { "--max-queue-weight" }, description = "Maximum number of bytes of query data to queue to disk before blocking or dropping samples.")
|
||||
private int maxQueueWeight = Integer.MIN_VALUE;
|
||||
|
||||
@Option(title = "max_log_size", name = {"--max-log-size"}, description = "How many bytes of log data to store before dropping segments. Might not be respected if a log file hasn't rolled so it can be deleted.")
|
||||
@Option(paramLabel = "max_log_size", names = { "--max-log-size" }, description = "How many bytes of log data to store before dropping segments. Might not be respected if a log file hasn't rolled so it can be deleted.")
|
||||
private long maxLogSize = Long.MIN_VALUE;
|
||||
|
||||
@Option(title = "path", name = {"--path"}, description = "Path to store the full query log at. Will have it's contents recursively deleted.")
|
||||
@Option(paramLabel = "path", names = { "--path" }, description = "Path to store the full query log at. Will have it's contents recursively deleted.")
|
||||
private String path = null;
|
||||
|
||||
@Option(title = "archive_command", name = {"--archive-command"}, description = "Command that will handle archiving rolled full query log files." +
|
||||
" Format is \"/path/to/script.sh %path\" where %path will be replaced with the file to archive" +
|
||||
@Option(paramLabel = "archive_command", names = { "--archive-command" }, description = "Command that will handle archiving rolled full query log files." +
|
||||
" Format is \"/path/to/script.sh %%path\" where %%path will be replaced with the file to archive" +
|
||||
" Enable this by setting the full_query_logging_options.allow_nodetool_archive_command: true in the config.")
|
||||
private String archiveCommand = null;
|
||||
|
||||
@Option(title = "archive_retries", name = {"--max-archive-retries"}, description = "Max number of archive retries.")
|
||||
@Option(paramLabel = "archive_retries", names = { "--max-archive-retries" }, description = "Max number of archive retries.")
|
||||
private int archiveRetries = Integer.MIN_VALUE;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "enablegossip", description = "Reenable gossip")
|
||||
public class EnableGossip extends NodeToolCmd
|
||||
public class EnableGossip extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "enablehandoff", description = "Reenable future hints storing on the current node")
|
||||
public class EnableHandoff extends NodeToolCmd
|
||||
public class EnableHandoff extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,26 +17,19 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
@Command(name = "enablehintsfordc", description = "Enable hints for a data center that was previsouly disabled")
|
||||
public class EnableHintsForDC extends NodeTool.NodeToolCmd
|
||||
public class EnableHintsForDC extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "<datacenter>", description = "The data center to enable")
|
||||
private List<String> args = new ArrayList<>();
|
||||
@Parameters(paramLabel = "datacenter", description = "The data center to enable", index = "0", arity = "1")
|
||||
private String datacenter;
|
||||
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
checkArgument(args.size() == 1, "enablehintsfordc requires exactly one data center");
|
||||
|
||||
probe.enableHintsForDC(args.get(0));
|
||||
probe.enableHintsForDC(datacenter);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,13 +18,11 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "enableoldprotocolversions", description = "Enable old protocol versions")
|
||||
public class EnableOldProtocolVersions extends NodeTool.NodeToolCmd
|
||||
public class EnableOldProtocolVersions extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,18 +17,15 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.TabularData;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "failuredetector", description = "Shows the failure detector information for the cluster")
|
||||
public class FailureDetectorInfo extends NodeToolCmd
|
||||
public class FailureDetectorInfo extends WithPortDisplayAbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,24 +17,35 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalKeyspace;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalTables;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.concatArgs;
|
||||
|
||||
@Command(name = "flush", description = "Flush one or more tables")
|
||||
public class Flush extends NodeToolCmd
|
||||
public class Flush extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
@CassandraUsage(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Parameters(index = "0", description = "The keyspace followed by one or many tables to flush", arity = "0..1")
|
||||
private String keyspace;
|
||||
|
||||
@Parameters(index = "1..*", description = "The tables to flush", arity = "0..*")
|
||||
private String[] tables;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
args = concatArgs(keyspace, tables);
|
||||
|
||||
List<String> keyspaces = parseOptionalKeyspace(args, probe);
|
||||
String[] tableNames = parseOptionalTables(args);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,26 +18,37 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parsePartitionKeys;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.concatArgs;
|
||||
|
||||
@Command(name = "forcecompact", description = "Force a (major) compaction on a table")
|
||||
public class ForceCompact extends NodeToolCmd
|
||||
public class ForceCompact extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<keyspace> <table> <keys>]", description = "The keyspace, table, and a list of partition keys ignoring the gc_grace_seconds")
|
||||
@CassandraUsage(usage = "[<keyspace> <table> <keys>]", description = "The keyspace, table, and a list of partition keys ignoring the gc_grace_seconds")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Parameters(index = "0", description = "The keyspace name to compact", arity = "0..1")
|
||||
private String keyspace;
|
||||
|
||||
@Parameters(index = "1", description = "The table name to compact", arity = "0..1")
|
||||
private String table;
|
||||
|
||||
@Parameters(index = "2..*", description = "The partition keys to compact", arity = "0..*")
|
||||
private String[] keys;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
args = concatArgs(keyspace, table, keys);
|
||||
// Check if the input has valid size
|
||||
checkArgument(args.size() >= 3, "forcecompact requires keyspace, table and keys args");
|
||||
|
||||
|
|
|
|||
|
|
@ -17,30 +17,40 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.schema.CompactionParams;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Parameters;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalKeyspace;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.parseOptionalTables;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.concatArgs;
|
||||
|
||||
@Command(name = "garbagecollect", description = "Remove deleted data from one or more tables")
|
||||
public class GarbageCollect extends NodeToolCmd
|
||||
public class GarbageCollect extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
@CassandraUsage(usage = "[<keyspace> <tables>...]", description = "The keyspace followed by one or many tables")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Option(title = "granularity",
|
||||
name = {"-g", "--granularity"},
|
||||
allowedValues = {"ROW", "CELL"},
|
||||
description = "Granularity of garbage removal. ROW (default) removes deleted partitions and rows, CELL also removes overwritten or deleted cells.")
|
||||
private String tombstoneOption = "ROW";
|
||||
@Parameters(index = "0", description = "The keyspace followed by one or many tables to garbage collect", arity = "0..1")
|
||||
private String keyspace;
|
||||
|
||||
@Option(title = "jobs",
|
||||
name = {"-j", "--jobs"},
|
||||
@Parameters(index = "1..*", description = "The tables to garbage collect", arity = "0..*")
|
||||
private String[] tables;
|
||||
|
||||
@Option(paramLabel = "granularity",
|
||||
names = { "-g", "--granularity" },
|
||||
description = "Granularity of garbage removal. ROW (default) removes deleted partitions and rows, CELL also removes overwritten or deleted cells.")
|
||||
private CompactionParams.TombstoneOption tombstoneOption = CompactionParams.TombstoneOption.ROW;
|
||||
|
||||
@Option(paramLabel = "jobs",
|
||||
names = { "-j", "--jobs" },
|
||||
description = "Number of sstables to cleanup simultanously, set to 0 to use all available compaction " +
|
||||
"threads. Defaults to 1 so that collections of newer tables can see the data is deleted " +
|
||||
"and also remove tombstones.")
|
||||
|
|
@ -49,6 +59,8 @@ public class GarbageCollect extends NodeToolCmd
|
|||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
args = concatArgs(keyspace, tables);
|
||||
|
||||
List<String> keyspaces = parseOptionalKeyspace(args, probe);
|
||||
String[] tableNames = parseOptionalTables(args);
|
||||
|
||||
|
|
@ -56,7 +68,7 @@ public class GarbageCollect extends NodeToolCmd
|
|||
{
|
||||
try
|
||||
{
|
||||
probe.garbageCollect(probe.output().out, tombstoneOption, jobs, keyspace, tableNames);
|
||||
probe.garbageCollect(probe.output().out, tombstoneOption.toString(), jobs, keyspace, tableNames);
|
||||
} catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException("Error occurred during garbage collection", e);
|
||||
|
|
|
|||
|
|
@ -17,23 +17,22 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.stats.GcStatsHolder;
|
||||
import org.apache.cassandra.tools.nodetool.stats.GcStatsPrinter;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "gcstats", description = "Print GC Statistics")
|
||||
public class GcStats extends NodeToolCmd
|
||||
public class GcStats extends AbstractCommand
|
||||
{
|
||||
@Option(title = "format",
|
||||
name = { "-F", "--format" },
|
||||
@Option(paramLabel = "format",
|
||||
names = { "-F", "--format" },
|
||||
description = "Output format (json, yaml, table)")
|
||||
private String outputFormat = "";
|
||||
|
||||
@Option(title = "human_readable",
|
||||
name = { "-H", "--human-readable" },
|
||||
@Option(paramLabel = "human_readable",
|
||||
names = { "-H", "--human-readable" },
|
||||
description = "Display gcstats with human-readable units")
|
||||
private boolean humanReadable = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,14 +18,13 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.audit.AuditLogOptions;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "getauditlog", description = "Print configuration of audit log if enabled, otherwise the configuration reflected in cassandra.yaml")
|
||||
public class GetAuditLog extends NodeTool.NodeToolCmd
|
||||
public class GetAuditLog extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
protected void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -18,18 +18,16 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.auth.AuthCacheMBean;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "getauthcacheconfig", description = "Get configuration of Auth cache")
|
||||
public class GetAuthCacheConfig extends NodeTool.NodeToolCmd
|
||||
public class GetAuthCacheConfig extends AbstractCommand
|
||||
{
|
||||
@SuppressWarnings("unused")
|
||||
@Option(title = "cache-name",
|
||||
name = {"--cache-name"},
|
||||
@Option(paramLabel = "cache-name",
|
||||
names = { "--cache-name" },
|
||||
description = "Name of Auth cache (required)",
|
||||
required = true)
|
||||
private String cacheName;
|
||||
|
|
|
|||
|
|
@ -21,15 +21,14 @@ import java.io.PrintStream;
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
/**
|
||||
* Prints all the configurations for AutoRepair through nodetool.
|
||||
*/
|
||||
@Command(name = "getautorepairconfig", description = "Print autorepair configurations")
|
||||
public class GetAutoRepairConfig extends NodeToolCmd
|
||||
public class GetAutoRepairConfig extends AbstractCommand
|
||||
{
|
||||
@VisibleForTesting
|
||||
protected static PrintStream out = System.out;
|
||||
|
|
|
|||
|
|
@ -17,13 +17,12 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "getbatchlogreplaythrottle", description = "Print batchlog replay throttle in KB/s. " +
|
||||
"This is reduced proportionally to the number of nodes in the cluster.")
|
||||
public class GetBatchlogReplayTrottle extends NodeToolCmd
|
||||
public class GetBatchlogReplayTrottle extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,34 +17,24 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.printSet;
|
||||
|
||||
/**
|
||||
* Nodetool command to get CIDR groups(s) of given IP
|
||||
*/
|
||||
@Command(name = "getcidrgroupsofip", description = "Print CIDR groups associated with given IP")
|
||||
public class GetCIDRGroupsOfIP extends NodeToolCmd
|
||||
public class GetCIDRGroupsOfIP extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "<IP address>", description = "Requires IP address as a string")
|
||||
private List<String> args = new ArrayList<>();
|
||||
@Parameters(paramLabel = "ip_address", description = "Requires IP address as a string", arity = "1", index = "0")
|
||||
private String ipStr;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
PrintStream out = probe.output().out;
|
||||
|
||||
checkArgument(args.size() == 1, "Requires IP address as input");
|
||||
|
||||
String ipStr = args.get(0);
|
||||
probe.printSet(out, "CIDR Groups", probe.getCidrGroupsOfIp(ipStr));
|
||||
printSet(probe.output().out, "CIDR Groups", probe.getCidrGroupsOfIp(ipStr));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "getcolumnindexsize", description = "Print the granularity of the collation index of rows within a partition in KiB")
|
||||
public class GetColumnIndexSize extends NodeToolCmd
|
||||
public class GetColumnIndexSize extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
protected void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -18,25 +18,34 @@
|
|||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.concatArgs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.db.ColumnFamilyStoreMBean;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
@Command(name = "getcompactionthreshold", description = "Print min and max compaction thresholds for a given table")
|
||||
public class GetCompactionThreshold extends NodeToolCmd
|
||||
public class GetCompactionThreshold extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "<keyspace> <table>", description = "The keyspace with a table")
|
||||
@CassandraUsage(usage = "<keyspace> <table>", description = "The keyspace with a table")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Parameters(index = "0", arity = "1", description = "The keyspace to get the compaction threshold for")
|
||||
private String keyspace;
|
||||
|
||||
@Parameters(index = "1", arity = "1", description = "The table to get the compaction threshold for")
|
||||
private String table;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
args = concatArgs(keyspace, table);
|
||||
|
||||
checkArgument(args.size() == 2, "getcompactionthreshold requires ks and cf args");
|
||||
String ks = args.get(0);
|
||||
String cf = args.get(1);
|
||||
|
|
|
|||
|
|
@ -21,17 +21,14 @@ import java.util.Map;
|
|||
|
||||
import com.google.common.math.DoubleMath;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "getcompactionthroughput", description = "Print the MiB/s throughput cap for compaction in the system as a rounded number")
|
||||
public class GetCompactionThroughput extends NodeToolCmd
|
||||
public class GetCompactionThroughput extends AbstractCommand
|
||||
{
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Option(name = { "-d", "--precise-mib" }, description = "Print the MiB/s throughput cap for compaction in the system as a precise number (double)")
|
||||
@Option(names = { "-d", "--precise-mib" }, description = "Print the MiB/s throughput cap for compaction in the system as a precise number (double)")
|
||||
private boolean compactionThroughputAsDouble;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -21,17 +21,16 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Parameters;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "getconcurrency", description = "Get maximum concurrency for processing stages")
|
||||
public class GetConcurrency extends NodeToolCmd
|
||||
public class GetConcurrency extends AbstractCommand
|
||||
{
|
||||
@Arguments(title = "[stage-names]",
|
||||
usage = "[stage-names]",
|
||||
description = "optional list of stage names, otherwise display all stages")
|
||||
@Parameters(paramLabel = "stage-names",
|
||||
description = "Optional list of stage names, otherwise display all stages",
|
||||
index = "0..*")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "getconcurrentcompactors", description = "Get the number of concurrent compactors in the system.")
|
||||
public class GetConcurrentCompactors extends NodeToolCmd
|
||||
public class GetConcurrentCompactors extends AbstractCommand
|
||||
{
|
||||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "getconcurrentviewbuilders", description = "Get the number of concurrent view builders in the system")
|
||||
public class GetConcurrentViewBuilders extends NodeToolCmd
|
||||
public class GetConcurrentViewBuilders extends AbstractCommand
|
||||
{
|
||||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "getdefaultrf", description = "Gets default keyspace replication factor.")
|
||||
public class GetDefaultKeyspaceRF extends NodeTool.NodeToolCmd
|
||||
public class GetDefaultKeyspaceRF extends AbstractCommand
|
||||
{
|
||||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,26 +17,38 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Parameters;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.concatArgs;
|
||||
|
||||
@Command(name = "getendpoints", description = "Print the end points that owns the key")
|
||||
public class GetEndpoints extends NodeToolCmd
|
||||
public class GetEndpoints extends WithPortDisplayAbstractCommand
|
||||
{
|
||||
@Arguments(usage = "<keyspace> <table> <key>", description = "The keyspace, the table, and the partition key for which we need to find the endpoint")
|
||||
@CassandraUsage(usage = "<keyspace> <table> <key>", description = "The keyspace, the table, and the partition key for which we need to find the endpoint")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Parameters(index = "0", arity = "0..1", description = "The keyspace for which we need to find the endpoint")
|
||||
private String keyspace;
|
||||
|
||||
@Parameters(index = "1", arity = "0..1", description = "The table for which we need to find the endpoint")
|
||||
private String table;
|
||||
|
||||
@Parameters(index = "2", arity = "0..1", description = "The partition key for which we need to find the endpoint")
|
||||
private String key;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
args = concatArgs(keyspace, table, key);
|
||||
|
||||
checkArgument(args.size() == 3, "getendpoints requires keyspace, table and partition key arguments");
|
||||
String ks = args.get(0);
|
||||
String table = args.get(1);
|
||||
|
|
|
|||
|
|
@ -18,14 +18,13 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.fql.FullQueryLoggerOptions;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "getfullquerylog", description = "Print configuration of fql if enabled, otherwise the configuration reflected in cassandra.yaml")
|
||||
public class GetFullQueryLog extends NodeToolCmd
|
||||
public class GetFullQueryLog extends AbstractCommand
|
||||
{
|
||||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,25 +19,21 @@ package org.apache.cassandra.tools.nodetool;
|
|||
|
||||
import com.google.common.math.DoubleMath;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "getinterdcstreamthroughput", description = "Print the throughput cap for inter-datacenter streaming and entire SSTable inter-datacenter streaming in the system" +
|
||||
"in rounded megabits. For precise number, please, use option -d")
|
||||
public class GetInterDCStreamThroughput extends NodeToolCmd
|
||||
public class GetInterDCStreamThroughput extends AbstractCommand
|
||||
{
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Option(name = { "-e", "--entire-sstable-throughput" }, description = "Print entire SSTable streaming throughput in MiB/s")
|
||||
@Option(names = { "-e", "--entire-sstable-throughput" }, description = "Print entire SSTable streaming throughput in MiB/s")
|
||||
private boolean entireSSTableThroughput;
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Option(name = { "-m", "--mib" }, description = "Print the throughput cap for inter-datacenter streaming in MiB/s")
|
||||
@Option(names = { "-m", "--mib" }, description = "Print the throughput cap for inter-datacenter streaming in MiB/s")
|
||||
private boolean interDCStreamThroughputMiB;
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Option(name = { "-d", "--precise-mbit" }, description = "Print the throughput cap for inter-datacenter streaming in precise Mbits (double)")
|
||||
@Option(names = { "-d", "--precise-mbit" }, description = "Print the throughput cap for inter-datacenter streaming in precise Mbits (double)")
|
||||
private boolean interDCStreamThroughputDoubleMbit;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,15 +17,13 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "getlogginglevels", description = "Get the runtime logging levels")
|
||||
public class GetLoggingLevels extends NodeToolCmd
|
||||
public class GetLoggingLevels extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "getmaxhintwindow", description = "Print the max hint window in ms")
|
||||
public class GetMaxHintWindow extends NodeTool.NodeToolCmd
|
||||
public class GetMaxHintWindow extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,36 +17,48 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.concatArgs;
|
||||
|
||||
@Command(name = "getsstables", description = "Print the sstable filenames that own the key")
|
||||
public class GetSSTables extends NodeToolCmd
|
||||
public class GetSSTables extends AbstractCommand
|
||||
{
|
||||
@Option(title = "hex_format",
|
||||
name = {"-hf", "--hex-format"},
|
||||
@Option(paramLabel = "hex_format",
|
||||
names = { "-hf", "--hex-format" },
|
||||
description = "Specify the key in hexadecimal string format")
|
||||
private boolean hexFormat = false;
|
||||
|
||||
@Option(name={"-l", "--show-levels"}, description="If the table is using leveled compaction the level of each sstable will be included in the output (Default: false)")
|
||||
@Option(names = { "-l", "--show-levels" }, description = "If the table is using leveled compaction the level of each sstable will be included in the output (Default: false)")
|
||||
private boolean showLevels = false;
|
||||
|
||||
@Arguments(usage = "<keyspace> <cfname> <key>", description = "The keyspace, the column family, and the key")
|
||||
@CassandraUsage(usage = "<keyspace> <cfname> <key>", description = "The keyspace, the column family, and the key")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Parameters(paramLabel = "keyspace", index = "0", arity = "0..1", description = "The keyspace")
|
||||
private String keyspace;
|
||||
|
||||
@Parameters(paramLabel = "cfname", index = "1", arity = "0..1", description = "The column family")
|
||||
private String cfname;
|
||||
|
||||
@Parameters(paramLabel = "key", index = "2", arity = "0..1", description = "The key")
|
||||
private String key;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
args = concatArgs(keyspace, cfname, key);
|
||||
|
||||
checkArgument(args.size() == 3, "getsstables requires ks, cf and key args");
|
||||
String ks = args.get(0);
|
||||
String cf = args.get(1);
|
||||
|
|
|
|||
|
|
@ -19,13 +19,11 @@ package org.apache.cassandra.tools.nodetool;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "getseeds", description = "Get the currently in use seed node IP list excluding the node IP")
|
||||
public class GetSeeds extends NodeToolCmd
|
||||
public class GetSeeds extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,20 +17,19 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "getsnapshotthrottle", description = "Print the snapshot_links_per_second throttle for snapshot/clearsnapshot")
|
||||
public class GetSnapshotThrottle extends NodeToolCmd
|
||||
public class GetSnapshotThrottle extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
long throttle = probe.getSnapshotLinksPerSecond();
|
||||
if (throttle > 0)
|
||||
System.out.println("Current snapshot throttle: " + throttle + " links/s");
|
||||
output.printInfo("Current snapshot throttle: %s links/s", throttle);
|
||||
else
|
||||
System.out.println("Snapshot throttle is disabled");
|
||||
output.printInfo("Snapshot throttle is disabled");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,25 +19,21 @@ package org.apache.cassandra.tools.nodetool;
|
|||
|
||||
import com.google.common.math.DoubleMath;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "getstreamthroughput", description = "Print the throughput cap for streaming and entire SSTable streaming in the system in rounded megabits. " +
|
||||
"For precise number, please, use option -d")
|
||||
public class GetStreamThroughput extends NodeToolCmd
|
||||
public class GetStreamThroughput extends AbstractCommand
|
||||
{
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Option(name = { "-e", "--entire-sstable-throughput" }, description = "Print entire SSTable streaming throughput in MiB/s")
|
||||
@Option(names = { "-e", "--entire-sstable-throughput" }, description = "Print entire SSTable streaming throughput in MiB/s")
|
||||
private boolean entireSSTableThroughput;
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Option(name = { "-m", "--mib" }, description = "Print the throughput cap for streaming in MiB/s")
|
||||
@Option(names = { "-m", "--mib" }, description = "Print the throughput cap for streaming in MiB/s")
|
||||
private boolean streamThroughputMiB;
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Option(name = { "-d", "--precise-mbit" }, description = "Print the throughput cap for streaming in precise Mbits (double)")
|
||||
@Option(names = { "-d", "--precise-mbit" }, description = "Print the throughput cap for streaming in precise Mbits (double)")
|
||||
private boolean streamThroughputDoubleMbit;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,32 +17,32 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
@Command(name = "gettimeout", description = "Print the timeout of the given type in ms")
|
||||
public class GetTimeout extends NodeToolCmd
|
||||
public class GetTimeout extends AbstractCommand
|
||||
{
|
||||
public static final String TIMEOUT_TYPES = "read, range, write, counterwrite, cascontention, truncate, internodeconnect, internodeuser, internodestreaminguser, misc (general rpc_timeout_in_ms)";
|
||||
|
||||
@Arguments(usage = "<timeout_type>", description = "The timeout type, one of (" + TIMEOUT_TYPES + ")")
|
||||
@CassandraUsage(usage = "<timeout_type>", description = "The timeout type, one of (" + TIMEOUT_TYPES + ")")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Parameters (index = "0", description = "The timeout type, one of (" + TIMEOUT_TYPES + ')', arity = "1")
|
||||
private String timeout_type;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
checkArgument(args.size() == 1, "gettimeout requires a timeout type, one of (" + TIMEOUT_TYPES + ")");
|
||||
try
|
||||
{
|
||||
probe.output().out.println("Current timeout for type " + args.get(0) + ": " + probe.getTimeout(args.get(0)) + " ms");
|
||||
probe.output().out.println("Current timeout for type " + timeout_type + ": " + probe.getTimeout(timeout_type) + " ms");
|
||||
} catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException(e.getMessage());
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "gettraceprobability", description = "Print the current trace probability value")
|
||||
public class GetTraceProbability extends NodeToolCmd
|
||||
public class GetTraceProbability extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -17,16 +17,14 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "gossipinfo", description = "Shows the gossip information for the cluster")
|
||||
public class GossipInfo extends NodeToolCmd
|
||||
public class GossipInfo extends WithPortDisplayAbstractCommand
|
||||
{
|
||||
@Option(title = "resolve_ip", name = {"-r", "--resolve-ip"}, description = "Show node domain names instead of IPs")
|
||||
@Option(paramLabel = "resolve_ip", names = { "-r", "--resolve-ip" }, description = "Show node domain names instead of IPs")
|
||||
private boolean resolveIp = false;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
|
@ -37,48 +36,41 @@ import java.util.stream.Stream;
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.db.guardrails.GuardrailsMBean;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool;
|
||||
import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import org.apache.cassandra.utils.LocalizeString;
|
||||
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.Comparator.comparing;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
public abstract class GuardrailsConfigCommand extends NodeTool.NodeToolCmd
|
||||
public abstract class GuardrailsConfigCommand extends AbstractCommand
|
||||
{
|
||||
@Command(name = "getguardrailsconfig", description = "Print runtime configuration of guardrails.")
|
||||
public static class GetGuardrailsConfig extends GuardrailsConfigCommand
|
||||
{
|
||||
@Option(name = { "--category", "-c" },
|
||||
description = "Category of guardrails to filter, can be one of 'values', 'thresholds', 'flags', 'others'.",
|
||||
allowedValues = { "values", "thresholds", "flags", "others" })
|
||||
private String guardrailCategory;
|
||||
@Option(names = { "--category", "-c" },
|
||||
description = "Category of guardrails to filter, can be one of 'values', 'thresholds', 'flags', 'others'.")
|
||||
private GuardrailCategory guardrailCategory;
|
||||
|
||||
@Option(name = { "--expand" },
|
||||
@Option(names = { "--expand" },
|
||||
description = "Expand all guardrail names so they reflect their counterparts in cassandra.yaml")
|
||||
private boolean expand = false;
|
||||
|
||||
@Arguments(description = "Specific name of a guardrail to get configuration of.")
|
||||
private List<String> args = new ArrayList<>();
|
||||
@Parameters(index = "0", arity = "0..1", description = "Specific name of a guardrail to get configuration of or all guardrails if not specified.")
|
||||
private String guardrailName;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
GuardrailCategory categoryEnum = GuardrailCategory.parseCategory(guardrailCategory, probe.output().out);
|
||||
|
||||
if (args.size() > 1)
|
||||
throw new IllegalStateException("Specify only one guardrail name to get the configuration of or no name to get the configuration of all of them.");
|
||||
|
||||
String guardrailName = !args.isEmpty() ? args.get(0) : null;
|
||||
|
||||
if (guardrailName != null && categoryEnum != null)
|
||||
if (guardrailName != null && guardrailCategory != null)
|
||||
throw new IllegalStateException("Do not specify additional arguments when --category/-c is set.");
|
||||
|
||||
Map<String, List<Method>> allGetters = parseGuardrailNames(probe.getGuardrailsMBean().getClass().getDeclaredMethods(), guardrailName);
|
||||
|
|
@ -89,7 +81,7 @@ public abstract class GuardrailsConfigCommand extends NodeTool.NodeToolCmd
|
|||
throw new IllegalStateException(format("Guardrail %s not found.", guardrailName));
|
||||
}
|
||||
|
||||
display(probe, allGetters, categoryEnum, expand);
|
||||
display(probe, allGetters, guardrailCategory, expand);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
|
@ -179,17 +171,28 @@ public abstract class GuardrailsConfigCommand extends NodeTool.NodeToolCmd
|
|||
{
|
||||
private static final Pattern SETTER_PATTERN = Pattern.compile("^set");
|
||||
|
||||
@Arguments(usage = "[<setter> <value1> ...]",
|
||||
@CassandraUsage(usage = "[<setter> <value1> ...]",
|
||||
description = "For flags, possible values are 'true' or 'false'. " +
|
||||
"For thresholds, two values are expected, first for failure, second for warning. " +
|
||||
"For values, enumeration of values expected or one value where multiple items are separated by comma. " +
|
||||
"Setting for thresholds accepting strings and value guardrails are reset by specifying 'null' or '[]' value. " +
|
||||
"For thresholds accepting integers, the reset value is -1.")
|
||||
private final List<String> args = new ArrayList<>();
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Parameters(index = "0", arity = "0..1")
|
||||
private String setterName;
|
||||
|
||||
@Parameters(index = "1..*", arity = "0..*", description = "Arguments for the setter. For flags, possible values are 'true' or 'false'. " +
|
||||
"For thresholds, two values are expected, first for failure, second for warning. " +
|
||||
"For values, enumeration of values expected or one value where multiple items are separated by comma. " +
|
||||
"Setting for thresholds accepting strings and value guardrails are reset by specifying 'null' or '[]' value. " +
|
||||
"For thresholds accepting integers, the reset value is -1.")
|
||||
private List<String> setterArgs = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
args = CommandUtils.concatArgs(setterName, setterArgs);
|
||||
if (args.isEmpty())
|
||||
throw new IllegalStateException("No arguments.");
|
||||
|
||||
|
|
@ -376,27 +379,6 @@ public abstract class GuardrailsConfigCommand extends NodeTool.NodeToolCmd
|
|||
thresholds,
|
||||
flags,
|
||||
others;
|
||||
|
||||
public static GuardrailCategory parseCategory(String category, PrintStream out)
|
||||
{
|
||||
if (category == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
return GuardrailCategory.valueOf(LocalizeString.toLowerCaseLocalized(category));
|
||||
}
|
||||
catch (IllegalArgumentException ex)
|
||||
{
|
||||
String enabledValues = Arrays.stream(GuardrailCategory.values())
|
||||
.map(GuardrailCategory::name)
|
||||
.collect(Collectors.joining(","));
|
||||
out.printf("%nError: Illegal value for -c/--category used: '"
|
||||
+ category + "'. Supported values are " + enabledValues + ".%n");
|
||||
System.exit(1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void display(NodeProbe probe, Map<String, List<Method>> methods, GuardrailCategory userCategory, boolean verbose)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraCliHelpLayout;
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.IHelpCommandInitializable2;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_COMMAND_LIST;
|
||||
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_COMMAND_LIST_HEADING;
|
||||
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_EXIT_CODE_LIST;
|
||||
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_EXIT_CODE_LIST_HEADING;
|
||||
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_FOOTER;
|
||||
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_FOOTER_HEADING;
|
||||
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_HEADER;
|
||||
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_HEADER_HEADING;
|
||||
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_SYNOPSIS;
|
||||
|
||||
@Command(name = "help",
|
||||
helpCommand = true,
|
||||
description = "Display help information")
|
||||
public class Help implements IHelpCommandInitializable2, Runnable
|
||||
{
|
||||
@Option(names = { "--help" }, hidden = true, usageHelp = true, descriptionKey = "helpCommand.help",
|
||||
description = "Show usage help for the help command and exit.")
|
||||
private boolean helpRequested;
|
||||
|
||||
@Parameters(paramLabel = "command", arity = "1..*", descriptionKey = "helpCommand.command",
|
||||
description = "The COMMAND to display the usage help message for.")
|
||||
private List<String> commands;
|
||||
|
||||
private CommandLine self;
|
||||
private PrintWriter out;
|
||||
private CommandLine.Help.ColorScheme colorScheme;
|
||||
|
||||
/**
|
||||
* Invokes {@code #usage(PrintStream, CommandLine.Help.ColorScheme) usage} for the specified command,
|
||||
* or for the parent command.
|
||||
*/
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
CommandLine parent = self == null ? null : self.getParent();
|
||||
if (parent == null)
|
||||
return;
|
||||
|
||||
CommandLine.Help.ColorScheme colors = colorScheme == null ?
|
||||
CommandLine.Help.defaultColorScheme(CommandLine.Help.Ansi.AUTO) :
|
||||
colorScheme;
|
||||
|
||||
if (commands == null)
|
||||
{
|
||||
// If the parent command is the top-level command, print help for the top-level command.
|
||||
printTopCommandUsage(parent, colors, out);
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent.isAbbreviatedSubcommandsAllowed())
|
||||
throw new CommandLine.ParameterException(parent, "Abbreviated subcommands are not allowed.");
|
||||
|
||||
// Print help for the last command in the list of commands.
|
||||
CommandLine subcommand = parent;
|
||||
for (String command : commands)
|
||||
{
|
||||
subcommand = subcommand.getSubcommands().get(command);
|
||||
if (subcommand == null)
|
||||
throw new CommandLine.ParameterException(parent, "Unknown subcommand '" + command + "'.", null, command);
|
||||
}
|
||||
|
||||
subcommand.usage(out, colors);
|
||||
}
|
||||
|
||||
public static void printTopCommandUsage(CommandLine command, CommandLine.Help.ColorScheme colors, PrintWriter writer)
|
||||
{
|
||||
if (command == null)
|
||||
return;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
CommandLine.Help help = command.getHelpFactory().create(command.getCommandSpec(), colors);
|
||||
if (!(help instanceof CassandraCliHelpLayout))
|
||||
{
|
||||
command.usage(writer, colors);
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, CommandLine.IHelpSectionRenderer> helpSectionMap = cassandraTopLevelHelpSectionKeys((CassandraCliHelpLayout) help);
|
||||
for (String key : command.getHelpSectionKeys())
|
||||
{
|
||||
CommandLine.IHelpSectionRenderer renderer = helpSectionMap.get(key);
|
||||
if (renderer == null)
|
||||
continue;
|
||||
String rendered = renderer.render(help);
|
||||
if (!Strings.isNullOrEmpty(rendered))
|
||||
sb.append(rendered);
|
||||
}
|
||||
|
||||
writer.println(sb);
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Top-level help command (includes all the available nodetool commands) has a different layout, so we need to
|
||||
* provide a different set of keys for the help sections.
|
||||
* @param layout The help class layout.
|
||||
* @return Map of supported keys for the help sections.
|
||||
*/
|
||||
public static Map<String, CommandLine.IHelpSectionRenderer> cassandraTopLevelHelpSectionKeys(CassandraCliHelpLayout layout)
|
||||
{
|
||||
Map<String, CommandLine.IHelpSectionRenderer> sectionMap = new LinkedHashMap<>();
|
||||
sectionMap.put(SECTION_KEY_HEADER_HEADING, CommandLine.Help::headerHeading);
|
||||
sectionMap.put(SECTION_KEY_HEADER, CommandLine.Help::header);
|
||||
sectionMap.put(SECTION_KEY_SYNOPSIS, layout::topLevelSynopsis);
|
||||
sectionMap.put(SECTION_KEY_COMMAND_LIST_HEADING, layout::topLevelCommandListHeading);
|
||||
sectionMap.put(SECTION_KEY_COMMAND_LIST, layout::topLevelCommandList);
|
||||
sectionMap.put(SECTION_KEY_EXIT_CODE_LIST_HEADING, CommandLine.Help::exitCodeListHeading);
|
||||
sectionMap.put(SECTION_KEY_EXIT_CODE_LIST, CommandLine.Help::exitCodeList);
|
||||
sectionMap.put(SECTION_KEY_FOOTER_HEADING, CommandLine.Help::footerHeading);
|
||||
sectionMap.put(SECTION_KEY_FOOTER, CommandLine.Help::footer);
|
||||
return sectionMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* The printHelpIfRequested method calls the init method on commands marked
|
||||
* as helpCommand before the help command's run or call method is called.
|
||||
*/
|
||||
public void init(CommandLine helpCommandLine,
|
||||
CommandLine.Help.ColorScheme colorScheme,
|
||||
PrintWriter out,
|
||||
PrintWriter err)
|
||||
{
|
||||
this.self = Preconditions.checkNotNull(helpCommandLine, "helpCommandLine");
|
||||
this.colorScheme = Preconditions.checkNotNull(colorScheme, "colorScheme");
|
||||
this.out = Preconditions.checkNotNull(out, "outWriter");
|
||||
}
|
||||
}
|
||||
|
|
@ -18,13 +18,6 @@
|
|||
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import io.airlift.airline.Option;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
|
@ -32,67 +25,87 @@ import java.util.List;
|
|||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.concatArgs;
|
||||
|
||||
@Command(name = "import", description = "Import new SSTables to the system")
|
||||
public class Import extends NodeToolCmd
|
||||
public class Import extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "<keyspace> <table> <directory> ...", description = "The keyspace, table name and directories to import sstables from")
|
||||
public static final String IMPORT_FAIL_MESSAGE = "Some directories failed to import, check server logs for details";
|
||||
|
||||
@CassandraUsage(usage = "<keyspace> <table> <directory> ...", description = "The keyspace, table name and directories to import sstables from")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Option(title = "keep_level",
|
||||
name = {"-l", "--keep-level"},
|
||||
@Parameters(index = "0", paramLabel = "keyspace", description = "The keyspace name")
|
||||
private String keyspace;
|
||||
|
||||
@Parameters(index = "1", paramLabel = "table", description = "The table name")
|
||||
private String table;
|
||||
|
||||
@Parameters(index = "2..*", paramLabel = "directories", description = "The directories to import sstables from")
|
||||
private String[] directories;
|
||||
|
||||
@Option(paramLabel = "keep_level",
|
||||
names = { "-l", "--keep-level" },
|
||||
description = "Keep the level on the new sstables")
|
||||
private boolean keepLevel = false;
|
||||
|
||||
@Option(title = "keep_repaired",
|
||||
name = {"-r", "--keep-repaired"},
|
||||
@Option(paramLabel = "keep_repaired",
|
||||
names = { "-r", "--keep-repaired" },
|
||||
description = "Keep any repaired information from the sstables")
|
||||
private boolean keepRepaired = false;
|
||||
|
||||
@Option(title = "no_verify_sstables",
|
||||
name = {"-v", "--no-verify"},
|
||||
@Option(paramLabel = "no_verify_sstables",
|
||||
names = { "-v", "--no-verify" },
|
||||
description = "Don't verify new sstables")
|
||||
private boolean noVerify = false;
|
||||
|
||||
@Option(title = "no_verify_tokens",
|
||||
name = {"-t", "--no-tokens"},
|
||||
@Option(paramLabel = "no_verify_tokens",
|
||||
names = { "-t", "--no-tokens" },
|
||||
description = "Don't verify that all tokens in the new sstable are owned by the current node")
|
||||
private boolean noVerifyTokens = false;
|
||||
|
||||
@Option(title = "no_invalidate_caches",
|
||||
name = {"-c", "--no-invalidate-caches"},
|
||||
@Option(paramLabel = "no_invalidate_caches",
|
||||
names = { "-c", "--no-invalidate-caches" },
|
||||
description = "Don't invalidate the row cache when importing")
|
||||
private boolean noInvalidateCaches = false;
|
||||
|
||||
@Option(title = "quick",
|
||||
name = {"-q", "--quick"},
|
||||
@Option(paramLabel = "quick",
|
||||
names = { "-q", "--quick" },
|
||||
description = "Do a quick import without verifying sstables, clearing row cache or checking in which data directory to put the file")
|
||||
private boolean quick = false;
|
||||
|
||||
@Option(title = "extended_verify",
|
||||
name = {"-e", "--extended-verify"},
|
||||
@Option(paramLabel = "extended_verify",
|
||||
names = { "-e", "--extended-verify" },
|
||||
description = "Run an extended verify, verifying all values in the new sstables")
|
||||
private boolean extendedVerify = false;
|
||||
|
||||
@Option(title = "copy_data",
|
||||
name = {"-p", "--copy-data"},
|
||||
// The previous option -p collides with the --port in the JMX, so we need to alter it to -cd.
|
||||
// It is safe to alter the name since the option is not used by users as it doesn't work.
|
||||
@Option(paramLabel = "copy_data",
|
||||
names = { "-cd", "--copy-data" },
|
||||
description = "Copy data from source directories instead of moving them")
|
||||
private boolean copyData = false;
|
||||
|
||||
@Option(title = "require_index_components",
|
||||
name = {"-ri", "--require-index-components"},
|
||||
@Option(paramLabel = "require_index_components",
|
||||
names = { "-ri", "--require-index-components" },
|
||||
description = "Require existing index components for SSTables with attached indexes")
|
||||
private boolean failOnMissingIndex = false;
|
||||
|
||||
@Option(title = "no_index_validation",
|
||||
name = {"-niv", "--no-index-validation"},
|
||||
@Option(paramLabel = "no_index_validation",
|
||||
names = { "-niv", "--no-index-validation" },
|
||||
description = "Skip SSTable-attached index checksum validation")
|
||||
private boolean noIndexValidation = false;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
args = concatArgs(keyspace, table, directories);
|
||||
checkArgument(args.size() >= 3, "import requires keyspace, table name and directories");
|
||||
|
||||
if (quick)
|
||||
|
|
@ -110,11 +123,9 @@ public class Import extends NodeToolCmd
|
|||
extendedVerify, copyData, failOnMissingIndex, !noIndexValidation);
|
||||
if (!failedDirs.isEmpty())
|
||||
{
|
||||
PrintStream err = probe.output().err;
|
||||
err.println("Some directories failed to import, check server logs for details:");
|
||||
for (String directory : failedDirs)
|
||||
err.println(directory);
|
||||
System.exit(1);
|
||||
output.printError(directory);
|
||||
throw new RuntimeException(IMPORT_FAIL_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,28 +17,25 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.lang.management.MemoryUsage;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.management.InstanceNotFoundException;
|
||||
|
||||
import org.apache.cassandra.db.ColumnFamilyStoreMBean;
|
||||
import org.apache.cassandra.io.util.FileUtils;
|
||||
import org.apache.cassandra.service.CacheServiceMBean;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "info", description = "Print node information (uptime, load, ...)")
|
||||
public class Info extends NodeToolCmd
|
||||
public class Info extends AbstractCommand
|
||||
{
|
||||
@Option(name = {"-T", "--tokens"}, description = "Display all tokens")
|
||||
@Option(names = { "-T", "--tokens" }, description = "Display all tokens")
|
||||
private boolean tokens = false;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -20,18 +20,19 @@ package org.apache.cassandra.tools.nodetool;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Parameters;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
/**
|
||||
* Nodetool command to invalidate CIDR permissions cache, for a give role or for all roles in the cache.
|
||||
*/
|
||||
@Command(name = "invalidatecidrpermissionscache", description = "Invalidate the cidr permissions cache")
|
||||
public class InvalidateCIDRPermissionsCache extends NodeToolCmd
|
||||
public class InvalidateCIDRPermissionsCache extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<role>...]", description = "List of roles to invalidate. By default, all roles")
|
||||
@CassandraUsage(usage = "[<role>...]", description = "List of roles to invalidate. By default, all roles")
|
||||
@Parameters(paramLabel = "roles", description = "List of roles to invalidate. By default, all roles", index = "0..*")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,13 +17,12 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "invalidatecountercache", description = "Invalidate the counter cache")
|
||||
public class InvalidateCounterCache extends NodeToolCmd
|
||||
public class InvalidateCounterCache extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -20,15 +20,16 @@ package org.apache.cassandra.tools.nodetool;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
@Command(name = "invalidatecredentialscache", description = "Invalidate the credentials cache")
|
||||
public class InvalidateCredentialsCache extends NodeToolCmd
|
||||
public class InvalidateCredentialsCache extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<role>...]", description = "List of roles to invalidate. By default, all roles")
|
||||
@CassandraUsage(usage = "[<role>...]", description = "List of roles to invalidate. By default, all roles")
|
||||
@Parameters(paramLabel = "roles", description = "List of roles to invalidate. By default, all roles", index = "0..*")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -20,15 +20,16 @@ package org.apache.cassandra.tools.nodetool;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
@Command(name = "invalidatejmxpermissionscache", description = "Invalidate the JMX permissions cache")
|
||||
public class InvalidateJmxPermissionsCache extends NodeToolCmd
|
||||
public class InvalidateJmxPermissionsCache extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<role>...]", description = "List of roles to invalidate. By default, all roles")
|
||||
@CassandraUsage(usage = "[<role>...]", description = "List of roles to invalidate. By default, all roles")
|
||||
@Parameters(paramLabel = "roles", description = "List of roles to invalidate. By default, all roles", index = "0..*")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "invalidatekeycache", description = "Invalidate the key cache")
|
||||
public class InvalidateKeyCache extends NodeToolCmd
|
||||
public class InvalidateKeyCache extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -20,15 +20,16 @@ package org.apache.cassandra.tools.nodetool;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
@Command(name = "invalidatenetworkpermissionscache", description = "Invalidate the network permissions cache")
|
||||
public class InvalidateNetworkPermissionsCache extends NodeToolCmd
|
||||
public class InvalidateNetworkPermissionsCache extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<role>...]", description = "List of roles to invalidate. By default, all roles")
|
||||
@CassandraUsage(usage = "[<role>...]", description = "List of roles to invalidate. By default, all roles")
|
||||
@Parameters(paramLabel = "roles", description = "List of roles to invalidate. By default, all roles", index = "0..*")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -22,89 +22,88 @@ import java.util.List;
|
|||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.auth.DataResource;
|
||||
import org.apache.cassandra.auth.FunctionResource;
|
||||
import org.apache.cassandra.auth.JMXResource;
|
||||
import org.apache.cassandra.auth.RoleResource;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Parameters;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
@Command(name = "invalidatepermissionscache", description = "Invalidate the permissions cache")
|
||||
public class InvalidatePermissionsCache extends NodeToolCmd
|
||||
public class InvalidatePermissionsCache extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<role>]", description = "A role for which permissions to specified resources need to be invalidated")
|
||||
private List<String> args = new ArrayList<>();
|
||||
@Parameters(paramLabel = "role", description = "A role for which permissions to specified resources need to be invalidated", arity = "0..1", index = "0")
|
||||
private String roleName;
|
||||
|
||||
// Data Resources
|
||||
@Option(title = "all-keyspaces",
|
||||
name = {"--all-keyspaces"},
|
||||
@Option(paramLabel = "all-keyspaces",
|
||||
names = { "--all-keyspaces" },
|
||||
description = "Invalidate permissions for 'ALL KEYSPACES'")
|
||||
private boolean allKeyspaces;
|
||||
|
||||
@Option(title = "keyspace",
|
||||
name = {"--keyspace"},
|
||||
@Option(paramLabel = "keyspace",
|
||||
names = { "--keyspace" },
|
||||
description = "Keyspace to invalidate permissions for")
|
||||
private String keyspace;
|
||||
|
||||
@Option(title = "all-tables",
|
||||
name = {"--all-tables"},
|
||||
@Option(paramLabel = "all-tables",
|
||||
names = { "--all-tables" },
|
||||
description = "Invalidate permissions for 'ALL TABLES'")
|
||||
private boolean allTables;
|
||||
|
||||
@Option(title = "table",
|
||||
name = {"--table"},
|
||||
@Option(paramLabel = "table",
|
||||
names = { "--table" },
|
||||
description = "Table to invalidate permissions for (you must specify --keyspace for using this option)")
|
||||
private String table;
|
||||
|
||||
// Roles Resources
|
||||
@Option(title = "all-roles",
|
||||
name = {"--all-roles"},
|
||||
@Option(paramLabel = "all-roles",
|
||||
names = { "--all-roles" },
|
||||
description = "Invalidate permissions for 'ALL ROLES'")
|
||||
private boolean allRoles;
|
||||
|
||||
@Option(title = "role",
|
||||
name = {"--role"},
|
||||
@Option(paramLabel = "role",
|
||||
names = { "--role" },
|
||||
description = "Role to invalidate permissions for")
|
||||
private String role;
|
||||
|
||||
// Functions Resources
|
||||
@Option(title = "all-functions",
|
||||
name = {"--all-functions"},
|
||||
@Option(paramLabel = "all-functions",
|
||||
names = { "--all-functions" },
|
||||
description = "Invalidate permissions for 'ALL FUNCTIONS'")
|
||||
private boolean allFunctions;
|
||||
|
||||
@Option(title = "functions-in-keyspace",
|
||||
name = {"--functions-in-keyspace"},
|
||||
@Option(paramLabel = "functions-in-keyspace",
|
||||
names = { "--functions-in-keyspace" },
|
||||
description = "Keyspace to invalidate permissions for")
|
||||
private String functionsInKeyspace;
|
||||
|
||||
@Option(title = "function",
|
||||
name = {"--function"},
|
||||
@Option(paramLabel = "function",
|
||||
names = { "--function" },
|
||||
description = "Function to invalidate permissions for (you must specify --functions-in-keyspace for using " +
|
||||
"this option; function format: name[arg1^..^agrN], for example: foo[Int32Type^DoubleType])")
|
||||
private String function;
|
||||
|
||||
// MBeans Resources
|
||||
@Option(title = "all-mbeans",
|
||||
name = {"--all-mbeans"},
|
||||
@Option(paramLabel = "all-mbeans",
|
||||
names = { "--all-mbeans" },
|
||||
description = "Invalidate permissions for 'ALL MBEANS'")
|
||||
private boolean allMBeans;
|
||||
|
||||
@Option(title = "mbean",
|
||||
name = {"--mbean"},
|
||||
@Option(paramLabel = "mbean",
|
||||
names = { "--mbean" },
|
||||
description = "MBean to invalidate permissions for")
|
||||
private String mBean;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
if (args.isEmpty())
|
||||
if (StringUtils.isEmpty(roleName))
|
||||
{
|
||||
checkArgument(!allKeyspaces && StringUtils.isEmpty(keyspace) && StringUtils.isEmpty(table)
|
||||
&& !allRoles && StringUtils.isEmpty(role)
|
||||
|
|
@ -116,8 +115,6 @@ public class InvalidatePermissionsCache extends NodeToolCmd
|
|||
}
|
||||
else
|
||||
{
|
||||
checkArgument(args.size() == 1,
|
||||
"A single <role> is only supported / you have a typo in the resource options spelling");
|
||||
List<String> resourceNames = new ArrayList<>();
|
||||
|
||||
// Data Resources
|
||||
|
|
@ -166,8 +163,6 @@ public class InvalidatePermissionsCache extends NodeToolCmd
|
|||
if (StringUtils.isNotEmpty(mBean))
|
||||
resourceNames.add(JMXResource.mbean(mBean).getName());
|
||||
|
||||
String roleName = args.get(0);
|
||||
|
||||
if (resourceNames.isEmpty())
|
||||
throw new IllegalArgumentException("No resource options specified");
|
||||
|
||||
|
|
|
|||
|
|
@ -20,16 +20,17 @@ package org.apache.cassandra.tools.nodetool;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
@Command(name = "invalidaterolescache", description = "Invalidate the roles cache")
|
||||
public class InvalidateRolesCache extends NodeToolCmd
|
||||
public class InvalidateRolesCache extends AbstractCommand
|
||||
{
|
||||
|
||||
@Arguments(usage = "[<role>...]", description = "List of roles to invalidate. By default, all roles")
|
||||
@CassandraUsage(usage = "[<role>...]", description = "List of roles to invalidate. By default, all roles")
|
||||
@Parameters(paramLabel = "role", description = "List of roles to invalidate. By default, all roles")
|
||||
private List<String> args = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@
|
|||
*/
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "invalidaterowcache", description = "Invalidate the row cache")
|
||||
public class InvalidateRowCache extends NodeToolCmd
|
||||
public class InvalidateRowCache extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.Console;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import org.apache.cassandra.io.util.File;
|
||||
import org.apache.cassandra.tools.INodeProbeFactory;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.ExecutionException;
|
||||
import picocli.CommandLine.IExecutionStrategy;
|
||||
import picocli.CommandLine.InitializationException;
|
||||
import picocli.CommandLine.Model.CommandSpec;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.ParameterException;
|
||||
import picocli.CommandLine.ParseResult;
|
||||
import picocli.CommandLine.RunLast;
|
||||
import picocli.CommandLine.Spec;
|
||||
|
||||
import static java.lang.Integer.parseInt;
|
||||
import static org.apache.cassandra.tools.NodeProbe.defaultPort;
|
||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||
import static org.apache.commons.lang3.StringUtils.isEmpty;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
|
||||
|
||||
/**
|
||||
* Command options for NodeTool commands that are executed via JMX.
|
||||
*/
|
||||
@Command(name = "connect", description = "Connect to a Cassandra node via JMX")
|
||||
public class JmxConnect extends AbstractCommand implements AutoCloseable
|
||||
{
|
||||
public static final String MIXIN_KEY = "jmx";
|
||||
|
||||
/** The command specification, used to access command-specific properties. */
|
||||
@Spec
|
||||
protected CommandSpec spec; // injected by picocli
|
||||
|
||||
@Option(names = { "-h", "--host" }, description = "Node hostname or ip address", arity = "0..1")
|
||||
private String host = "127.0.0.1";
|
||||
|
||||
@Option(names = { "-p", "--port" }, description = "Remote jmx agent port number", arity = "0..1")
|
||||
private String port = String.valueOf(defaultPort);
|
||||
|
||||
@Option(names = { "-u", "--username" }, description = "Remote jmx agent username", arity = "0..1")
|
||||
private String username = EMPTY;
|
||||
|
||||
@Option(names = { "-pw", "--password" }, description = "Remote jmx agent password", arity = "0..1")
|
||||
private String password = EMPTY;
|
||||
|
||||
@Option(names = { "-pwf", "--password-file" }, description = "Path to the JMX password file", arity = "0..1")
|
||||
private String passwordFilePath = EMPTY;
|
||||
|
||||
@Inject
|
||||
private INodeProbeFactory nodeProbeFactory;
|
||||
|
||||
/**
|
||||
* This method is called by picocli and used depending on the execution strategy.
|
||||
* @param parseResult The parsed command line.
|
||||
* @return The exit code.
|
||||
*/
|
||||
public static int executionStrategy(ParseResult parseResult)
|
||||
{
|
||||
CommandSpec jmx = parseResult.commandSpec().mixins().get(MIXIN_KEY);
|
||||
if (jmx == null)
|
||||
throw new InitializationException("No JmxConnect command found in the top-level hierarchy");
|
||||
|
||||
try (JmxConnectionCommandInvoker invoker = new JmxConnectionCommandInvoker((JmxConnect) jmx.userObject()))
|
||||
{
|
||||
return invoker.execute(parseResult);
|
||||
}
|
||||
catch (JmxConnectionCommandInvoker.CloseException e)
|
||||
{
|
||||
jmx.commandLine()
|
||||
.getErr()
|
||||
.println("Failed to connect to JMX: " + e.getMessage());
|
||||
return jmx.commandLine().getExitCodeExceptionMapper().getExitCode(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the JMX connection to the Cassandra node using the provided options.
|
||||
*/
|
||||
@Override
|
||||
protected void execute(NodeProbe probe)
|
||||
{
|
||||
assert probe == null;
|
||||
try
|
||||
{
|
||||
if (isNotEmpty(username))
|
||||
{
|
||||
if (isNotEmpty(passwordFilePath))
|
||||
password = readUserPasswordFromFile(username, passwordFilePath);
|
||||
|
||||
if (isEmpty(password))
|
||||
password = promptAndReadPassword();
|
||||
}
|
||||
|
||||
probe(username.isEmpty() ? nodeProbeFactory.create(host, parseInt(port))
|
||||
: nodeProbeFactory.create(host, parseInt(port), username, password));
|
||||
}
|
||||
catch (IOException | SecurityException e)
|
||||
{
|
||||
Throwable rootCause = Throwables.getRootCause(e);
|
||||
output.printError("nodetool: Failed to connect to '%s:%s' - %s: '%s'.%n", host, port,
|
||||
rootCause.getClass().getSimpleName(), rootCause.getMessage());
|
||||
throw new InitializationException("Failed to connect to JMX", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception
|
||||
{
|
||||
if (probe() == null)
|
||||
return;
|
||||
((AutoCloseable) probe()).close();
|
||||
}
|
||||
|
||||
private static String readUserPasswordFromFile(String username, String passwordFilePath)
|
||||
{
|
||||
String password = EMPTY;
|
||||
|
||||
File passwordFile = new File(passwordFilePath);
|
||||
try (Scanner scanner = new Scanner(passwordFile.toJavaIOFile()).useDelimiter("\\s+"))
|
||||
{
|
||||
while (scanner.hasNextLine())
|
||||
{
|
||||
if (scanner.hasNext())
|
||||
{
|
||||
String jmxRole = scanner.next();
|
||||
if (jmxRole.equals(username) && scanner.hasNext())
|
||||
{
|
||||
password = scanner.next();
|
||||
break;
|
||||
}
|
||||
}
|
||||
scanner.nextLine();
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
private static String promptAndReadPassword()
|
||||
{
|
||||
String password = EMPTY;
|
||||
|
||||
Console console = System.console();
|
||||
if (console != null)
|
||||
password = String.valueOf(console.readPassword("Password:"));
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
private static class JmxConnectionCommandInvoker implements IExecutionStrategy, AutoCloseable
|
||||
{
|
||||
private final JmxConnect connect;
|
||||
|
||||
public JmxConnectionCommandInvoker(JmxConnect connect)
|
||||
{
|
||||
this.connect = connect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int execute(ParseResult parseResult) throws ExecutionException, ParameterException
|
||||
{
|
||||
CommandSpec lastParent = lastExecutableSubcommandWithSameParent(parseResult.asCommandLineList());
|
||||
if (lastParent.userObject() instanceof AbstractCommand)
|
||||
{
|
||||
AbstractCommand command = (AbstractCommand) lastParent.userObject();
|
||||
if (command.shouldConnect())
|
||||
connect.run();
|
||||
command.probe(connect.probe());
|
||||
}
|
||||
return new RunLast().execute(parseResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws CloseException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (connect.probe() != null)
|
||||
((AutoCloseable) connect.probe()).close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new CloseException("Failed to close JMX connection", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static CommandLine.Model.CommandSpec lastExecutableSubcommandWithSameParent(List<CommandLine> parsedCommands)
|
||||
{
|
||||
int start = parsedCommands.size() - 1;
|
||||
for (int i = parsedCommands.size() - 2; i >= 0; i--)
|
||||
{
|
||||
if (parsedCommands.get(i).getParent() != parsedCommands.get(i + 1).getParent())
|
||||
break;
|
||||
start = i;
|
||||
}
|
||||
return parsedCommands.get(start).getCommandSpec();
|
||||
}
|
||||
|
||||
private static class CloseException extends RuntimeException
|
||||
{
|
||||
public CloseException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,15 +18,15 @@
|
|||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
|
||||
@Command(name = "join", description = "Join the ring")
|
||||
public class Join extends NodeToolCmd
|
||||
public class Join extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
|
|
|
|||
|
|
@ -15,38 +15,35 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.cassandra.tools;
|
||||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.cassandra.auth.AuthKeyspace;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import static org.apache.cassandra.tools.nodetool.CommandUtils.printSet;
|
||||
|
||||
/**
|
||||
* Nodetool command to list available CIDR groups, in the table {@link AuthKeyspace#CIDR_GROUPS}
|
||||
*/
|
||||
@Command(name = "listcidrgroups", description = "List existing cidr groups")
|
||||
public class ListCIDRGroups extends NodeToolCmd
|
||||
public class ListCIDRGroups extends AbstractCommand
|
||||
{
|
||||
@Arguments(usage = "[<cidrGroup>]", description = "LIST operation can be invoked with or without cidr group name")
|
||||
private List<String> args = new ArrayList<>();
|
||||
@Parameters(paramLabel = "cidrGroup", description = "LIST operation can be invoked with or without cidr group name", arity = "0..1")
|
||||
private String cidrGroup;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
PrintStream out = probe.output().out;
|
||||
|
||||
if (args.size() < 1)
|
||||
if (StringUtils.isEmpty(cidrGroup))
|
||||
{
|
||||
probe.printSet(out, "CIDR Groups", probe.listAvailableCidrGroups());
|
||||
printSet(probe.output().out, "CIDR Groups", probe.listAvailableCidrGroups());
|
||||
return;
|
||||
}
|
||||
|
||||
String cidrGroup = args.get(0);
|
||||
probe.printSet(out, "CIDRs", probe.listCidrsOfCidrGroup(cidrGroup));
|
||||
printSet(probe.output().out, "CIDRs", probe.listCidrsOfCidrGroup(cidrGroup));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue