From ac8743269c2147ffd66efec42c464fc5eab8aead Mon Sep 17 00:00:00 2001 From: Calle Wilund Date: Wed, 25 Jan 2017 15:12:58 +0000 Subject: [PATCH] scylla-jmx: Allow ssl, auth etc options for JMX connector Actually removes a bunch of code to manage the JMX connector, since as of jdk8u102, the standard jmx connector answers to property setting bind address -> can restrict access. Note that the RMI connector will now (as is jdk normal) _bind_ to 0.0.0.0, but it will not answer non-local requests if "remote" is not enabled. This is the default jdk behaviour. In any case, we rely on setting the appropriate properties instead, and also allow pass-through of -D flags to java, which in turn means those who wish can turn on both auth and ssl, set key/trust stores etc etc. Message-Id: <1485357178-20714-1-git-send-email-calle@scylladb.com> --- scripts/scylla-jmx | 57 ++++++++-- src/main/java/com/scylladb/jmx/main/Main.java | 102 +++--------------- 2 files changed, 67 insertions(+), 92 deletions(-) diff --git a/scripts/scylla-jmx b/scripts/scylla-jmx index 10a9e55..0247896 100755 --- a/scripts/scylla-jmx +++ b/scripts/scylla-jmx @@ -3,12 +3,16 @@ # Copyright (C) 2015 Cloudius Systems, Ltd. JMX_PORT="7199" -API_ADDR="" -API_PORT="" +JMX_ADDR= + +API_ADDR= +API_PORT= + CONF_FILE="" DEBUG="" PARAM_HELP="-h" PARAM_JMX_PORT="-jp" +PARAM_JMX_ADDR="-ja" PARAM_API_PORT="-p" PARAM_ADDR="-a" PARAM_LOCATION="-l" @@ -20,6 +24,11 @@ ALLOW_DEBUG="-d" REMOTE=0 HOSTNAME=`hostname` + +PROPERTIES= +JMX_AUTH=-Dcom.sun.management.jmxremote.authenticate=false +JMX_SSL=-Dcom.sun.management.jmxremote.ssl=false + print_help() { cat < - The jmx port to open $PARAM_API_PORT - The API port to connect to $PARAM_ADDR
- The API address to connect to + $PARAM_JMX_ADDR
- JMX bind address $PARAM_FILE - A configuration file to use $PARAM_LOCATION - The location of the jmx proxy jar file $ALLOW_REMOTE - When set allow remote jmx connectivity @@ -61,6 +71,10 @@ do JMX_PORT=$2 shift 2 ;; + "$PARAM_JMX_ADDR") + JMX_ADDR=-Dcom.sun.management.jmxremote.host=$2 + shift 2 + ;; "$PARAM_LOCATION") LOCATION=$2 LOCATION_SCRIPTS="$2" @@ -82,6 +96,26 @@ do DEBUG="-agentlib:jdwp=transport=dt_socket,address=127.0.0.1:7690,server=y,suspend=n" shift 1 ;; + -Dcom.sun.management.jmxremote.host=*) + JMX_ADDR=$1 + shift + ;; + -Dcom.sun.management.jmxremote.authenticate=*) + JMX_AUTH=$1 + shift 1 + ;; + -Dcom.sun.management.jmxremote.ssl=*) + JMX_SSL=$1 + shift 1 + ;; + -Dcom.sun.management.jmxremote.local.only=*) + JMX_LOCAL=$1 + shift 1 + ;; + -D*) + PROPERTIES="$PROPERTIES $1" + shift 1 + ;; *) echo "Unknown parameter: $1" print_help @@ -89,11 +123,20 @@ do esac done - -if [ $REMOTE -eq 1 ]; then - REMOTE="-Djavax.management.builder.initial=com.scylladb.jmx.utils.APIBuilder -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=$JMX_PORT -Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT -Dcom.sun.management.jmxremote.local.only=false -Djava.rmi.server.hostname=$HOSTNAME" +if [ $REMOTE -eq 0 ]; then + if [ -z $JMX_ADDR ]; then + JMX_ADDR=-Dcom.sun.management.jmxremote.host=localhost + fi else - REMOTE="-Dcassandra.jmx.local.port=$JMX_PORT" + if [ -z $JMX_LOCAL ]; then + JMX_LOCAL=-Dcom.sun.management.jmxremote.local.only=false + fi fi -exec "$LOCATION_SCRIPTS"/symlinks/scylla-jmx $API_ADDR $API_PORT $DEBUG $CONF_FILE $REMOTE -Xmx256m -XX:+UseSerialGC -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -jar $LOCATION/scylla-jmx-1.0.jar +exec "$LOCATION_SCRIPTS"/symlinks/scylla-jmx $DEBUG \ + $API_PORT $API_ADDR $CONF_FILE -Xmx256m -XX:+UseSerialGC \ + $JMX_AUTH $JMX_SSL $JMX_ADDR $JMX_LOCAL \ + -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=$JMX_PORT \ + -Djava.rmi.server.hostname=$HOSTNAME -Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT \ + -Djavax.management.builder.initial=com.scylladb.jmx.utils.APIBuilder \ + $PROPERTIES -jar $LOCATION/scylla-jmx-1.0.jar diff --git a/src/main/java/com/scylladb/jmx/main/Main.java b/src/main/java/com/scylladb/jmx/main/Main.java index 6a8dfd3..3aa5a2f 100644 --- a/src/main/java/com/scylladb/jmx/main/Main.java +++ b/src/main/java/com/scylladb/jmx/main/Main.java @@ -4,22 +4,11 @@ package com.scylladb.jmx.main; import static java.lang.management.ManagementFactory.getPlatformMBeanServer; -import static java.rmi.registry.LocateRegistry.createRegistry; import static java.util.Arrays.asList; -import static javax.net.ServerSocketFactory.getDefault; -import java.io.IOException; import java.lang.reflect.Constructor; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.rmi.server.RMIServerSocketFactory; -import java.util.HashMap; -import java.util.Map; import javax.management.MBeanServer; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXServiceURL; -import javax.management.remote.rmi.RMIConnectorServer; import org.apache.cassandra.db.commitlog.CommitLog; import org.apache.cassandra.db.compaction.CompactionManager; @@ -42,88 +31,31 @@ public class Main { private static final APIConfig config = new APIConfig(); public static final APIClient client = new APIClient(config); - private static JMXConnectorServer jmxServer = null; - - private static void setupJmx() { - System.setProperty("javax.management.builder.initial", "com.scylladb.jmx.utils.APIBuilder"); - String jmxPort = System.getProperty("com.sun.management.jmxremote.port"); - - if (jmxPort == null) { - System.out.println("JMX is not enabled to receive remote connections."); - - jmxPort = System.getProperty("cassandra.jmx.local.port", "7199"); - String address = System.getProperty("jmx.address", "localhost"); - if (address.equals("localhost")) { - System.setProperty("java.rmi.server.hostname", InetAddress.getLoopbackAddress().getHostAddress()); - } else { - try { - System.setProperty("java.rmi.server.hostname", InetAddress.getByName(address).getHostAddress()); - } catch (UnknownHostException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - try { - RMIServerSocketFactory serverFactory = pPort -> getDefault().createServerSocket(pPort, 0, - InetAddress.getLoopbackAddress()); - createRegistry(Integer.valueOf(jmxPort), null, serverFactory); - - StringBuffer url = new StringBuffer(); - url.append("service:jmx:"); - url.append("rmi://").append(address).append("/jndi/"); - url.append("rmi://").append(address).append(":").append(jmxPort).append("/jmxrmi"); - System.out.println(url); - Map env = new HashMap<>(); - env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, serverFactory); - - jmxServer = new RMIConnectorServer(new JMXServiceURL(url.toString()), env, getPlatformMBeanServer()); - - jmxServer.start(); - } catch (IOException e) { - System.out.println("Error starting local jmx server: " + e.toString()); - } - - } else { - System.out.println("JMX is enabled to receive remote connections on port: " + jmxPort); - } - - } - public static void main(String[] args) throws Exception { System.out.println("Connecting to " + config.getBaseUrl()); System.out.println("Starting the JMX server"); - setupJmx(); + MBeanServer server = getPlatformMBeanServer(); + for (Class clazz : asList(StorageService.class, StorageProxy.class, MessagingService.class, + CommitLog.class, Gossiper.class, EndpointSnitchInfo.class, FailureDetector.class, CacheService.class, + CompactionManager.class, GCInspector.class, StreamManager.class)) { + Constructor c = clazz.getDeclaredConstructor(APIClient.class); + APIMBean m = c.newInstance(client); + server.registerMBean(m, null); + } try { - MBeanServer server = getPlatformMBeanServer(); - for (Class clazz : asList(StorageService.class, StorageProxy.class, - MessagingService.class, CommitLog.class, Gossiper.class, EndpointSnitchInfo.class, - FailureDetector.class, CacheService.class, CompactionManager.class, GCInspector.class, - StreamManager.class)) { - Constructor c = clazz.getDeclaredConstructor(APIClient.class); - APIMBean m = c.newInstance(client); - server.registerMBean(m, null); - } + // forces check for dynamically created mbeans + server.queryNames(null, null); + } catch (IllegalStateException e) { + // ignore this. Just means we started before scylla. + } - try { - // forces check for dynamically created mbeans - server.queryNames(null, null); - } catch (IllegalStateException e) { - // ignore this. Just means we started before scylla. - } + String jmxPort = System.getProperty("com.sun.management.jmxremote.port"); + System.out.println("JMX is enabled to receive remote connections on port: " + jmxPort); - for (;;) { - Thread.sleep(Long.MAX_VALUE); - } - } finally { - // make sure to kill the server otherwise we can hang. Not an issue - // when killed perhaps, but any exception above etc would leave a - // zombie. - if (jmxServer != null) { - jmxServer.stop(); - } + for (;;) { + Thread.sleep(Long.MAX_VALUE); } }