This is an automated email from the ASF dual-hosted git repository.
smiklosovic pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/trunk by this push:
new 4d2ee09ffa Make cassandra-stress able to read all credentials from a
file
4d2ee09ffa is described below
commit 4d2ee09ffabf7fb086fb9e2bd042fc946e72c3ec
Author: Stefan Miklosovic <[email protected]>
AuthorDate: Fri May 19 12:31:40 2023 +0200
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
---
CHANGES.txt | 1 +
NEWS.txt | 2 +
.../pages/managing/tools/cassandra_stress.adoc | 4 +
.../cassandra/stress/report/StressMetrics.java | 3 +-
.../cassandra/stress/settings/CliOption.java | 13 ++-
.../stress/settings/SettingsCredentials.java | 129 +++++++++++++++++++++
.../cassandra/stress/settings/SettingsJMX.java | 98 ++++++++++++++++
.../cassandra/stress/settings/SettingsMode.java | 26 +++--
.../stress/settings/SettingsTransport.java | 46 ++++++--
.../cassandra/stress/settings/StressSettings.java | 18 ++-
.../apache/cassandra/stress/util/JmxCollector.java | 12 +-
.../stress/settings/SettingsCredentialsTest.java | 126 ++++++++++++++++++++
12 files changed, 446 insertions(+), 32 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 168e5b2bed..b3e78b4dea 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -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)
diff --git a/NEWS.txt b/NEWS.txt
index 5c3267e1e0..b209e5adb0 100644
--- a/NEWS.txt
+++ b/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
---------
diff --git a/doc/modules/cassandra/pages/managing/tools/cassandra_stress.adoc
b/doc/modules/cassandra/pages/managing/tools/cassandra_stress.adoc
index 7cf3548c48..e24367caca 100644
--- a/doc/modules/cassandra/pages/managing/tools/cassandra_stress.adoc
+++ b/doc/modules/cassandra/pages/managing/tools/cassandra_stress.adoc
@@ -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
diff --git
a/tools/stress/src/org/apache/cassandra/stress/report/StressMetrics.java
b/tools/stress/src/org/apache/cassandra/stress/report/StressMetrics.java
index b50dfd23f0..85bfc32121 100644
--- a/tools/stress/src/org/apache/cassandra/stress/report/StressMetrics.java
+++ b/tools/stress/src/org/apache/cassandra/stress/report/StressMetrics.java
@@ -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)
{
diff --git
a/tools/stress/src/org/apache/cassandra/stress/settings/CliOption.java
b/tools/stress/src/org/apache/cassandra/stress/settings/CliOption.java
index eba276e241..3d721f3cc7 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/CliOption.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/CliOption.java
@@ -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("_", "-");
+ }
}
diff --git
a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCredentials.java
b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCredentials.java
new file mode 100644
index 0000000000..76513b75f9
--- /dev/null
+++
b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCredentials.java
@@ -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;
+ }
+}
diff --git
a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsJMX.java
b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsJMX.java
new file mode 100644
index 0000000000..af202bef43
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsJMX.java
@@ -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;
+ }
+}
diff --git
a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
index 7e53547e81..b009d04177 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
@@ -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()
diff --git
a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
index 5f22a7b7c2..cf62999822 100644
---
a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
+++
b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
@@ -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()
diff --git
a/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
index 2f76dfb0fd..9b831187f2 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
@@ -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)
{
diff --git
a/tools/stress/src/org/apache/cassandra/stress/util/JmxCollector.java
b/tools/stress/src/org/apache/cassandra/stress/util/JmxCollector.java
index 8cfbebbd65..24cb4c788b 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/JmxCollector.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/JmxCollector.java
@@ -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)
{
diff --git
a/tools/stress/test/unit/org/apache/cassandra/stress/settings/SettingsCredentialsTest.java
b/tools/stress/test/unit/org/apache/cassandra/stress/settings/SettingsCredentialsTest.java
new file mode 100644
index 0000000000..a1a07c4612
--- /dev/null
+++
b/tools/stress/test/unit/org/apache/cassandra/stress/settings/SettingsCredentialsTest.java
@@ -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);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]