JMX fixes for agentless configration
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/6bc2410f Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/6bc2410f Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/6bc2410f Branch: refs/heads/master Commit: 6bc2410f592df048085ecbd28ee9920665e0d056 Parents: d2d78e4 Author: Andrew Kennedy <[email protected]> Authored: Thu Aug 28 07:42:55 2014 +0100 Committer: Andrew Kennedy <[email protected]> Committed: Sat Aug 30 17:23:47 2014 +0100 ---------------------------------------------------------------------- .../java/brooklyn/entity/java/JmxSupport.java | 50 +++----- .../main/java/brooklyn/entity/java/UsesJmx.java | 116 +++++++++---------- 2 files changed, 74 insertions(+), 92 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6bc2410f/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java b/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java index 19ee628..4ce9456 100644 --- a/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java +++ b/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java @@ -18,8 +18,6 @@ */ package brooklyn.entity.java; -import static com.google.common.base.Preconditions.checkNotNull; - import java.util.EnumSet; import java.util.List; @@ -32,10 +30,8 @@ import org.slf4j.LoggerFactory; import brooklyn.config.ConfigKey; import brooklyn.config.ConfigKey.HasConfigKey; import brooklyn.entity.Entity; -import brooklyn.entity.basic.Attributes; import brooklyn.entity.basic.EntityInternal; import brooklyn.entity.basic.EntityLocal; -import brooklyn.entity.effector.EffectorTasks; import brooklyn.event.feed.jmx.JmxHelper; import brooklyn.location.access.BrooklynAccessUtils; import brooklyn.location.basic.Locations; @@ -160,24 +156,18 @@ public class JmxSupport implements UsesJmx { public String getJmxUrl() { init(); - - String host = entity.getAttribute(Attributes.HOSTNAME); - if (host==null) { - SshMachineLocation machine = EffectorTasks.getSshMachine(entity); - host = machine.getAddress().getHostName(); - } - + + HostAndPort jmx = BrooklynAccessUtils.getBrooklynAccessibleAddress(entity, entity.getAttribute(JMX_PORT)); + HostAndPort rmi = BrooklynAccessUtils.getBrooklynAccessibleAddress(entity, entity.getAttribute(RMI_REGISTRY_PORT)); + if (EnumSet.of(JmxAgentModes.JMXMP, JmxAgentModes.JMXMP_AND_RMI).contains(getJmxAgentMode())) { - HostAndPort jmxmp = BrooklynAccessUtils.getBrooklynAccessibleAddress(entity, entity.getAttribute(JMX_PORT)); - return JmxHelper.toJmxmpUrl(jmxmp.getHostText(), jmxmp.getPort()); + return JmxHelper.toJmxmpUrl(jmx.getHostText(), jmx.getPort()); } else { if (getJmxAgentMode() == JmxAgentModes.NONE) { fixPortsForModeNone(); } // this will work for agent or agentless - return JmxHelper.toRmiJmxUrl(host, - entity.getAttribute(JMX_PORT), - entity.getAttribute(RMI_REGISTRY_PORT), + return JmxHelper.toRmiJmxUrl(jmx.getHostText(), jmx.getPort(), rmi.getPort(), entity.getAttribute(JMX_CONTEXT)); } } @@ -269,18 +259,18 @@ public class JmxSupport implements UsesJmx { /** applies _some_ of the common settings needed to connect via JMX */ public void applyJmxJavaSystemProperties(MutableMap.Builder<String,Object> result) { if (!isJmx()) return ; - - Integer jmxRemotePort; - String hostName = getEntity().getAttribute(Attributes.HOSTNAME); - if (hostName==null) hostName = checkNotNull(getMachine().get().getAddress().getHostName(), "hostname for entity " + entity); - + + HostAndPort jmx = BrooklynAccessUtils.getBrooklynAccessibleAddress(entity, entity.getAttribute(JMX_PORT)); + Integer jmxRemotePort = getEntity().getAttribute(JMX_PORT); + String hostName = jmx.getHostText(); + result.put("com.sun.management.jmxremote", null); + result.put("java.rmi.server.hostname", hostName); switch (getJmxAgentMode()) { case JMXMP_AND_RMI: result.put(JmxmpAgent.RMI_REGISTRY_PORT_PROPERTY, Preconditions.checkNotNull(entity.getAttribute(UsesJmx.RMI_REGISTRY_PORT), "registry port")); case JMXMP: - jmxRemotePort = getEntity().getAttribute(JMX_PORT); if (jmxRemotePort==null || jmxRemotePort<=0) throw new IllegalStateException("Unsupported JMX port "+jmxRemotePort+" - when applying system properties ("+getJmxAgentMode()+" / "+getEntity()+")"); result.put(JmxmpAgent.JMXMP_PORT_PROPERTY, jmxRemotePort); @@ -289,25 +279,21 @@ public class JmxSupport implements UsesJmx { // (should not be present, but remove just to be sure) result.remove("java.rmi.server.hostname"); break; - case JMX_RMI_CUSTOM_AGENT: - jmxRemotePort = getEntity().getAttribute(JMX_PORT); + case JMX_RMI_CUSTOM_AGENT: if (jmxRemotePort==null || jmxRemotePort<=0) throw new IllegalStateException("Unsupported JMX port "+jmxRemotePort+" - when applying system properties ("+getJmxAgentMode()+" / "+getEntity()+")"); - result.put(JmxRmiAgent.RMI_REGISTRY_PORT_PROPERTY, - Preconditions.checkNotNull(entity.getAttribute(UsesJmx.RMI_REGISTRY_PORT), "registry port")); + result.put(JmxRmiAgent.RMI_REGISTRY_PORT_PROPERTY, Preconditions.checkNotNull(entity.getAttribute(UsesJmx.RMI_REGISTRY_PORT), "registry port")); result.put(JmxRmiAgent.JMX_SERVER_PORT_PROPERTY, jmxRemotePort); - result.put("java.rmi.server.hostname", hostName); break; case NONE: - // only for mode 'NONE' - other modes use different fields jmxRemotePort = fixPortsForModeNone(); + case JMX_RMI: result.put("com.sun.management.jmxremote.port", jmxRemotePort); - result.put("java.rmi.server.hostname", hostName); break; - default: + default: throw new IllegalStateException("Unsupported JMX mode - when applying system properties ("+getJmxAgentMode()+" / "+getEntity()+")"); } - + if (isSecure()) { // set values true, and apply keys pointing to keystore / truststore getJmxSslSupport().applyAgentJmxJavaSystemProperties(result); @@ -320,7 +306,7 @@ public class JmxSupport implements UsesJmx { /** installs files needed for JMX, to the runDir given in constructor, assuming the runDir has been created */ public void install() { - if (getJmxAgentMode()!=JmxAgentModes.NONE) { + if (EnumSet.of(JmxAgentModes.JMXMP_AND_RMI, JmxAgentModes.JMXMP, JmxAgentModes.JMX_RMI_CUSTOM_AGENT).contains(getJmxAgentMode())) { getMachine().get().copyTo(ResourceUtils.create(this).getResourceFromUrl( getJmxAgentJarUrl()), getJmxAgentJarDestinationFilePath()); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6bc2410f/software/base/src/main/java/brooklyn/entity/java/UsesJmx.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/java/UsesJmx.java b/software/base/src/main/java/brooklyn/entity/java/UsesJmx.java index 8166d0c..ff8164a 100644 --- a/software/base/src/main/java/brooklyn/entity/java/UsesJmx.java +++ b/software/base/src/main/java/brooklyn/entity/java/UsesJmx.java @@ -25,6 +25,7 @@ import brooklyn.config.ConfigKey; import brooklyn.entity.Entity; import brooklyn.entity.basic.ConfigKeys; import brooklyn.event.AttributeSensor; +import brooklyn.event.basic.AttributeSensorAndConfigKey; import brooklyn.event.basic.BasicAttributeSensorAndConfigKey; import brooklyn.event.basic.BasicConfigKey; import brooklyn.event.basic.PortAttributeSensorAndConfigKey; @@ -34,14 +35,14 @@ import brooklyn.util.flags.SetFromFlag; public interface UsesJmx extends UsesJava { - public static final int DEFAULT_JMX_PORT = 1099; // RMI port? + public static final int DEFAULT_JMX_PORT = 1099; // RMI port? @SetFromFlag("useJmx") - public static final ConfigKey<Boolean> USE_JMX = ConfigKeys.newConfigKey("jmx.enabled", "JMX enabled", Boolean.TRUE); + ConfigKey<Boolean> USE_JMX = ConfigKeys.newConfigKey("jmx.enabled", "JMX enabled", Boolean.TRUE); - /** chosen by java itself by default; setting this will only have any effect if using an agent */ + /** Chosen by Java itself by default, setting this will only have any effect if using an agent. */ @SetFromFlag("jmxPort") - public static final PortAttributeSensorAndConfigKey JMX_PORT = new PortAttributeSensorAndConfigKey( + PortAttributeSensorAndConfigKey JMX_PORT = new PortAttributeSensorAndConfigKey( "jmx.direct.port", "JMX direct/private port (e.g. JMX RMI server port, or JMXMP port, but not RMI registry port)", PortRanges.fromString("31001+")) { @Override protected Integer convertConfigToSensor(PortRange value, Entity entity) { // TODO when using JmxAgentModes.NONE we should *not* convert, but leave it null @@ -52,64 +53,59 @@ public interface UsesJmx extends UsesJava { return super.convertConfigToSensor(value, entity); } }; - - /** well-known port used by Java itself to start the RMI registry where JMX private port can be discovered; - * ignored if using JMXMP agent - */ + + /** Well-known port used by Java itself to start the RMI registry where JMX private port can be discovered, ignored if using JMXMP agent. */ @SetFromFlag("rmiRegistryPort") - public static final PortAttributeSensorAndConfigKey RMI_REGISTRY_PORT = new PortAttributeSensorAndConfigKey( - "rmi.registry.port", "RMI registry port, used for discovering JMX (private) port", PortRanges.fromString("1099, 19099+")); + PortAttributeSensorAndConfigKey RMI_REGISTRY_PORT = ConfigKeys.newPortSensorAndConfigKey( + "rmi.registry.port", "RMI registry port, used for discovering JMX (private) port", PortRanges.fromString("1099,19099+")); @SetFromFlag("jmxContext") - public static final BasicAttributeSensorAndConfigKey<String> JMX_CONTEXT = new BasicAttributeSensorAndConfigKey<String>( - String.class, "jmx.context", "JMX context path", "jmxrmi"); + AttributeSensorAndConfigKey<String, String> JMX_CONTEXT = ConfigKeys.newStringSensorAndConfigKey("jmx.context", "JMX context path", "jmxrmi"); - public static final AttributeSensor<String> JMX_URL = new BasicAttributeSensorAndConfigKey<String>( + AttributeSensor<String> JMX_URL = new BasicAttributeSensorAndConfigKey<String>( String.class, "jmx.service.url", "The URL for connecting to the MBean Server"); - /** forces JMX to be secured, using JMXMP so it gets through firewalls _and_ SSL/TLS - * (NB: there is not currently any corresponding JMXMP without SSL/TLS) */ + /** Forces JMX to be secured, using JMXMP so it gets through firewalls <em>and</em> SSL/TLS. */ @SetFromFlag("jmxSecure") - public static final ConfigKey<Boolean> JMX_SSL_ENABLED = ConfigKeys.newBooleanConfigKey("jmx.ssl.enabled", "JMX over JMXMP enabled with SSL/TLS", Boolean.FALSE); + ConfigKey<Boolean> JMX_SSL_ENABLED = ConfigKeys.newBooleanConfigKey("jmx.ssl.enabled", "JMX over JMXMP enabled with SSL/TLS", Boolean.FALSE); - public enum JmxAgentModes { - /** auto-detect the agent to use based on location, preferring JMXMP except at localhost where JMX_RMI_CUSTOM_AGENT is preferred */ + enum JmxAgentModes { + /** Auto-detect the agent to use based on location. Prefer {@link #JMXMP} except at localhost which uses {@link #JMX_RMI_CUSTOM_AGENT}. */ AUTODETECT, - /** JMXMP which permits firewall access through a single port {@link UsesJmx#JMX_PORT} */ + + /** JMXMP which permits firewall access through a single port {@link UsesJmx#JMX_PORT}. */ JMXMP, - /** Start {@link #JMXMP} along with an RMI Registry on {@link UsesJmx#RMI_REGISTRY_PORT} - * (redirecting to an anonymous high-numbered port as the RMI server) */ + + /** Start {@link #JMXMP} along with an RMI Registry on {@link UsesJmx#RMI_REGISTRY_PORT}, redirecting to an anonymous high-numbered port as the RMI server. */ JMXMP_AND_RMI, - /** JMX over RMI custom agent which permits access through a known RMI registry port, redirected to a known JMX-RMI port; - * two ports must be opened on the firewall, and the same hostname resolvable on the target machine and by the client */ + + /** JMX over RMI custom agent which permits access through a known {@link UsesJmx#RMI_REGISTRY_PORT}, redirected to a known {@link UsesJmx#JMX_PORT}. + * Both ports must be opened on the firewall, and the same hostname resolvable on the target machine and by the client */ JMX_RMI_CUSTOM_AGENT, - /** do not install a JMX agent; use the default RMI which opens a registry at a known port, redirected to an _unknown_ port for jmx - * (experimental) */ + + /** As with {@link UsesJmx#JMX_RMI_CUSTOM_AGENT} but no custom agent requred, entity must handle pots correctly. */ + JMX_RMI, + + /** Do not install a JMX agent. Use the default {@link UsesJmx#RMI_REGISTRY_PORT}, redirected to an unknown port for JMX. */ NONE } - + @SetFromFlag("jmxAgentMode") - public static final ConfigKey<JmxAgentModes> JMX_AGENT_MODE = ConfigKeys.newConfigKey(JmxAgentModes.class, - "jmx.agent.mode", "What type of JMX agent to use; defaults to null (autodetect) which means " + - "JMXMP_AND_RMI allowing firewall access through a single port as well as local access supporting jconsole " + - "(unless JMX_SSL_ENABLED is set, in which case it is JMXMP only)", - JmxAgentModes.AUTODETECT); + ConfigKey<JmxAgentModes> JMX_AGENT_MODE = ConfigKeys.newConfigKey("jmx.agent.mode", + "What type of JMX agent to use; defaults to null (autodetect) which means " + + "JMXMP_AND_RMI allowing firewall access through a single port as well as local access supporting jconsole " + + "(unless JMX_SSL_ENABLED is set, in which case it is JMXMP only)", + JmxAgentModes.AUTODETECT); + + /* Currently these are only used to connect, so only applies where systems set this up themselves. */ + AttributeSensorAndConfigKey<String, String> JMX_USER = ConfigKeys.newStringSensorAndConfigKey("jmx.user", "JMX username"); + AttributeSensorAndConfigKey<String, String> JMX_PASSWORD = ConfigKeys.newStringSensorAndConfigKey("jmx.password", "JMX password"); - /** Currently only used to connect; not used to set up JMX (so only applies where systems set this up themselves) - */ - public static final BasicAttributeSensorAndConfigKey<String> JMX_USER = new BasicAttributeSensorAndConfigKey<String>( - String.class, "jmx.user", "JMX username"); - - /** Currently only used to connect; not used to set up JMX (so only applies where systems set this up themselves) - */ - public static final BasicAttributeSensorAndConfigKey<String> JMX_PASSWORD = new BasicAttributeSensorAndConfigKey<String>( - String.class, "jmx.password", "JMX password"); - /* * Synopsis of how the keys work for JMX_SSL: - * + * * BROOKLYN - * * brooklyn ROOT key + cert -> + * * brooklyn ROOT key + cert -> * used to identify things brooklyn has signed, ie to confirm their identity * signs all certs created by brooklyn * (created per entity if not specified as input) @@ -120,7 +116,7 @@ public interface UsesJmx extends UsesJava { * global would probably be fine but more work; * however it is important that this _not_ sign agents keys, * to prevent agents from accessing other agents) - * + * * AGENT (e.g. JMX server in each managed java process) * * gets AGENT key + cert -> * signed by brooklyn ROOT, used to authenticate itself to brooklyn @@ -129,57 +125,57 @@ public interface UsesJmx extends UsesJava { */ /* TODO brooklyn ROOT key - * + * public static final ConfigKey<String> BROOKLYN_SSL_ROOT_KEYSTORE_URL = new BasicConfigKey<String>( String.class, "brooklyn.ssl.root.keyStoreUrl", "URL to keystore Brooklyn should use as root private key and certificate-signing authority", null); - + public static final ConfigKey<String> BROOKLYN_SSL_ROOT_KEY_DATA = new BasicConfigKey<String>( String.class, "brooklyn.ssl.root.key", "root private key (RSA string format), used to sign managed servers", null); public static final ConfigKey<String> BROOKLYN_SSL_ROOT_CERT_DATA = new BasicConfigKey<String>( String.class, "brooklyn.ssl.root.cert", "certificate for root private key (RSA string format)", null); - + * brooklyn.ssl.root.keyStorePassword * brooklyn.ssl.root.keyAlias (if null, looks for one called 'brooklyn', otherwise takes the first key) * brooklyn.ssl.root.keyPassword - */ - + */ + public static final ConfigKey<PrivateKey> JMX_SSL_ACCESS_KEY = new BasicConfigKey<PrivateKey>( PrivateKey.class, "jmx.ssl.access.key", "key used to access a JMX agent (typically per entity, embedded in the managed JVM)", null); public static final ConfigKey<Certificate> JMX_SSL_ACCESS_CERT = new BasicConfigKey<Certificate>( Certificate.class, "jmx.ssl.access.cert", "certificate of key used to access a JMX agent", null); - + /* TODO specify a keystore from which to get the access key * (above keys are set programmatically, typically _not_ by the user ... keystore would be the way to do that) - * + * * jmx.ssl.access.keyStoreUrl (optional) * jmx.ssl.access.keyStorePassword (optional) * jmx.ssl.access.keyAlias (optional) */ - + /* could allow user to specify additional certs for JMX agents which should be trusted - * + * * jmx.ssl.access.trustStoreUrl */ - - /* optionally: could allow JMX agent to trust additional accessers, + + /* optionally: could allow JMX agent to trust additional accessers, * and/or use known keys in the case that other accessers might want to authenticate the JMX server - * - * NB currently agent keys are not stored in brooklyn... no reason to as + * + * NB currently agent keys are not stored in brooklyn... no reason to as * (a) currently we trust jmx agents; and (b) for agent-auth we should simply sign keys; * either way, seems fine for brooklyn to throw them away once they are installed on the remote machine) - * + * * jmx.ssl.agent.keyStoreUrl * jmx.ssl.agent.keyStorePassword * jmx.ssl.agent.keyAlias * jmx.ssl.agent.keyPassword - * + * * jmx.ssl.agent.trustStoreUrl */ /* optionally: this could be set to disallow attaching to JMX through the attach mechanism * (but this option is generally not considered needed, as JVM attachment is * already restricted to localhost and to the the user running the process) - * + * * -XX:+DisableAttachMechanism */ } \ No newline at end of file
