Wednesday January 09, 2008 ![]() |
JMX, SNMP, Java, etc...Daniel Fuchs blogs on JMX, SNMP, Java, etc... |
JMX is a wonderful tool to monitor and troubleshoot running applications. The new JDK 6 Attach API makes it very easy to attach to a running Java process, and start a JMX agent that will expose monitoring and configuration data to JMX consoles - like JConsole. However, there are some situations where you wish to start a JMX agent on demand, explore the monitoring data or diagnose the probable cause of an observed problem, and then close your JMX agent, leaving the application just how you found it. In this post, I will discuss a means by which you can upload and start such a remotely stoppable JMX agent. Here is how. Starting an agent on demandIn some of my previous posts I have outlined how to use a
premain agent in order to create a custom
JMX RMI Connector Server. In this post, we're going to
reuse much of the concepts explained
before.
However, we will add the ability to dynamically
upload the JMX agent in the running application by
creating an
Agent-Main class. In fact, an public static void agentmain(String agentArgs); Our Custom agents started on demand cannot be stopped
The problem with custom agents created on demand is that they
can't be stopped: you can't stop them at the end of the
This behaviour is a much desirable feature in a standalone JMX
application, where you can control when to start and stop
your JMX Connector Server - but it leads to awkward situations
in the case of JMX Agents started from In a previous post I have suggested a work around which consisted
on creating a
In this post, we will show how to:
If needed, the JMX Connector Server can also be re-created and re-started later on. To make things less easy, we will do all of this with a secure firewall-friendly (one single port) RMI Connector Server. Making a Remotely Stoppable JMX Connector Server
Project SourcesThe code source that does all of this comprises the following classes:
You can see the example sources here in the form of a NetBeans 6 project. Building the StoppableAgent jar
Once you have compiled all the classes, you can create an agent
jar by invoking an ant target like this one in your
If you're using the provided NetBeans 6 project simply clean & build
the StoppableAgent project: the agent jar ( Loading and Starting the agent in a Running applicationThe If you don't have a target application to play with, you could use this one: public class Test {
public static void main(String[] args) throws Exception {
System.out.println("Strike Enter to exit:");
System.in.read();
}
}
Compile it and start it as follow:
java -classpath . \
-Djavax.net.ssl.keyStore=<keystore> \
-Djavax.net.ssl.keyStorePassword=<password> \
-Djavax.net.ssl.trustStore=<truststore> \
-Djavax.net.ssl.trustStorePassword=<trustword> \
Test
Note: If you haven't already a keystore and trustore to play with, the Monitoring and Management guide has a section that explains how to create them. To start the stoppable agent in a target application use the following command:
java -Dexample.rmi.agent.port=<port> \
-Dexample.rmi.agent.stopper=<secret-name> \
-cp <agent.jar>:<jdk.home>/tools.jar \
-Djavax.net.ssl.keyStore=<keystore> \
-Djavax.net.ssl.keyStorePassword=<password> \
-Djavax.net.ssl.trustStore=<truststore> \
-Djavax.net.ssl.trustStorePassword=<trustword> \
example.rmi.agent.Attach start <pid>
To check that the StoppableAgent was correctly started run the following command:
java -Dexample.rmi.agent.port=<port> \
-Dexample.rmi.agent.stopper=<secret-name> \
-cp <agent.jar>:<jdk.home>/tools.jar \
-Djavax.net.ssl.keyStore=<keystore> \
-Djavax.net.ssl.keyStorePassword=<password> \
-Djavax.net.ssl.trustStore=<truststore> \
-Djavax.net.ssl.trustStorePassword=<trustword> \
example.rmi.agent.Attach status
Connecting from remoteTo connect with JConsole, start it with the following command line:
jconsole -J-Djavax.net.ssl.keyStore=<keystore> \
-J-Djavax.net.ssl.keyStorePassword=<password> \
-J-Djavax.net.ssl.trustStore=<truststore> \
-J-Djavax.net.ssl.trustStorePassword=<trustword>
Then in the JConsole connection window select Remote Connection and
simply type Stopping the agentTo stop the agent, you now only need to invoke the following command:
java -Dexample.rmi.agent.port=<port> \
-Dexample.rmi.agent.stopper=<secret-name> \
-cp <agent.jar>:<jdk.home>/tools.jar \
-Djavax.net.ssl.keyStore=<keystore> \
-Djavax.net.ssl.keyStorePassword=<password> \
-Djavax.net.ssl.trustStore=<truststore> \
-Djavax.net.ssl.trustStorePassword=<trustword> \
example.rmi.agent.Attach stop
Some additional considerationsThe 'start' command can only be invoked from the local machine where the application is running. This is because we use the Attach API to upload the stoppable agent. However, once done, the agent can be accessed from remote in a secure way. Since 'status' and 'stop' use a regular JMX connection with the stoppable agent, they could also be invoked from a remote machine. Cheers, Posted by dfuchs ( Jan 09 2008, 03:15:39 PM CET ) Permalink Comments [3] |
Your solutions, while innovative, are basically just tricks to get around the horrible application architecture of what is supposedly an enterprise management/monitoring framework. By your own admission the cons are pretty serious:
* It only works with the JMX RMI/JRMP connector. There's no way to do the same thing for the JMX RMI/IIOP connector, for instance.
* It doesn't allow you to stop the connector when you no longer need it. The connector will stay started until the application exits.
Is there any move on Sun's part to create a REAL solution to these challenges? I can't imagine my company is the only one in the world that has a default deny policy on their firewall. My security guys will only give me a port or two, not access to 65,535 ports on the server.
Frustrated by JMX,
ErikC
Posted by ErikC on April 18, 2008 at 02:00 AM CEST #
Hi Erick,
In retrospect, it was certainly a mistake to have the default agent use two port numbers, instead of a single one.
Bear in mind however that having the possibility to start a connector on demand through the attach API is quite an advance feature of the Sun JVM.
All these problems that I cite arise when you try to use this attach on demand feature:
The regular use case for managing an application is to start and stop the JMXConnector server in the main() of your application, where none of these problems arise since you have full control over the connector configuration, and over when to start it and stop it.
Note also that the remotely stoppable connector trick shown above precisely works with all kind of connectors, JRMP, IIOP, or whatever.
What didn't work with the IIOP connector was the CleanThread daemon - which indeed was a horrible trick, but if you use a remotely stoppable connector like above you won't need that trick.
For some time now we've been working on a WebService connector for JMX (this is JSR 262) - and this will certainly help to get through firewall.
I do believe that these issues around the JMX RMI connector and firewalls is something we do need to address in the next version of the API for JDK 7.
I am sorry to hear your frustration. I wrote these articles in the hope it could help quickly getting around firewall issues.
Did you get to try my remotely stoppable JMXConnectorServer above?
Best regards, and let me know if I can help.
-- daniel
Posted by daniel on April 18, 2008 at 09:23 AM CEST #
Thanks for the comment, and I apologize for sounding so harsh. My fellow coworkers pointed out that I sounded overly frustrated...but it was with JMX not you! :-)
See the problem is we're trying to monitor Tomcat via JMX and we'd rather not branch the code base modify the main() for ourselves as to make upgrades easier.
Oh well, we'll keep looking for a compromise that works between SEC & DEV.
Cheers,
ErikC
Posted by ErikC on April 22, 2008 at 12:50 AM CEST #