diff --git a/CHANGES.txt b/CHANGES.txt index 954fa3f9d6..50c796714e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +2.1.4 + * If no JMX flags are set start a localhost only JMX service + 2.1.3 * Fix HSHA/offheap_objects corruption (CASSANDRA-8719) * Upgrade libthrift to 0.9.2 (CASSANDRA-8685) diff --git a/NEWS.txt b/NEWS.txt index 602770c784..076885c9b1 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -13,6 +13,12 @@ restore snapshots created with the previous major version using the 'sstableloader' tool. You can upgrade the file format of your snapshots using the provided 'sstableupgrade' tool. +2.1.4 +===== + +The default JMX config now listens to localhost only. You must enable +the other JMX flags in cassandra-env.sh manually. + 2.1.3 ===== diff --git a/bin/cassandra.bat b/bin/cassandra.bat index 99b291ad77..fefd3fcc8e 100644 --- a/bin/cassandra.bat +++ b/bin/cassandra.bat @@ -65,10 +65,13 @@ set JAVA_OPTS=-ea^ -XX:MaxTenuringThreshold=1^ -XX:CMSInitiatingOccupancyFraction=75^ -XX:+UseCMSInitiatingOccupancyOnly^ - -Dcom.sun.management.jmxremote.port=7199^ - -Dcom.sun.management.jmxremote.ssl=false^ - -Dcom.sun.management.jmxremote.authenticate=false^ - -Dlogback.configurationFile=logback.xml + -Dlogback.configurationFile=logback.xml^ + -Dcassandra.jmx.local.port=7199 +REM **** JMX REMOTE ACCESS SETTINGS SEE: https://wiki.apache.org/cassandra/JmxSecurity *** +REM -Dcom.sun.management.jmxremote.port=7199^ +REM -Dcom.sun.management.jmxremote.ssl=false^ +REM -Dcom.sun.management.jmxremote.authenticate=true^ +REM -Dcom.sun.management.jmxremote.password.file=C:\jmxremote.password REM ***** CLASSPATH library setting ***** REM Ensure that any user defined CLASSPATH variables are not used on startup diff --git a/build.xml b/build.xml index eaef5340dd..cf401e4067 100644 --- a/build.xml +++ b/build.xml @@ -25,7 +25,7 @@ - + @@ -1113,6 +1113,7 @@ + diff --git a/conf/cassandra-env.ps1 b/conf/cassandra-env.ps1 index 9c6b6f48d5..7a71a137c9 100644 --- a/conf/cassandra-env.ps1 +++ b/conf/cassandra-env.ps1 @@ -400,10 +400,17 @@ Function SetCassandraEnvironment # https://blogs.oracle.com/jmxetc/entry/troubleshooting_connection_problems_in_jconsole # for more on configuring JMX through firewalls, etc. (Short version: # get it working with no firewall first.) - $env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT" - $env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.ssl=false" - $env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=false" + # + # Due to potential security exploits, Cassandra ships with JMX accessible + # *only* from localhost. To enable remote JMX connections, uncomment lines below + # with authentication and ssl enabled. See https://wiki.apache.org/cassandra/JmxSecurity + # + #$env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT" + #$env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.ssl=false" + #$env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=true" #$env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.password.file=C:/jmxremote.password" + $env:JVM_OPTS="$env:JVM_OPTS -Dcassandra.jmx.local.port=$JMX_PORT -XX:+DisableExplicitGC" + $env:JVM_OPTS="$env:JVM_OPTS $JVM_EXTRA_OPTS" $env:JVM_OPTS = "$env:JVM_OPTS -Dlog4j.configuration=log4j-server.properties" diff --git a/conf/cassandra-env.sh b/conf/cassandra-env.sh index 3f4c21b088..58022e6124 100644 --- a/conf/cassandra-env.sh +++ b/conf/cassandra-env.sh @@ -270,6 +270,22 @@ JVM_OPTS="$JVM_OPTS -Djava.net.preferIPv4Stack=true" # https://blogs.oracle.com/jmxetc/entry/troubleshooting_connection_problems_in_jconsole # for more on configuring JMX through firewalls, etc. (Short version: # get it working with no firewall first.) +# +# Cassandra ships with JMX accessible *only* from localhost. +# To enable remote JMX connections, uncomment lines below +# with authentication and/or ssl enabled. See https://wiki.apache.org/cassandra/JmxSecurity +# +LOCAL_JMX=yes + +if [ "$LOCAL_JMX" = "yes" ]; then + JVM_OPTS="$JVM_OPTS -Dcassandra.jmx.local.port=$JMX_PORT -XX:+DisableExplicitGC" +else + JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT" + JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT" + JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.ssl=false" + JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=true" + JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.password.file=/etc/cassandra/jmxremote.password" +fi # To use mx4j, an HTML interface for JMX, add mx4j-tools.jar to the lib/ # directory. @@ -279,11 +295,6 @@ JVM_OPTS="$JVM_OPTS -Djava.net.preferIPv4Stack=true" #MX4J_ADDRESS="-Dmx4jaddress=127.0.0.1" #MX4J_PORT="-Dmx4jport=8081" -JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT" -JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT" -JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.ssl=false" -JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=false" -#JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.password.file=/etc/cassandra/jmxremote.password" JVM_OPTS="$JVM_OPTS $MX4J_ADDRESS" JVM_OPTS="$JVM_OPTS $MX4J_PORT" JVM_OPTS="$JVM_OPTS $JVM_EXTRA_OPTS" diff --git a/debian/changelog b/debian/changelog index 339da0ce6e..807546033a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +cassandra (2.1.4) unstable; urgency=medium + + * New release + + -- Jake Luciani Fri, 27 Mar 2015 13:48:25 -0400 + cassandra (2.1.3) unstable; urgency=medium * New release diff --git a/src/java/org/apache/cassandra/service/CassandraDaemon.java b/src/java/org/apache/cassandra/service/CassandraDaemon.java index 50c8295928..3e398bffa2 100644 --- a/src/java/org/apache/cassandra/service/CassandraDaemon.java +++ b/src/java/org/apache/cassandra/service/CassandraDaemon.java @@ -23,14 +23,16 @@ import java.lang.management.ManagementFactory; import java.lang.management.MemoryPoolMXBean; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.Date; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.TimeUnit; +import java.rmi.registry.LocateRegistry; +import java.rmi.server.RMIServerSocketFactory; +import java.util.*; + import java.util.concurrent.TimeUnit; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.StandardMBean; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.rmi.RMIConnectorServer; import com.google.common.collect.Iterables; import com.google.common.util.concurrent.Uninterruptibles; @@ -66,9 +68,61 @@ import org.apache.cassandra.utils.*; public class CassandraDaemon { public static final String MBEAN_NAME = "org.apache.cassandra.db:type=NativeAccess"; + public static JMXConnectorServer jmxServer = null; private static final Logger logger = LoggerFactory.getLogger(CassandraDaemon.class); + private static void maybeInitJmx() + { + String jmxPort = System.getProperty("com.sun.management.jmxremote.port"); + + if (jmxPort == null) + { + logger.warn("JMX is not enabled to receive remote connections. Please see cassandra-env.sh for more info."); + + jmxPort = System.getProperty("cassandra.jmx.local.port"); + + if (jmxPort == null) + { + logger.error("cassandra.jmx.local.port missing from cassandra-env.sh, unable to start local JMX service." + jmxPort); + } + else + { + System.setProperty("java.rmi.server.hostname","127.0.0.1"); + + try + { + RMIServerSocketFactory serverFactory = new RMIServerSocketFactoryImpl(); + LocateRegistry.createRegistry(Integer.valueOf(jmxPort), null, serverFactory); + + StringBuffer url = new StringBuffer(); + url.append("service:jmx:"); + url.append("rmi://localhost/jndi/"); + url.append("rmi://localhost:").append(jmxPort).append("/jmxrmi"); + + Map env = new HashMap(); + env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, serverFactory); + + jmxServer = new RMIConnectorServer( + new JMXServiceURL(url.toString()), + env, + ManagementFactory.getPlatformMBeanServer() + ); + + jmxServer.start(); + } + catch (IOException e) + { + logger.error("Error starting local jmx server: ", e); + } + } + } + else + { + logger.info("JMX is enabled to receive remote connections on port: " + jmxPort); + } + } + private static final CassandraDaemon instance = new CassandraDaemon(); /** @@ -159,6 +213,8 @@ public class CassandraDaemon CLibrary.tryMlockall(); + maybeInitJmx(); + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable e) @@ -432,6 +488,18 @@ public class CassandraDaemon // We rely on the shutdown hook to drain the node if (FBUtilities.isWindows()) System.exit(0); + + if (jmxServer != null) + { + try + { + jmxServer.stop(); + } + catch (IOException e) + { + logger.error("Error shutting down local JMX server: ", e); + } + } } diff --git a/src/java/org/apache/cassandra/utils/RMIServerSocketFactoryImpl.java b/src/java/org/apache/cassandra/utils/RMIServerSocketFactoryImpl.java new file mode 100644 index 0000000000..75331abd2f --- /dev/null +++ b/src/java/org/apache/cassandra/utils/RMIServerSocketFactoryImpl.java @@ -0,0 +1,34 @@ +package org.apache.cassandra.utils; + +import java.io.IOException; +import java.net.*; +import java.rmi.server.RMIServerSocketFactory; +import javax.net.ServerSocketFactory; + + +public class RMIServerSocketFactoryImpl implements RMIServerSocketFactory +{ + + public ServerSocket createServerSocket(final int pPort) throws IOException { + return ServerSocketFactory.getDefault().createServerSocket(pPort, 0, InetAddress.getLoopbackAddress()); + } + + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (obj == this) + { + return true; + } + + return obj.getClass().equals(getClass()); + } + + public int hashCode() + { + return RMIServerSocketFactoryImpl.class.hashCode(); + } +}