mirror of https://github.com/apache/cassandra
Make cassandra-stress able to read all credentials from a file
As side-effect, this patch also introduces possibility to pass credentials to JMX. patch by Stefan Miklosovic; reviewed by Brandon Williams for CASSANDRA-18544
This commit is contained in:
parent
ffe4d85df2
commit
4d2ee09ffa
|
|
@ -1,4 +1,5 @@
|
|||
5.0
|
||||
* Make cassandra-stress able to read all credentials from a file (CASSANDRA-18544)
|
||||
* Add guardrail for partition size and deprecate compaction_large_partition_warning_threshold (CASSANDRA-18500)
|
||||
* Add HISTORY command for CQLSH (CASSANDRA-15046)
|
||||
* Fix sstable formats configuration (CASSANDRA-18441)
|
||||
|
|
|
|||
2
NEWS.txt
2
NEWS.txt
|
|
@ -142,6 +142,8 @@ New features
|
|||
Superusers have it by default, whereas regular users don't have it by default.
|
||||
- Added support for using UDFs as masking functions attached to table columns on the schema.
|
||||
- Added `sstablepartitions` offline tool to find large partitions in sstables.
|
||||
- `cassandra-stress` has a new option called '-jmx' which enables a user to pass username and password to JMX (CASSANDRA-18544)
|
||||
- It is possible to read all credentials for `cassandra-stress` from a file via option `-credentials-file` (CASSANDRA-18544)
|
||||
|
||||
Upgrading
|
||||
---------
|
||||
|
|
|
|||
|
|
@ -71,6 +71,10 @@ Primary Options:::
|
|||
Graph recorded metrics
|
||||
-tokenrange:;;
|
||||
Token range settings
|
||||
-jmx:;;
|
||||
Username and password for JMX connection
|
||||
-credentials-file <path>:;;
|
||||
Credentials file to specify for CQL, JMX and transport
|
||||
Suboptions:::
|
||||
Every command and primary option has its own collection of suboptions.
|
||||
These are too numerous to list here. For information on the suboptions
|
||||
|
|
|
|||
|
|
@ -114,7 +114,8 @@ public class StressMetrics implements MeasurementSink
|
|||
try
|
||||
{
|
||||
gcStatsCollector = new JmxCollector(toJmxNodes(settings.node.resolveAllPermitted(settings)),
|
||||
settings.port.jmxPort);
|
||||
settings.port.jmxPort,
|
||||
settings.jmx);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,8 +37,10 @@ public enum CliOption
|
|||
LOG("Where to log progress to, and the interval at which to do it", SettingsLog.helpPrinter()),
|
||||
TRANSPORT("Custom transport factories", SettingsTransport.helpPrinter()),
|
||||
PORT("The port to connect to cassandra nodes on", SettingsPort.helpPrinter()),
|
||||
JMX("JMX credentials", SettingsJMX.helpPrinter()),
|
||||
GRAPH("-graph", "Graph recorded metrics", SettingsGraph.helpPrinter()),
|
||||
TOKENRANGE("Token range settings", SettingsTokenRange.helpPrinter())
|
||||
TOKENRANGE("Token range settings", SettingsTokenRange.helpPrinter()),
|
||||
CREDENTIALS_FILE("Credentials file for CQL, JMX and transport", SettingsCredentials.helpPrinter());
|
||||
;
|
||||
|
||||
private static final Map<String, CliOption> LOOKUP;
|
||||
|
|
@ -63,11 +65,12 @@ public enum CliOption
|
|||
public final String description;
|
||||
private final Runnable helpPrinter;
|
||||
|
||||
private CliOption(String description, Runnable helpPrinter)
|
||||
CliOption(String description, Runnable helpPrinter)
|
||||
{
|
||||
this(null, description, helpPrinter);
|
||||
}
|
||||
private CliOption(String extraName, String description, Runnable helpPrinter)
|
||||
|
||||
CliOption(String extraName, String description, Runnable helpPrinter)
|
||||
{
|
||||
this.extraName = extraName;
|
||||
this.description = description;
|
||||
|
|
@ -79,4 +82,8 @@ public enum CliOption
|
|||
helpPrinter.run();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return name().replaceAll("_", "-");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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.stress.settings;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.cassandra.io.util.File;
|
||||
import org.apache.cassandra.stress.util.ResultLogger;
|
||||
|
||||
public class SettingsCredentials implements Serializable
|
||||
{
|
||||
public static final String CQL_USERNAME_PROPERTY_KEY = "cql.username";
|
||||
public static final String CQL_PASSWORD_PROPERTY_KEY = "cql.password";
|
||||
public static final String JMX_USERNAME_PROPERTY_KEY = "jmx.username";
|
||||
public static final String JMX_PASSWORD_PROPERTY_KEY = "jmx.password";
|
||||
public static final String TRANSPORT_TRUSTSTORE_PASSWORD_PROPERTY_KEY = "transport.truststore.password";
|
||||
public static final String TRANSPORT_KEYSTORE_PASSWORD_PROPERTY_KEY = "transport.keystore.password";
|
||||
|
||||
private final String file;
|
||||
|
||||
public final String cqlUsername;
|
||||
public final String cqlPassword;
|
||||
public final String jmxUsername;
|
||||
public final String jmxPassword;
|
||||
public final String transportTruststorePassword;
|
||||
public final String transportKeystorePassword;
|
||||
|
||||
public SettingsCredentials(String file)
|
||||
{
|
||||
this.file = file;
|
||||
if (file == null)
|
||||
{
|
||||
cqlUsername = null;
|
||||
cqlPassword = null;
|
||||
jmxUsername = null;
|
||||
jmxPassword = null;
|
||||
transportTruststorePassword = null;
|
||||
transportKeystorePassword = null;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Properties properties = new Properties();
|
||||
try (InputStream is = new FileInputStream(new File(file).toJavaIOFile()))
|
||||
{
|
||||
properties.load(is);
|
||||
|
||||
cqlUsername = properties.getProperty(CQL_USERNAME_PROPERTY_KEY);
|
||||
cqlPassword = properties.getProperty(CQL_PASSWORD_PROPERTY_KEY);
|
||||
jmxUsername = properties.getProperty(JMX_USERNAME_PROPERTY_KEY);
|
||||
jmxPassword = properties.getProperty(JMX_PASSWORD_PROPERTY_KEY);
|
||||
transportTruststorePassword = properties.getProperty(TRANSPORT_TRUSTSTORE_PASSWORD_PROPERTY_KEY);
|
||||
transportKeystorePassword = properties.getProperty(TRANSPORT_KEYSTORE_PASSWORD_PROPERTY_KEY);
|
||||
}
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
// CLI Utility Methods
|
||||
public void printSettings(ResultLogger out)
|
||||
{
|
||||
out.printf(" File: %s%n", file == null ? "*not set*" : file);
|
||||
out.printf(" CQL username: %s%n", cqlUsername == null ? "*not set*" : cqlUsername);
|
||||
out.printf(" CQL password: %s%n", cqlPassword == null ? "*not set*" : "*suppressed*");
|
||||
out.printf(" JMX username: %s%n", jmxUsername == null ? "*not set*" : jmxUsername);
|
||||
out.printf(" JMX password: %s%n", jmxPassword == null ? "*not set*" : "*suppressed*");
|
||||
out.printf(" Transport truststore password: %s%n", transportTruststorePassword == null ? "*not set*" : "*suppressed*");
|
||||
out.printf(" Transport keystore password: %s%n", transportKeystorePassword == null ? "*not set*" : "*suppressed*");
|
||||
}
|
||||
|
||||
public static SettingsCredentials get(Map<String, String[]> clArgs)
|
||||
{
|
||||
String[] params = clArgs.remove("-credentials-file");
|
||||
if (params == null)
|
||||
return new SettingsCredentials(null);
|
||||
|
||||
if (params.length != 1)
|
||||
{
|
||||
printHelp();
|
||||
System.out.println("Invalid -credentials-file option provided, see output for valid options");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
return new SettingsCredentials(params[0]);
|
||||
}
|
||||
|
||||
public static void printHelp()
|
||||
{
|
||||
System.out.println("Usage: -credentials-file <file> ");
|
||||
System.out.printf("File is supposed to be a standard property file with '%s', '%s', '%s', '%s', '%s', and '%s' as keys. " +
|
||||
"The values for these keys will be overriden by their command-line counterparts when specified.%n",
|
||||
CQL_USERNAME_PROPERTY_KEY,
|
||||
CQL_PASSWORD_PROPERTY_KEY,
|
||||
JMX_USERNAME_PROPERTY_KEY,
|
||||
JMX_PASSWORD_PROPERTY_KEY,
|
||||
TRANSPORT_KEYSTORE_PASSWORD_PROPERTY_KEY,
|
||||
TRANSPORT_TRUSTSTORE_PASSWORD_PROPERTY_KEY);
|
||||
}
|
||||
|
||||
public static Runnable helpPrinter()
|
||||
{
|
||||
return SettingsCredentials::printHelp;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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.stress.settings;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cassandra.stress.util.ResultLogger;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.apache.cassandra.stress.settings.SettingsCredentials.JMX_PASSWORD_PROPERTY_KEY;
|
||||
import static org.apache.cassandra.stress.settings.SettingsCredentials.JMX_USERNAME_PROPERTY_KEY;
|
||||
|
||||
public class SettingsJMX implements Serializable
|
||||
{
|
||||
public final String user;
|
||||
public final String password;
|
||||
|
||||
public SettingsJMX(Options options, SettingsCredentials credentials)
|
||||
{
|
||||
this.user = options.user.setByUser() ? options.user.value() : credentials.jmxUsername;
|
||||
this.password = options.password.setByUser() ? options.password.value() : credentials.jmxPassword;
|
||||
}
|
||||
|
||||
// Option Declarations
|
||||
|
||||
public static final class Options extends GroupedOptions
|
||||
{
|
||||
final OptionSimple user = new OptionSimple("user=",
|
||||
".*",
|
||||
null,
|
||||
format("Username for JMX connection, when specified, it will override the value in credentials file for key '%s'", JMX_USERNAME_PROPERTY_KEY),
|
||||
false);
|
||||
|
||||
final OptionSimple password = new OptionSimple("password=",
|
||||
".*",
|
||||
null,
|
||||
format("Password for JMX connection, when specified, it will override the value in credentials file for key '%s'", JMX_PASSWORD_PROPERTY_KEY),
|
||||
false);
|
||||
|
||||
@Override
|
||||
public List<? extends Option> options()
|
||||
{
|
||||
return Arrays.asList(user, password);
|
||||
}
|
||||
}
|
||||
|
||||
// CLI Utility Methods
|
||||
public void printSettings(ResultLogger out)
|
||||
{
|
||||
out.printf(" Username: %s%n", user);
|
||||
out.printf(" Password: %s%n", (password == null ? "*not set*" : "*suppressed*"));
|
||||
}
|
||||
|
||||
public static SettingsJMX get(Map<String, String[]> clArgs, SettingsCredentials credentials)
|
||||
{
|
||||
String[] params = clArgs.remove("-jmx");
|
||||
if (params == null)
|
||||
return new SettingsJMX(new SettingsJMX.Options(), credentials);
|
||||
|
||||
GroupedOptions options = GroupedOptions.select(params, new SettingsJMX.Options());
|
||||
if (options == null)
|
||||
{
|
||||
printHelp();
|
||||
System.out.println("Invalid -jmx options provided, see output for valid options");
|
||||
System.exit(1);
|
||||
}
|
||||
return new SettingsJMX((SettingsJMX.Options) options, credentials);
|
||||
}
|
||||
|
||||
public static void printHelp()
|
||||
{
|
||||
GroupedOptions.printOptions(System.out, "-jmx", new SettingsJMX.Options());
|
||||
}
|
||||
|
||||
public static Runnable helpPrinter()
|
||||
{
|
||||
return SettingsJMX::printHelp;
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +32,10 @@ import com.datastax.driver.core.ProtocolOptions;
|
|||
import com.datastax.driver.core.ProtocolVersion;
|
||||
import org.apache.cassandra.stress.util.ResultLogger;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.apache.cassandra.stress.settings.SettingsCredentials.CQL_PASSWORD_PROPERTY_KEY;
|
||||
import static org.apache.cassandra.stress.settings.SettingsCredentials.CQL_USERNAME_PROPERTY_KEY;
|
||||
|
||||
public class SettingsMode implements Serializable
|
||||
{
|
||||
|
||||
|
|
@ -51,7 +55,7 @@ public class SettingsMode implements Serializable
|
|||
private final String compression;
|
||||
|
||||
|
||||
public SettingsMode(GroupedOptions options)
|
||||
public SettingsMode(GroupedOptions options, SettingsCredentials credentials)
|
||||
{
|
||||
if (options instanceof Cql3Options)
|
||||
{
|
||||
|
|
@ -63,8 +67,8 @@ public class SettingsMode implements Serializable
|
|||
api = ConnectionAPI.JAVA_DRIVER_NATIVE;
|
||||
style = opts.useUnPrepared.setByUser() ? ConnectionStyle.CQL : ConnectionStyle.CQL_PREPARED;
|
||||
compression = ProtocolOptions.Compression.valueOf(opts.useCompression.value().toUpperCase()).name();
|
||||
username = opts.user.value();
|
||||
password = opts.password.value();
|
||||
username = opts.user.setByUser() ? opts.user.value() : credentials.cqlUsername;
|
||||
password = opts.password.setByUser() ? opts.password.value() : credentials.cqlPassword;
|
||||
maxPendingPerConnection = opts.maxPendingPerConnection.value().isEmpty() ? null : Integer.valueOf(opts.maxPendingPerConnection.value());
|
||||
connectionsPerHost = opts.connectionsPerHost.value().isEmpty() ? null : Integer.valueOf(opts.connectionsPerHost.value());
|
||||
authProviderClassname = opts.authProvider.value();
|
||||
|
|
@ -137,8 +141,12 @@ public class SettingsMode implements Serializable
|
|||
final OptionSimple useUnPrepared = new OptionSimple("unprepared", "", null, "force use of unprepared statements", false);
|
||||
final OptionSimple useCompression = new OptionSimple("compression=", "none|lz4|snappy", "none", "", false);
|
||||
final OptionSimple port = new OptionSimple("port=", "[0-9]+", "9046", "", false);
|
||||
final OptionSimple user = new OptionSimple("user=", ".+", null, "username", false);
|
||||
final OptionSimple password = new OptionSimple("password=", ".+", null, "password", false);
|
||||
final OptionSimple user = new OptionSimple("user=", ".+", null,
|
||||
format("CQL user, when specified, it will override the value in credentials file for key '%s'", CQL_USERNAME_PROPERTY_KEY),
|
||||
false);
|
||||
final OptionSimple password = new OptionSimple("password=", ".+", null,
|
||||
format("CQL password, when specified, it will override the value in credentials file for key '%s'", CQL_PASSWORD_PROPERTY_KEY),
|
||||
false);
|
||||
final OptionSimple authProvider = new OptionSimple("auth-provider=", ".*", null, "Fully qualified implementation of com.datastax.driver.core.AuthProvider", false);
|
||||
final OptionSimple maxPendingPerConnection = new OptionSimple("maxPending=", "[0-9]+", "128", "Maximum pending requests per connection", false);
|
||||
final OptionSimple connectionsPerHost = new OptionSimple("connectionsPerHost=", "[0-9]+", "8", "Number of connections per host", false);
|
||||
|
|
@ -179,11 +187,9 @@ public class SettingsMode implements Serializable
|
|||
out.printf(" Max Pending Per Connection: %d%n", maxPendingPerConnection);
|
||||
out.printf(" Connections Per Host: %d%n", connectionsPerHost);
|
||||
out.printf(" Compression: %s%n", compression);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static SettingsMode get(Map<String, String[]> clArgs)
|
||||
public static SettingsMode get(Map<String, String[]> clArgs, SettingsCredentials credentials)
|
||||
{
|
||||
String[] params = clArgs.remove("-mode");
|
||||
if (params == null)
|
||||
|
|
@ -192,7 +198,7 @@ public class SettingsMode implements Serializable
|
|||
opts.accept("cql3");
|
||||
opts.accept("native");
|
||||
opts.accept("prepared");
|
||||
return new SettingsMode(opts);
|
||||
return new SettingsMode(opts, credentials);
|
||||
}
|
||||
|
||||
GroupedOptions options = GroupedOptions.select(params, new Cql3NativeOptions(), new Cql3SimpleNativeOptions());
|
||||
|
|
@ -202,7 +208,7 @@ public class SettingsMode implements Serializable
|
|||
System.out.println("Invalid -mode options provided, see output for valid options");
|
||||
System.exit(1);
|
||||
}
|
||||
return new SettingsMode(options);
|
||||
return new SettingsMode(options, credentials);
|
||||
}
|
||||
|
||||
public static void printHelp()
|
||||
|
|
|
|||
|
|
@ -29,13 +29,19 @@ import java.util.Map;
|
|||
import org.apache.cassandra.config.EncryptionOptions;
|
||||
import org.apache.cassandra.stress.util.ResultLogger;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.apache.cassandra.stress.settings.SettingsCredentials.TRANSPORT_KEYSTORE_PASSWORD_PROPERTY_KEY;
|
||||
import static org.apache.cassandra.stress.settings.SettingsCredentials.TRANSPORT_TRUSTSTORE_PASSWORD_PROPERTY_KEY;
|
||||
|
||||
public class SettingsTransport implements Serializable
|
||||
{
|
||||
private final TOptions options;
|
||||
private final SettingsCredentials credentials;
|
||||
|
||||
public SettingsTransport(TOptions options)
|
||||
public SettingsTransport(TOptions options, SettingsCredentials credentials)
|
||||
{
|
||||
this.options = options;
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
public EncryptionOptions getEncryptionOptions()
|
||||
|
|
@ -46,7 +52,7 @@ public class SettingsTransport implements Serializable
|
|||
encOptions = encOptions
|
||||
.withEnabled(true)
|
||||
.withTrustStore(options.trustStore.value())
|
||||
.withTrustStorePassword(options.trustStorePw.value())
|
||||
.withTrustStorePassword(options.trustStorePw.setByUser() ? options.trustStorePw.value() : credentials.transportTruststorePassword)
|
||||
.withAlgorithm(options.alg.value())
|
||||
.withProtocol(options.protocol.value())
|
||||
.withCipherSuites(options.ciphers.value().split(","));
|
||||
|
|
@ -54,14 +60,14 @@ public class SettingsTransport implements Serializable
|
|||
{
|
||||
encOptions = encOptions
|
||||
.withKeyStore(options.keyStore.value())
|
||||
.withKeyStorePassword(options.keyStorePw.value());
|
||||
.withKeyStorePassword(options.keyStorePw.setByUser() ? options.keyStorePw.value() : credentials.transportKeystorePassword);
|
||||
}
|
||||
else
|
||||
{
|
||||
// mandatory for SSLFactory.createSSLContext(), see CASSANDRA-9325
|
||||
encOptions = encOptions
|
||||
.withKeyStore(encOptions.truststore)
|
||||
.withKeyStorePassword(encOptions.truststore_password);
|
||||
.withKeyStorePassword(encOptions.truststore_password != null ? encOptions.truststore_password : credentials.transportTruststorePassword);
|
||||
}
|
||||
}
|
||||
return encOptions;
|
||||
|
|
@ -72,12 +78,18 @@ public class SettingsTransport implements Serializable
|
|||
static class TOptions extends GroupedOptions implements Serializable
|
||||
{
|
||||
final OptionSimple trustStore = new OptionSimple("truststore=", ".*", null, "SSL: full path to truststore", false);
|
||||
final OptionSimple trustStorePw = new OptionSimple("truststore-password=", ".*", null, "SSL: truststore password", false);
|
||||
final OptionSimple trustStorePw = new OptionSimple("truststore-password=", ".*", null,
|
||||
format("SSL: truststore password, when specified, it will override the value in credentials file of key '%s'",
|
||||
TRANSPORT_TRUSTSTORE_PASSWORD_PROPERTY_KEY), false);
|
||||
final OptionSimple keyStore = new OptionSimple("keystore=", ".*", null, "SSL: full path to keystore", false);
|
||||
final OptionSimple keyStorePw = new OptionSimple("keystore-password=", ".*", null, "SSL: keystore password", false);
|
||||
final OptionSimple keyStorePw = new OptionSimple("keystore-password=", ".*", null,
|
||||
format("SSL: keystore password, when specified, it will override the value in credentials file for key '%s'",
|
||||
TRANSPORT_KEYSTORE_PASSWORD_PROPERTY_KEY), false);
|
||||
final OptionSimple protocol = new OptionSimple("ssl-protocol=", ".*", "TLS", "SSL: connection protocol to use", false);
|
||||
final OptionSimple alg = new OptionSimple("ssl-alg=", ".*", null, "SSL: algorithm", false);
|
||||
final OptionSimple ciphers = new OptionSimple("ssl-ciphers=", ".*", "TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA", "SSL: comma delimited list of encryption suites to use", false);
|
||||
final OptionSimple ciphers = new OptionSimple("ssl-ciphers=", ".*",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"SSL: comma delimited list of encryption suites to use", false);
|
||||
|
||||
@Override
|
||||
public List<? extends Option> options()
|
||||
|
|
@ -89,14 +101,26 @@ public class SettingsTransport implements Serializable
|
|||
// CLI Utility Methods
|
||||
public void printSettings(ResultLogger out)
|
||||
{
|
||||
out.println(" " + options.getOptionAsString());
|
||||
String tPassword = options.trustStorePw.setByUser() ? options.trustStorePw.value() : credentials.transportTruststorePassword;
|
||||
tPassword = tPassword != null ? "*suppressed*" : tPassword;
|
||||
|
||||
String kPassword = options.keyStorePw.setByUser() ? options.keyStore.value() : credentials.transportKeystorePassword;
|
||||
kPassword = kPassword != null ? "*suppressed*" : kPassword;
|
||||
|
||||
out.printf(" Truststore: %s%n", options.trustStore.value());
|
||||
out.printf(" Truststore Password: %s%n", tPassword);
|
||||
out.printf(" Keystore: %s%n", options.keyStore.value());
|
||||
out.printf(" Keystore Password: %s%n", kPassword);
|
||||
out.printf(" SSL Protocol: %s%n", options.protocol.value());
|
||||
out.printf(" SSL Algorithm: %s%n", options.alg.value());
|
||||
out.printf(" SSL Ciphers: %s%n", options.ciphers.value());
|
||||
}
|
||||
|
||||
public static SettingsTransport get(Map<String, String[]> clArgs)
|
||||
public static SettingsTransport get(Map<String, String[]> clArgs, SettingsCredentials credentials)
|
||||
{
|
||||
String[] params = clArgs.remove("-transport");
|
||||
if (params == null)
|
||||
return new SettingsTransport(new TOptions());
|
||||
return new SettingsTransport(new TOptions(), credentials);
|
||||
|
||||
GroupedOptions options = GroupedOptions.select(params, new TOptions());
|
||||
if (options == null)
|
||||
|
|
@ -105,7 +129,7 @@ public class SettingsTransport implements Serializable
|
|||
System.out.println("Invalid -transport options provided, see output for valid options");
|
||||
System.exit(1);
|
||||
}
|
||||
return new SettingsTransport((TOptions) options);
|
||||
return new SettingsTransport((TOptions) options, credentials);
|
||||
}
|
||||
|
||||
public static void printHelp()
|
||||
|
|
|
|||
|
|
@ -38,11 +38,13 @@ public class StressSettings implements Serializable
|
|||
public final SettingsColumn columns;
|
||||
public final SettingsErrors errors;
|
||||
public final SettingsLog log;
|
||||
public final SettingsCredentials credentials;
|
||||
public final SettingsMode mode;
|
||||
public final SettingsNode node;
|
||||
public final SettingsSchema schema;
|
||||
public final SettingsTransport transport;
|
||||
public final SettingsPort port;
|
||||
public final SettingsJMX jmx;
|
||||
public final SettingsGraph graph;
|
||||
public final SettingsTokenRange tokenRange;
|
||||
|
||||
|
|
@ -53,11 +55,13 @@ public class StressSettings implements Serializable
|
|||
SettingsColumn columns,
|
||||
SettingsErrors errors,
|
||||
SettingsLog log,
|
||||
SettingsCredentials credentials,
|
||||
SettingsMode mode,
|
||||
SettingsNode node,
|
||||
SettingsSchema schema,
|
||||
SettingsTransport transport,
|
||||
SettingsPort port,
|
||||
SettingsJMX jmx,
|
||||
SettingsGraph graph,
|
||||
SettingsTokenRange tokenRange)
|
||||
{
|
||||
|
|
@ -68,11 +72,13 @@ public class StressSettings implements Serializable
|
|||
this.columns = columns;
|
||||
this.errors = errors;
|
||||
this.log = log;
|
||||
this.credentials = credentials;
|
||||
this.mode = mode;
|
||||
this.node = node;
|
||||
this.schema = schema;
|
||||
this.transport = transport;
|
||||
this.port = port;
|
||||
this.jmx = jmx;
|
||||
this.graph = graph;
|
||||
this.tokenRange = tokenRange;
|
||||
}
|
||||
|
|
@ -194,10 +200,12 @@ public class StressSettings implements Serializable
|
|||
SettingsColumn columns = SettingsColumn.get(clArgs);
|
||||
SettingsErrors errors = SettingsErrors.get(clArgs);
|
||||
SettingsLog log = SettingsLog.get(clArgs);
|
||||
SettingsMode mode = SettingsMode.get(clArgs);
|
||||
SettingsCredentials credentials = SettingsCredentials.get(clArgs);
|
||||
SettingsMode mode = SettingsMode.get(clArgs, credentials);
|
||||
SettingsNode node = SettingsNode.get(clArgs);
|
||||
SettingsSchema schema = SettingsSchema.get(clArgs, command);
|
||||
SettingsTransport transport = SettingsTransport.get(clArgs);
|
||||
SettingsTransport transport = SettingsTransport.get(clArgs, credentials);
|
||||
SettingsJMX jmx = SettingsJMX.get(clArgs, credentials);
|
||||
SettingsGraph graph = SettingsGraph.get(clArgs, command);
|
||||
if (!clArgs.isEmpty())
|
||||
{
|
||||
|
|
@ -216,7 +224,7 @@ public class StressSettings implements Serializable
|
|||
System.exit(1);
|
||||
}
|
||||
|
||||
return new StressSettings(command, rate, generate, insert, columns, errors, log, mode, node, schema, transport, port, graph, tokenRange);
|
||||
return new StressSettings(command, rate, generate, insert, columns, errors, log, credentials, mode, node, schema, transport, port, jmx, graph, tokenRange);
|
||||
}
|
||||
|
||||
private static Map<String, String[]> parseMap(String[] args)
|
||||
|
|
@ -290,10 +298,14 @@ public class StressSettings implements Serializable
|
|||
transport.printSettings(out);
|
||||
out.println("Port:");
|
||||
port.printSettings(out);
|
||||
out.println("JMX:");
|
||||
jmx.printSettings(out);
|
||||
out.println("Graph:");
|
||||
graph.printSettings(out);
|
||||
out.println("TokenRange:");
|
||||
tokenRange.printSettings(out);
|
||||
out.println("Credentials file:");
|
||||
credentials.printSettings(out);
|
||||
|
||||
if (command.type == Command.USER)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import java.util.concurrent.Executors;
|
|||
import java.util.concurrent.Future;
|
||||
|
||||
import org.apache.cassandra.concurrent.NamedThreadFactory;
|
||||
import org.apache.cassandra.stress.settings.SettingsJMX;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
|
||||
public class JmxCollector implements Callable<JmxCollector.GcStats>
|
||||
|
|
@ -76,23 +77,26 @@ public class JmxCollector implements Callable<JmxCollector.GcStats>
|
|||
final NodeProbe[] probes;
|
||||
|
||||
// TODO: should expand to whole cluster
|
||||
public JmxCollector(Collection<String> hosts, int port)
|
||||
public JmxCollector(Collection<String> hosts, int port, SettingsJMX jmx)
|
||||
{
|
||||
probes = new NodeProbe[hosts.size()];
|
||||
int i = 0;
|
||||
for (String host : hosts)
|
||||
{
|
||||
probes[i] = connect(host, port);
|
||||
probes[i] = connect(host, port, jmx);
|
||||
probes[i].getAndResetGCStats();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private static NodeProbe connect(String host, int port)
|
||||
private static NodeProbe connect(String host, int port, SettingsJMX jmx)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new NodeProbe(host, port);
|
||||
if (jmx.user != null && jmx.password != null)
|
||||
return new NodeProbe(host, port, jmx.user, jmx.password);
|
||||
else
|
||||
return new NodeProbe(host, port);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* 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.stress.settings;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.io.util.File;
|
||||
import org.apache.cassandra.io.util.FileUtils;
|
||||
|
||||
import static org.apache.cassandra.io.util.File.WriteMode.OVERWRITE;
|
||||
import static org.apache.cassandra.stress.settings.SettingsCredentials.CQL_PASSWORD_PROPERTY_KEY;
|
||||
import static org.apache.cassandra.stress.settings.SettingsCredentials.CQL_USERNAME_PROPERTY_KEY;
|
||||
import static org.apache.cassandra.stress.settings.SettingsCredentials.JMX_PASSWORD_PROPERTY_KEY;
|
||||
import static org.apache.cassandra.stress.settings.SettingsCredentials.JMX_USERNAME_PROPERTY_KEY;
|
||||
import static org.apache.cassandra.stress.settings.SettingsCredentials.TRANSPORT_KEYSTORE_PASSWORD_PROPERTY_KEY;
|
||||
import static org.apache.cassandra.stress.settings.SettingsCredentials.TRANSPORT_TRUSTSTORE_PASSWORD_PROPERTY_KEY;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class SettingsCredentialsTest
|
||||
{
|
||||
@Test
|
||||
public void testReadCredentialsFromFileMixed() throws Exception
|
||||
{
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(CQL_USERNAME_PROPERTY_KEY, "cqluserfromfile");
|
||||
properties.setProperty(CQL_PASSWORD_PROPERTY_KEY, "cqlpasswordfromfile");
|
||||
properties.setProperty(JMX_USERNAME_PROPERTY_KEY, "jmxuserfromfile");
|
||||
properties.setProperty(JMX_PASSWORD_PROPERTY_KEY, "jmxpasswordfromfile");
|
||||
properties.setProperty(TRANSPORT_KEYSTORE_PASSWORD_PROPERTY_KEY, "keystorestorepasswordfromfile");
|
||||
properties.setProperty(TRANSPORT_TRUSTSTORE_PASSWORD_PROPERTY_KEY, "truststorepasswordfromfile");
|
||||
|
||||
File tempFile = FileUtils.createTempFile("cassandra-stress-credentials-test", "properties");
|
||||
|
||||
try (Writer w = tempFile.newWriter(OVERWRITE))
|
||||
{
|
||||
properties.store(w, null);
|
||||
}
|
||||
|
||||
Map<String, String[]> args = new HashMap<>();
|
||||
args.put("write", new String[]{});
|
||||
args.put("-mode", new String[]{ "cql3", "native", "password=cqlpasswordoncommandline" });
|
||||
args.put("-transport", new String[]{ "truststore=sometruststore", "keystore=somekeystore" });
|
||||
args.put("-jmx", new String[]{ "password=jmxpasswordoncommandline" });
|
||||
args.put("-credentials-file", new String[]{ tempFile.absolutePath() });
|
||||
StressSettings settings = StressSettings.get(args);
|
||||
|
||||
assertEquals("cqluserfromfile", settings.credentials.cqlUsername);
|
||||
assertEquals("cqlpasswordfromfile", settings.credentials.cqlPassword);
|
||||
assertEquals("jmxuserfromfile", settings.credentials.jmxUsername);
|
||||
assertEquals("jmxpasswordfromfile", settings.credentials.jmxPassword);
|
||||
assertEquals("keystorestorepasswordfromfile", settings.credentials.transportKeystorePassword);
|
||||
assertEquals("truststorepasswordfromfile", settings.credentials.transportTruststorePassword);
|
||||
|
||||
assertEquals("cqluserfromfile", settings.mode.username);
|
||||
assertEquals("cqlpasswordoncommandline", settings.mode.password);
|
||||
assertEquals("jmxuserfromfile", settings.jmx.user);
|
||||
assertEquals("jmxpasswordoncommandline", settings.jmx.password);
|
||||
assertEquals("keystorestorepasswordfromfile", settings.transport.getEncryptionOptions().keystore_password);
|
||||
assertEquals("truststorepasswordfromfile", settings.transport.getEncryptionOptions().truststore_password);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadCredentialsFromFileOverridenByCommandLine() throws Exception
|
||||
{
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(CQL_USERNAME_PROPERTY_KEY, "cqluserfromfile");
|
||||
properties.setProperty(CQL_PASSWORD_PROPERTY_KEY, "cqlpasswordfromfile");
|
||||
properties.setProperty(JMX_USERNAME_PROPERTY_KEY, "jmxuserfromfile");
|
||||
properties.setProperty(JMX_PASSWORD_PROPERTY_KEY, "jmxpasswordfromfile");
|
||||
properties.setProperty(TRANSPORT_KEYSTORE_PASSWORD_PROPERTY_KEY, "keystorestorepasswordfromfile");
|
||||
properties.setProperty(TRANSPORT_TRUSTSTORE_PASSWORD_PROPERTY_KEY, "truststorepasswordfromfile");
|
||||
|
||||
File tempFile = FileUtils.createTempFile("cassandra-stress-credentials-test", "properties");
|
||||
|
||||
try (Writer w = tempFile.newWriter(OVERWRITE))
|
||||
{
|
||||
properties.store(w, null);
|
||||
}
|
||||
|
||||
Map<String, String[]> args = new HashMap<>();
|
||||
args.put("write", new String[]{});
|
||||
args.put("-mode", new String[]{ "cql3", "native", "password=cqlpasswordoncommandline", "user=cqluseroncommandline" });
|
||||
args.put("-jmx", new String[]{ "password=jmxpasswordoncommandline", "user=jmxuseroncommandline" });
|
||||
args.put("-transport", new String[]{ "truststore=sometruststore",
|
||||
"keystore=somekeystore",
|
||||
"truststore-password=truststorepasswordfromcommandline",
|
||||
"keystore-password=keystorepasswordfromcommandline" });
|
||||
args.put("-credentials-file", new String[]{ tempFile.absolutePath() });
|
||||
StressSettings settings = StressSettings.get(args);
|
||||
|
||||
assertEquals("cqluserfromfile", settings.credentials.cqlUsername);
|
||||
assertEquals("cqlpasswordfromfile", settings.credentials.cqlPassword);
|
||||
assertEquals("jmxuserfromfile", settings.credentials.jmxUsername);
|
||||
assertEquals("jmxpasswordfromfile", settings.credentials.jmxPassword);
|
||||
assertEquals("keystorestorepasswordfromfile", settings.credentials.transportKeystorePassword);
|
||||
assertEquals("truststorepasswordfromfile", settings.credentials.transportTruststorePassword);
|
||||
|
||||
assertEquals("cqluseroncommandline", settings.mode.username);
|
||||
assertEquals("cqlpasswordoncommandline", settings.mode.password);
|
||||
assertEquals("jmxuseroncommandline", settings.jmx.user);
|
||||
assertEquals("jmxpasswordoncommandline", settings.jmx.password);
|
||||
assertEquals("truststorepasswordfromcommandline", settings.transport.getEncryptionOptions().truststore_password);
|
||||
assertEquals("keystorepasswordfromcommandline", settings.transport.getEncryptionOptions().keystore_password);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue