rewrite JMX as a driver adapter

This commit is contained in:
Jonathan Shook
2022-05-25 11:58:32 -05:00
parent 5a4692cf9e
commit 9275181cbf
22 changed files with 624 additions and 376 deletions

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.adapter.jmx;
import io.nosqlbench.adapter.jmx.mappers.JMXOpMapper;
import io.nosqlbench.engine.api.activityimpl.OpMapper;
import io.nosqlbench.engine.api.activityimpl.uniform.DriverAdapter;
import io.nosqlbench.engine.api.activityimpl.uniform.DriverSpaceCache;
import io.nosqlbench.engine.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.nb.annotations.Service;
import io.nosqlbench.nb.api.config.standard.NBConfigModel;
import io.nosqlbench.nb.api.config.standard.NBConfigurable;
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
@Service(value = DriverAdapter.class, selector = "jmx-v2")
public class JMXDriverAdapter implements DriverAdapter<Op,JMXSpace>, NBConfigurable {
private NBConfiguration config;
@Override
public OpMapper<Op> getOpMapper() {
return new JMXOpMapper(getSpaceCache());
}
@Override
public DriverSpaceCache<? extends JMXSpace> getSpaceCache() {
return new DriverSpaceCache<>(JMXSpace::new);
}
@Override
public NBConfiguration getConfiguration() {
return config;
}
@Override
public void applyConfig(NBConfiguration cfg) {
this.config = cfg;
}
@Override
public NBConfigModel getConfigModel() {
return new JMXSpace("test").getConfigModel();
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.adapter.jmx;
public enum JMXOpTypes {
Read,
Print,
Explain
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.adapter.jmx;
import io.nosqlbench.engine.api.util.SSLKsFactory;
import io.nosqlbench.nb.api.config.standard.*;
import io.nosqlbench.nb.api.errors.OpConfigError;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
public class JMXSpace implements NBConfigurable {
private final String name;
private JMXConnector connector;
private NBConfiguration cfg;
public JMXSpace(String name) {
this.name = name;
}
@Override
public void applyConfig(NBConfiguration cfg) {
this.cfg = cfg;
}
public NBConfigModel getConfigModel() {
return ConfigModel.of(JMXSpace.class)
.add(Param.optional("username", String.class))
.add(Param.optional("password", String.class))
.add(SSLKsFactory.get().getConfigModel())
.asReadOnly();
}
public synchronized JMXConnector getConnector() {
if (this.connector == null) {
this.connector = bindConnector();
}
return this.connector;
}
private JMXConnector bindConnector() {
Map<String, Object> connectorEnv = new HashMap<>();
String username = cfg.getOptional("username")
.map(u -> SecureUtils.readSecret("JMX username", u))
.orElse(null);
String password = cfg.getOptional("password")
.map(p -> SecureUtils.readSecret("JMX password", p))
.orElse(null);
if (username != null && password != null) {
connectorEnv.put(JMXConnector.CREDENTIALS, new String[]{username, password});
}
JMXConnector connector = null;
try {
JMXServiceURL url = bindJMXServiceURL();
connector = JMXConnectorFactory.connect(url, connectorEnv);
} catch (IOException e) {
e.printStackTrace();
}
return connector;
}
private JMXServiceURL bindJMXServiceURL() {
JMXServiceURL url = null;
url = cfg.getOptional("url")
.map(
u -> {
try {
return new JMXServiceURL(u);
} catch (MalformedURLException e) {
throw new OpConfigError("Error with JMX URL: " + e);
}
})
.orElse(null);
if (url!=null) {
return url;
}
String host = cfg.get("host");
String protocol = cfg.get("protocol");
int port = cfg.getOrDefault("port", 0);
String path = cfg.get("path");
try {
return new JMXServiceURL(protocol, host, port, path);
} catch (MalformedURLException e) {
throw new OpConfigError("Error with JMX URL parameters: " + e);
}
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.nosqlbench.driver.jmx;
package io.nosqlbench.adapter.jmx;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

View File

@@ -14,9 +14,7 @@
* limitations under the License.
*/
package io.nosqlbench.driver.jmx;
import java.util.function.Function;
package io.nosqlbench.adapter.jmx;
public class ValueConverter {

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.adapter.jmx.dispensers;
import io.nosqlbench.adapter.jmx.JMXSpace;
import io.nosqlbench.adapter.jmx.operations.JMXExplainOperation;
import io.nosqlbench.engine.api.activityimpl.BaseOpDispenser;
import io.nosqlbench.engine.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.engine.api.templating.ParsedOp;
import javax.management.ObjectName;
import java.util.function.LongFunction;
public class JMXExplainDispenser extends BaseOpDispenser<Op> {
private final LongFunction<JMXSpace> spaceF;
private final LongFunction<ObjectName> nameF;
public JMXExplainDispenser(LongFunction<JMXSpace> spaceF, LongFunction<ObjectName> nameF, ParsedOp op) {
super(op);
this.spaceF =spaceF;
this.nameF = nameF;
}
@Override
public Op apply(long value) {
return new JMXExplainOperation(
spaceF.apply(value).getConnector(),
nameF.apply(value)
);
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.adapter.jmx.dispensers;
import io.nosqlbench.adapter.jmx.JMXSpace;
import io.nosqlbench.adapter.jmx.operations.JMXPrintOperation;
import io.nosqlbench.engine.api.activityimpl.BaseOpDispenser;
import io.nosqlbench.engine.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.engine.api.templating.ParsedOp;
import io.nosqlbench.virtdata.library.basics.core.threadstate.SharedState;
import javax.management.ObjectName;
import java.util.function.LongFunction;
public class JMXPrintDispenser extends BaseOpDispenser<Op> {
private final LongFunction<JMXSpace> spaceF;
private final LongFunction<ObjectName> nameF;
private final LongFunction<String> readvarF;
private final LongFunction<String> asTypeF;
private final LongFunction<String> asNameF;
private final LongFunction<SharedState.Scope> scopeF;
public JMXPrintDispenser(LongFunction<JMXSpace> spaceF, LongFunction<ObjectName> nameF, ParsedOp op) {
super(op);
this.spaceF =spaceF;
this.nameF = nameF;
this.readvarF = op.getAsFunctionOr("readvar","Value");
this.asTypeF = op.getAsFunctionOr("as_type","String");
this.asNameF = op.getAsOptionalFunction("as_name", String.class).orElse(readvarF);
this.scopeF = op.getAsOptionalEnumFunction("scope", SharedState.Scope.class).orElse(l -> SharedState.Scope.thread);
}
@Override
public Op apply(long value) {
return new JMXPrintOperation(
spaceF.apply(value),
nameF.apply(value),
readvarF.apply(value),
asTypeF.apply(value),
asNameF.apply(value),
scopeF.apply(value)
);
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.adapter.jmx.dispensers;
import io.nosqlbench.adapter.jmx.JMXSpace;
import io.nosqlbench.adapter.jmx.operations.JMXReadOperation;
import io.nosqlbench.engine.api.activityimpl.BaseOpDispenser;
import io.nosqlbench.engine.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.engine.api.templating.ParsedOp;
import io.nosqlbench.virtdata.library.basics.core.threadstate.SharedState;
import javax.management.ObjectName;
import java.util.function.LongFunction;
public class JMXReadDispenser extends BaseOpDispenser<Op> {
private final LongFunction<JMXSpace> spaceF;
private final LongFunction<ObjectName> nameF;
private final LongFunction<String> readvarF;
private final LongFunction<String> asTypeF;
private final LongFunction<String> asNameF;
private final LongFunction<SharedState.Scope> scopeF;
public JMXReadDispenser(LongFunction<JMXSpace> spaceF, LongFunction<ObjectName> nameF, ParsedOp op) {
super(op);
this.spaceF =spaceF;
this.nameF = nameF;
this.readvarF = op.getAsFunctionOr("readvar","Value");
this.asTypeF = op.getAsFunctionOr("as_type","String");
this.asNameF = op.getAsOptionalFunction("as_name", String.class).orElse(readvarF);
this.scopeF = op.getAsOptionalEnumFunction("scope", SharedState.Scope.class).orElse(l -> SharedState.Scope.thread);
}
@Override
public Op apply(long value) {
return new JMXReadOperation(
spaceF.apply(value),
nameF.apply(value),
readvarF.apply(value),
asTypeF.apply(value),
asNameF.apply(value),
scopeF.apply(value)
);
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.nosqlbench.driver.jmx.formats;
package io.nosqlbench.adapter.jmx.formats;
import javax.management.*;
import java.util.Map;

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.adapter.jmx.mappers;
import io.nosqlbench.adapter.jmx.JMXOpTypes;
import io.nosqlbench.adapter.jmx.JMXSpace;
import io.nosqlbench.adapter.jmx.dispensers.JMXExplainDispenser;
import io.nosqlbench.adapter.jmx.dispensers.JMXPrintDispenser;
import io.nosqlbench.adapter.jmx.dispensers.JMXReadDispenser;
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
import io.nosqlbench.engine.api.activityimpl.OpMapper;
import io.nosqlbench.engine.api.activityimpl.uniform.DriverSpaceCache;
import io.nosqlbench.engine.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.engine.api.templating.ParsedOp;
import io.nosqlbench.engine.api.templating.TypeAndTarget;
import io.nosqlbench.nb.api.errors.OpConfigError;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import java.util.function.LongFunction;
public class JMXOpMapper implements OpMapper<Op> {
private final DriverSpaceCache<? extends JMXSpace> jmxCache;
public JMXOpMapper(DriverSpaceCache<? extends JMXSpace> jmxCache) {
this.jmxCache = jmxCache;
}
@Override
public OpDispenser<? extends Op> apply(ParsedOp op) {
LongFunction<String> spaceNameFunc = op.getAsFunctionOr("space","default");
LongFunction<JMXSpace> spaceFunc = l -> jmxCache.get(spaceNameFunc.apply(l));
LongFunction<? extends String> nameFunction = op.getAsRequiredFunction("object");
LongFunction<ObjectName> oNameFunc = n -> {
try {
String name = nameFunction.apply(n);
return new ObjectName(name);
} catch (MalformedObjectNameException e) {
throw new OpConfigError("You must specify a valid object name for any JMX operation:" + e);
}
};
TypeAndTarget<JMXOpTypes, String> optype = op.getTypeAndTarget(JMXOpTypes.class, String.class, "type", "target");
return switch (optype.enumId) {
case Read -> new JMXReadDispenser(spaceFunc, oNameFunc, op);
case Print -> new JMXPrintDispenser(spaceFunc, oNameFunc, op);
case Explain -> new JMXExplainDispenser(spaceFunc, oNameFunc, op);
};
}
}

View File

@@ -14,13 +14,12 @@
* limitations under the License.
*/
package io.nosqlbench.driver.jmx.ops;
package io.nosqlbench.adapter.jmx.operations;
import io.nosqlbench.driver.jmx.formats.MBeanInfoConsoleFormat;
import io.nosqlbench.adapter.jmx.formats.MBeanInfoConsoleFormat;
import javax.management.*;
import javax.management.remote.JMXConnector;
import java.io.IOException;
public class JMXExplainOperation extends JmxOp {
public final static String EXPLAIN = "explain";

View File

@@ -14,33 +14,38 @@
* limitations under the License.
*/
package io.nosqlbench.driver.jmx.ops;
package io.nosqlbench.adapter.jmx.operations;
import io.nosqlbench.driver.jmx.ValueConverter;
import io.nosqlbench.adapter.jmx.JMXSpace;
import io.nosqlbench.adapter.jmx.ValueConverter;
import io.nosqlbench.virtdata.library.basics.core.threadstate.SharedState;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import java.util.Map;
public class JMXPrintOperation extends JMXReadOperation {
public static final String PRINTVAR = "printvar";
public JMXPrintOperation(JMXConnector connector, ObjectName objectName, String attribute, Map<String, String> cfg) {
super(connector, objectName, attribute, cfg);
public JMXPrintOperation(
JMXSpace space,
ObjectName oname,
String readvar,
String asType,
String asName,
SharedState.Scope scope
) {
super(space, oname, readvar, asType, asName, scope);
}
@Override
public void execute() {
Object value = readObject(attribute);
System.out.println("# read JMX attribute '" + attribute + "' as " + value.getClass() +
Object value = readObject(readvar);
System.out.println("# read JMX attribute '" + readvar + "' as " + value.getClass() +
((asType != null) ? " as_type=" + asType : "") +
((asName != null) ? " as_name=" + asName : ""));
if (asType != null) {
value = ValueConverter.convert(asType, value);
}
String storedName = (asName == null) ? attribute : asName;
String storedName = (asName == null) ? readvar : asName;
System.out.println(storedName + "=" + value + "\n");
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.adapter.jmx.operations;
import io.nosqlbench.adapter.jmx.JMXSpace;
import io.nosqlbench.adapter.jmx.ValueConverter;
import io.nosqlbench.virtdata.library.basics.core.threadstate.SharedState;
import javax.management.ObjectName;
public class JMXReadOperation extends JmxOp {
protected final String readvar;
protected final String asType;
protected final String asName;
protected final SharedState.Scope scope;
public JMXReadOperation(
JMXSpace space,
ObjectName oname,
String readvar,
String asType,
String asName,
SharedState.Scope scope
) {
super(space.getConnector(), oname);
this.readvar = readvar;
this.asType = asType;
this.asName = asName;
this.scope = scope;
}
@Override
public void execute() {
Object value = readObject(readvar);
value = ValueConverter.convert(asType, value);
String storedName = asName;
SharedState.put(scope, storedName, value);
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.nosqlbench.driver.jmx.ops;
package io.nosqlbench.adapter.jmx.operations;
import io.nosqlbench.engine.api.activityimpl.uniform.flowtypes.Op;
import org.apache.logging.log4j.LogManager;

View File

@@ -1,56 +0,0 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.driver.jmx;
import io.nosqlbench.driver.jmx.ops.JmxOp;
import io.nosqlbench.engine.api.activityapi.core.SyncAction;
import io.nosqlbench.engine.api.activityapi.planning.OpSequence;
import io.nosqlbench.engine.api.activityimpl.ActivityDef;
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class JMXAction implements SyncAction {
private final static Logger logger = LogManager.getLogger(JMXAction.class);
private final ActivityDef activityDef;
private final int slot;
private final JMXActivity activity;
private OpSequence<OpDispenser<? extends JmxOp>> sequencer;
public JMXAction(ActivityDef activityDef, int slot, JMXActivity activity) {
this.activityDef = activityDef;
this.slot = slot;
this.activity = activity;
}
@Override
public void init() {
this.sequencer = activity.getSequencer();
}
@Override
public int runCycle(long cycle) {
LongFunction<? extends JmxOp> readyJmxOp = sequencer.apply(cycle);
JmxOp jmxOp = readyJmxOp.apply(cycle);
jmxOp.execute();
return 0;
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.driver.jmx;
import io.nosqlbench.driver.jmx.ops.JmxOp;
import io.nosqlbench.engine.api.activityapi.core.Activity;
import io.nosqlbench.engine.api.activityapi.planning.OpSequence;
import io.nosqlbench.engine.api.activityimpl.ActivityDef;
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
import io.nosqlbench.engine.api.activityimpl.SimpleActivity;
import io.nosqlbench.engine.api.util.SSLKsFactory;
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import javax.net.ssl.SSLContext;
public class JMXActivity extends SimpleActivity implements Activity {
private OpSequence<OpDispenser<? extends JmxOp>> sequence;
private SSLContext sslContext;
public JMXActivity(ActivityDef activityDef) {
super(activityDef);
}
@Override
public void initActivity() {
super.initActivity();
this.sequence = createOpSequenceFromCommands(ReadyJmxOp::new, false);
setDefaultsFromOpSequence(sequence);
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
this.sslContext= SSLKsFactory.get().getContext(sslCfg);
// TODO: Require qualified default with an op sequence as the input
}
/**
* If this is null, then no SSL is requested.
* @return The SSLContext for this activity
*/
public SSLContext getSslContext() {
return sslContext;
}
public OpSequence<OpDispenser<? extends JmxOp>> getSequencer() {
return sequence;
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.driver.jmx;
import io.nosqlbench.engine.api.activityapi.core.ActionDispenser;
import io.nosqlbench.engine.api.activityapi.core.ActivityType;
import io.nosqlbench.engine.api.activityimpl.ActivityDef;
import io.nosqlbench.nb.annotations.Service;
@Service(value = ActivityType.class, selector = "jmx")
public class JMXActivityType implements ActivityType<JMXActivity> {
@Override
public JMXActivity getActivity(ActivityDef activityDef) {
return new JMXActivity(activityDef);
}
@Override
public ActionDispenser getActionDispenser(JMXActivity activity) {
return new JMXActionDispenser(activity);
}
}

View File

@@ -1,119 +0,0 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.driver.jmx;
import io.nosqlbench.driver.jmx.ops.JMXExplainOperation;
import io.nosqlbench.driver.jmx.ops.JMXPrintOperation;
import io.nosqlbench.driver.jmx.ops.JMXReadOperation;
import io.nosqlbench.driver.jmx.ops.JmxOp;
import io.nosqlbench.engine.api.activityimpl.BaseOpDispenser;
import io.nosqlbench.engine.api.templating.CommandTemplate;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class ReadyJmxOp extends BaseOpDispenser<JmxOp> {
private final CommandTemplate command;
public ReadyJmxOp(CommandTemplate command) {
super(command);
this.command = command;
}
public JmxOp apply(long value) {
Map<String, String> cmdmap = command.getCommand(value);
JMXConnector connector = bindConnector(cmdmap);
if (!cmdmap.containsKey("object")) {
throw new RuntimeException("You must specify an object in a jmx operation as in object=...");
}
ObjectName objectName = null;
try {
String object = cmdmap.get("object");
if (object == null) {
throw new RuntimeException("You must specify an object name for any JMX operation.");
}
objectName = new ObjectName(object);
} catch (MalformedObjectNameException e) {
e.printStackTrace();
}
if (cmdmap.containsKey(JMXReadOperation.READVAR)) {
return new JMXReadOperation(connector, objectName, cmdmap.get(JMXReadOperation.READVAR), cmdmap);
} else if (cmdmap.containsKey(JMXPrintOperation.PRINTVAR)) {
return new JMXPrintOperation(connector, objectName, cmdmap.get(JMXPrintOperation.PRINTVAR), cmdmap);
} else if (cmdmap.containsKey(JMXExplainOperation.EXPLAIN)) {
return new JMXExplainOperation(connector, objectName);
}
throw new RuntimeException("No valid form of JMX operation was determined from the provided command details:" + cmdmap);
}
private JMXConnector bindConnector(Map<String, String> cmdmap) {
Map<String, Object> connectorEnv = new HashMap<>();
String username = cmdmap.remove("username");
String password = cmdmap.remove("password");
username = SecureUtils.readSecret("JMX username", username);
password = SecureUtils.readSecret("JMX password", password);
if (username != null && password != null) {
connectorEnv.put(JMXConnector.CREDENTIALS, new String[]{username, password});
}
JMXConnector connector = null;
try {
JMXServiceURL url = bindJMXServiceURL(cmdmap);
connector = JMXConnectorFactory.connect(url, connectorEnv);
} catch (IOException e) {
e.printStackTrace();
}
return connector;
}
private JMXServiceURL bindJMXServiceURL(Map<String, String> cmdmap) {
JMXServiceURL url = null;
try {
if (cmdmap.containsKey("url")) {
url = new JMXServiceURL(cmdmap.get("url"));
} else {
if (cmdmap.containsKey("host")) {
throw new RuntimeException("You must provide at least a host if you do not provide a url.");
}
String protocol = cmdmap.get("protocol");
String host = cmdmap.get("host");
int port = Optional.ofNullable(cmdmap.get("port")).map(Integer::parseInt).orElse(0);
String path = cmdmap.get("path");
url = new JMXServiceURL(protocol, host, port, path);
}
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
return url;
}
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.driver.jmx.ops;
import io.nosqlbench.driver.jmx.ValueConverter;
import io.nosqlbench.virtdata.library.basics.core.threadstate.SharedState;
import javax.management.*;
import javax.management.remote.JMXConnector;
import java.util.Map;
public class JMXReadOperation extends JmxOp {
public final static String READVAR = "readvar";
public final static String AS_TYPE = "as_type";
public final static String AS_NAME = "as_name";
public final static String SCOPE = "scope";
protected final String attribute;
protected final String asType;
protected final String asName;
protected final SharedState.Scope scope;
public JMXReadOperation(JMXConnector connector, ObjectName objectName, String attribute, Map<String, String> cfg) {
super(connector, objectName);
this.attribute = attribute;
this.asType = cfg.remove(AS_TYPE);
this.asName = cfg.remove(AS_NAME);
String scopeName = cfg.remove(SCOPE);
if (scopeName != null) {
scope = SharedState.Scope.valueOf(scopeName);
} else {
scope = SharedState.Scope.process;
}
}
@Override
public void execute() {
Object value = readObject(attribute);
if (asType != null) {
value = ValueConverter.convert(asType, value);
}
String storedName = (asName == null) ? attribute : asName;
switch (scope) {
case process:
SharedState.gl_ObjectMap.put(storedName, value);
break;
case thread:
SharedState.tl_ObjectMap.get().put(storedName, value);
break;
}
}
}

View File

@@ -16,18 +16,7 @@
package io.nosqlbench.driver.jmx;
import io.nosqlbench.engine.api.activityapi.core.Action;
import io.nosqlbench.engine.api.activityapi.core.ActionDispenser;
import io.nosqlbench.engine.api.activityimpl.uniform.flowtypes.Op;
public class JMXActionDispenser implements ActionDispenser {
private final JMXActivity activity;
public JMXActionDispenser(JMXActivity activity) {
this.activity = activity;
}
@Override
public Action getAction(int slot) {
return new JMXAction(activity.getActivityDef(),slot,activity);
}
public class BaseJMXOp implements Op {
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed 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 io.nosqlbench.driver.jmx;
import io.nosqlbench.adapter.jmx.SecureUtils;
import io.nosqlbench.engine.api.util.SSLKsFactory;
import io.nosqlbench.nb.api.config.standard.*;
import io.nosqlbench.nb.api.errors.OpConfigError;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
public class JMXSpace implements NBConfigurable {
private final String name;
private NBConfiguration config;
private SSLContext sslContext;
private JMXConnector connector;
public JMXSpace(String name, NBConfiguration config) {
this.name = name;
this.config = config;
SSLKsFactory.get().getContext(config);
}
public synchronized JMXConnector getConnector() {
if (this.connector == null) {
this.connector = bindConnector();
}
return this.connector;
}
private JMXConnector bindConnector() {
Map<String, Object> connectorEnv = new HashMap<>();
String username = config.get("username", String.class);
String password = config.get("password", String.class);
username = SecureUtils.readSecret("JMX username", username);
password = SecureUtils.readSecret("JMX password", password);
if (username != null && password != null) {
connectorEnv.put(JMXConnector.CREDENTIALS, new String[]{username, password});
}
JMXConnector connector = null;
try {
JMXServiceURL url = bindJMXServiceURL();
connector = JMXConnectorFactory.connect(url, connectorEnv);
} catch (IOException e) {
e.printStackTrace();
}
return connector;
}
private JMXServiceURL bindJMXServiceURL() {
JMXServiceURL url = null;
try {
url = config.getOptional("url")
.map(u -> {
try {
return new JMXServiceURL(u);
} catch (MalformedURLException e) {
throw new OpConfigError("Error while configuring JMX service URL: " + e.getMessage());
}
})
.orElse(null);
if (url==null) {
String host = config.get("host");
String protocol = config.get("protocol");
int port = config.get("port", Integer.class);
String path = config.get("path");
url = new JMXServiceURL(protocol, host, port, path);
}
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
return url;
}
@Override
public void applyConfig(NBConfiguration config) {
this.config = config;
}
@Override
public NBConfigModel getConfigModel() {
return ConfigModel.of(JMXSpace.class)
.add(Param.optional("url"))
.add(Param.optional("host"))
.add(Param.optional("protocol"))
.add(Param.optional("port",Integer.class))
.add(Param.optional("path"))
.add(Param.optional("username"))
.add(Param.optional("password"))
.add(SSLKsFactory.get().getConfigModel())
.asReadOnly();
}
// NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
// this.sslContext= SSLKsFactory.get().getContext(sslCfg);
}

View File

@@ -16,6 +16,7 @@
package io.nosqlbench.driver.jmx;
import io.nosqlbench.adapter.jmx.ValueConverter;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;