modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/DetectionMechanism.java | 18 + modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/LsofComponent.java | 95 +++++++--- modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/LsofDiscoveryComponent.java | 79 ++++++++ modules/plugins/lsof/src/main/resources/META-INF/rhq-plugin.xml | 55 +++-- 4 files changed, 197 insertions(+), 50 deletions(-)
New commits: commit 1dfd6c55d8f929bc57a7cfb6f57c95e6c103b6ee Author: John Mazzitelli mazz@redhat.com Date: Tue Dec 29 15:51:19 2009 -0500
build out the lsof plugin some more - add the ability to use either lsof external app or internal sigar API
diff --git a/modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/DetectionMechanism.java b/modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/DetectionMechanism.java new file mode 100644 index 0000000..56e7648 --- /dev/null +++ b/modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/DetectionMechanism.java @@ -0,0 +1,18 @@ +package org.rhq.plugins.lsof; + +/** + * Indicator of the detection mechanism to use to detect network resources. + * + * @author John Mazzitelli + */ +public enum DetectionMechanism { + /** + * Use an external executable (such as 'lsof') to detect network resources. + */ + EXTERNAL, + + /** + * Use a Java-based mechanism that is internal to this plugin. + */ + INTERNAL +} diff --git a/modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/LsofComponent.java b/modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/LsofComponent.java index 919ced8..7080264 100644 --- a/modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/LsofComponent.java +++ b/modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/LsofComponent.java @@ -18,17 +18,20 @@ */ package org.rhq.plugins.lsof;
+import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern;
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.hyperic.sigar.NetConnection;
import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.PropertyList; import org.rhq.core.domain.configuration.PropertyMap; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.pluginapi.operation.OperationResult; +import org.rhq.core.util.exception.ThrowableUtil; import org.rhq.plugins.script.ScriptServerComponent;
/** @@ -39,46 +42,84 @@ import org.rhq.plugins.script.ScriptServerComponent; public class LsofComponent extends ScriptServerComponent { private final Log log = LogFactory.getLog(LsofComponent.class);
+ protected static final String VERSION = "1.0"; // our plugin version, used when this resource is told to use its internal mechanism + protected static final String PLUGINCONFIG_DETECTION_MECHANISM = "detectionMechanism"; // also used for operation results + protected static final String PLUGINCONFIG_EXECUTABLE = ScriptServerComponent.PLUGINCONFIG_EXECUTABLE; + @Override public OperationResult invokeOperation(String name, Configuration params) throws Exception { OperationResult result;
if ("getNetworkConnections".equals(name)) { - // compile the regex that will be used to parse the output - String regex = params.getSimpleValue("regex", ""); - if (regex.length() == 0) { - throw new Exception("missing regex parameter"); - } - Pattern pattern = Pattern.compile(regex); + Configuration pluginConfiguration = getResourcContext().getPluginConfiguration(); + DetectionMechanism mechanism = LsofDiscoveryComponent.getDetectionMechanism(pluginConfiguration); + + if (mechanism == DetectionMechanism.EXTERNAL) { + log.info("Getting network connections using the external mechanism"); + + // compile the regex that will be used to parse the output + String regex = params.getSimpleValue("regex", ""); + if (regex.length() == 0) { + throw new Exception("missing regex parameter"); + } + Pattern pattern = Pattern.compile(regex);
- // first run the executable - OperationResult intermediaryResult = super.invokeOperation(name, params); - Configuration intermediaryConfig = intermediaryResult.getComplexResults(); + // first run the executable + OperationResult intermediaryResult = super.invokeOperation(name, params); + Configuration intermediaryConfig = intermediaryResult.getComplexResults();
- // now build our results object - result = new OperationResult(); - Configuration config = result.getComplexResults(); - config.put(intermediaryConfig.getSimple(OPERATION_RESULT_EXITCODE)); - if (intermediaryResult.getErrorMessage() != null) { - result.setErrorMessage(intermediaryResult.getErrorMessage()); + // now build our results object + result = new OperationResult(); + Configuration config = result.getComplexResults(); + config.put(new PropertySimple("detectionMechanism", mechanism.toString())); + config.put(intermediaryConfig.getSimple(OPERATION_RESULT_EXITCODE)); + if (intermediaryResult.getErrorMessage() != null) { + result.setErrorMessage(intermediaryResult.getErrorMessage()); + } else { + String output = intermediaryConfig.getSimpleValue(OPERATION_RESULT_OUTPUT, ""); + if (output.length() > 0) { + PropertyList list = new PropertyList("networkConnections"); + config.put(list); + + String[] lines = output.split("\n"); + for (String line : lines) { + Matcher matcher = pattern.matcher(line); + if (matcher.matches()) { + PropertyMap map = new PropertyMap("networkConnection"); + list.add(map); + map.put(new PropertySimple("localHost", matcher.group(1))); + map.put(new PropertySimple("localPort", matcher.group(2))); + map.put(new PropertySimple("remoteHost", matcher.group(3))); + map.put(new PropertySimple("remotePort", matcher.group(4))); + } + } + } + } } else { - String output = intermediaryConfig.getSimpleValue(OPERATION_RESULT_OUTPUT, ""); - if (output.length() > 0) { - PropertyList list = new PropertyList("networkConnections"); - config.put(list); + log.info("Getting network connections using the internal mechanism"); + result = new OperationResult(); + Configuration config = result.getComplexResults(); + config.put(new PropertySimple("detectionMechanism", mechanism.toString()));
- String[] lines = output.split("\n"); - for (String line : lines) { - Matcher matcher = pattern.matcher(line); - if (matcher.matches()) { + try { + List<NetConnection> conns; + conns = getResourcContext().getSystemInformation().getNetworkConnections(null, 0); + config.put(new PropertySimple(OPERATION_RESULT_EXITCODE, "0")); + if (conns.size() > 0) { + PropertyList list = new PropertyList("networkConnections"); + config.put(list); + for (NetConnection conn : conns) { PropertyMap map = new PropertyMap("networkConnection"); list.add(map); - map.put(new PropertySimple("host", matcher.group(1))); - map.put(new PropertySimple("port", matcher.group(2))); - map.put(new PropertySimple("remoteHost", matcher.group(3))); - map.put(new PropertySimple("remotePort", matcher.group(4))); + map.put(new PropertySimple("localHost", conn.getLocalAddress())); + map.put(new PropertySimple("localPort", conn.getLocalPort())); + map.put(new PropertySimple("remoteHost", conn.getRemoteAddress())); + map.put(new PropertySimple("remotePort", conn.getRemotePort())); } } + } catch (Exception e) { + config.put(new PropertySimple(OPERATION_RESULT_EXITCODE, "1")); + result.setErrorMessage(ThrowableUtil.getAllMessages(e)); } } } else { diff --git a/modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/LsofDiscoveryComponent.java b/modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/LsofDiscoveryComponent.java index 0a4f2ed..a5bfe31 100644 --- a/modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/LsofDiscoveryComponent.java +++ b/modules/plugins/lsof/src/main/java/org/rhq/plugins/lsof/LsofDiscoveryComponent.java @@ -18,6 +18,17 @@ */ package org.rhq.plugins.lsof;
+import java.io.File; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.configuration.PropertySimple; +import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails; +import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext; +import org.rhq.core.system.SystemInfoFactory; import org.rhq.plugins.script.ScriptDiscoveryComponent;
/** @@ -26,4 +37,72 @@ import org.rhq.plugins.script.ScriptDiscoveryComponent; * @author John Mazzitelli */ public class LsofDiscoveryComponent extends ScriptDiscoveryComponent { + private final Log log = LogFactory.getLog(LsofDiscoveryComponent.class); + + private static final String DEFAULT_NAME = "Network Resource Detector"; + private static final String DEFAULT_DESCRIPTION = "A resource that is used to detect network resources."; + + @Override + public DiscoveredResourceDetails discoverResource(Configuration pluginConfig, + ResourceDiscoveryContext discoveryContext) throws InvalidPluginConfigurationException { + + DiscoveredResourceDetails details; + + DetectionMechanism detectionMechanism = getDetectionMechanism(pluginConfig); + log.debug("resource will have detection mechanism of [" + detectionMechanism + "]"); + + switch (detectionMechanism) { + case INTERNAL: + if (!SystemInfoFactory.isNativeSystemInfoAvailable()) { + throw new InvalidPluginConfigurationException( + "The native system is not available - cannot use the internal detection mechanism"); + } + if (SystemInfoFactory.isNativeSystemInfoDisabled()) { + throw new InvalidPluginConfigurationException( + "The native system is disabled - cannot use the internal detection mechanism"); + } + String version = LsofComponent.VERSION; + details = new DiscoveredResourceDetails(discoveryContext.getResourceType(), "*lsof-internal*", + DEFAULT_NAME, version, DEFAULT_DESCRIPTION, pluginConfig, null); + break; + case EXTERNAL: + // do all that we can to make sure we have a valid full path to the executable + PropertySimple executable = pluginConfig.getSimple(LsofComponent.PLUGINCONFIG_EXECUTABLE); + executable.setStringValue(findExecutable(executable.getStringValue())); + + details = super.discoverResource(pluginConfig, discoveryContext); + details.setResourceName(DEFAULT_NAME); + break; + default: + throw new InvalidPluginConfigurationException("Unknown detection mechanism: " + detectionMechanism); + } + + return details; + } + + private String findExecutable(String executable) { + File findIt = new File(executable); + if (!findIt.isAbsolute()) { + // the typical locations where lsof can usually be found + String[] possibleLocations = { "/usr/bin", "/usr/sbin", "/bin", "/sbin", "/usr/local/bin" }; + for (String possibleLocation : possibleLocations) { + findIt = new File(possibleLocation, executable); + if (findIt.exists()) { + executable = findIt.getAbsolutePath(); + break; + } + } + } + return executable; + } + + @Override + protected String determineDescription(ResourceDiscoveryContext context, Configuration pluginConfig) { + return DEFAULT_DESCRIPTION; // we don't use the discovery tool to get us a description - we hard code one + } + + public static DetectionMechanism getDetectionMechanism(Configuration pluginConfig) { + String mechanism = pluginConfig.getSimpleValue(LsofComponent.PLUGINCONFIG_DETECTION_MECHANISM, "external"); + return DetectionMechanism.valueOf(mechanism); + } } \ No newline at end of file diff --git a/modules/plugins/lsof/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/lsof/src/main/resources/META-INF/rhq-plugin.xml index e1e385c..a280d27 100644 --- a/modules/plugins/lsof/src/main/resources/META-INF/rhq-plugin.xml +++ b/modules/plugins/lsof/src/main/resources/META-INF/rhq-plugin.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?>
<plugin name="lsof" - displayName="LSOF Network Resource Detector" + displayName="Network Resource Detector" description="Detects resources out in the network using lsof technology" package="org.rhq.plugins.lsof" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" @@ -10,57 +10,66 @@
<depends plugin="Script" useClasses="true" />
- <server name="LSOF Utility" + <server name="Network Resource Detector" discovery="LsofDiscoveryComponent" class="LsofComponent" - description="The lsof tool to be used to detect network resources" + description="A resource that is used to detect network resources." supportsManualAdd="true">
<plugin-configuration> - <c:group name="executableEnvironment" displayName="Executable Runtime Environment"> - <c:simple-property name="executable" required="true" default="lsof" description="The full path to the command line executable or script" /> - <c:simple-property name="workingDirectory" required="false" description="When the executable is invoked, this will be its working directory." /> - <c:list-property name="environmentVariables" required="false" description="Environment variables that are set when executing the executable"> + <c:simple-property name="detectionMechanism" required="true" defaultValue="EXTERNAL" description="Determines how to perform network resource detection. 'external' means that an external executable tool (e.g. lsof) will be used; 'internal' means internal Java detection code provided by the RHQ plugin will be used."> + <c:property-options> + <c:option value="EXTERNAL" default="true" /> + <c:option value="INTERNAL" /> + </c:property-options> + </c:simple-property> + <c:group name="executableEnvironment" displayName="External - Executable Runtime Environment"> + <c:simple-property name="executable" required="false" default="lsof" description="The full path to the external executable to be used. If not defined, you must select 'internal' for the detection mechanism. This is ignored if using the 'internal' detection mechanism." /> + <c:simple-property name="workingDirectory" required="false" description="When the external executable is invoked, this will be its working directory. This is ignored if using the 'internal' detection mechanism." /> + <c:list-property name="environmentVariables" required="false" description="Environment variables that are set when executing the executable. This is ignored if using the 'internal' detection mechanism."> <c:map-property name="environmentVariable"> <c:simple-property name="name" type="string" required="true" summary="true" description="Name of the environment variable"/> <c:simple-property name="value" type="string" required="true" summary="true" description="Value of the environment variable" /> </c:map-property> </c:list-property> </c:group> - <c:group name="version" displayName="Version Definition"> - <c:simple-property name="versionArguments" required="false" default="-v" description="The arguments to pass to the executable that will help determine the version of the managed resource"/> - <c:simple-property name="versionRegex" required="false" default=".*evision:[ \t]+(\d+.\d+).*" description="The regex that can pick out the version from the executable output. If the regex has a captured group, its matched content will be used as the version. If there is no captured group, the entire output will be used as the version."/> - </c:group> - <c:group name="description" displayName="Description Definition"> - <c:simple-property name="descriptionArguments" required="false" default="-h" description="The arguments to pass to the executable that will help determine the managed resource description. This can be arguments to enable verbose version output."/> + <c:group name="version" displayName="External - Version Definition"> + <c:simple-property name="versionArguments" required="false" default="-v" description="The arguments to pass to the executable that will help determine the version of the external tool. This is ignored if using the 'internal' detection mechanism."/> + <c:simple-property name="versionRegex" required="false" default=".*evision:[ \t]+(\d+.\d+).*" description="The regex that can pick out the version from the executable output. If the regex has a captured group, its matched content will be used as the version. If there is no captured group, the entire output will be used as the version. This is ignored if using the 'internal' detection mechanism."/> </c:group> </plugin-configuration>
<operation name="execute" - description="Executes the executable with a set of arguments and returns the output and exit code."> + description="Executes the external detection executable with a set of arguments and returns the output and exit code. This is only useful when configured to use the external detection mechanism. If this resource is not configured to use the external mechanism, invoking this operation will fail."> <parameters> <c:simple-property name="arguments" required="false" default="-i -P" description="The arguments to pass to the executable." /> </parameters> <results> <c:simple-property name="exitCode" type="integer" required="true"/> - <c:simple-property name="output" required="false" /> + <c:simple-property name="output" type="longString" required="false" /> </results> </operation>
<operation name="getNetworkConnections" description="Determines the network connections currently established on the machine"> <parameters> - <c:simple-property name="arguments" required="true" default="-i -P" description="The arguments to pass to the executable." /> - <c:simple-property name="regex" required="true" default=".*TCP\s+(.+):(.+)->(.+):(.+)\s+.*" description="Must have groups that match the output fields" /> + <c:simple-property name="arguments" required="false" default="-i -P" description="The arguments to pass to the executable. This parameter will be ignored if using the 'internal' detection mechanism." /> + <c:simple-property name="regex" required="false" default=".*TCP\s+(.+):(.+)->(.+):(.+)\s+.*" description="Regular expression used to parse each line of the output of the external executable. This regex must have capture groups that match the output fields as defined in the results metadata. This parameter will be ignored if using the 'internal' detection mechanism." /> </parameters> <results> + <c:simple-property name="detectionMechanism" required="true" description="Describes the mechanism that was used to peform the detection."> + <c:property-options> + <c:option value="EXTERNAL" /> + <c:option value="INTERNAL" /> + </c:property-options> + </c:simple-property> <c:simple-property name="exitCode" type="integer" required="true"/> - <c:list-property name="networkConnections"> - <c:map-property name="networkConnection"> - <c:simple-property name="host" type="string" /> - <c:simple-property name="port" type="string" /> - <c:simple-property name="remoteHost" type="string" /> - <c:simple-property name="remotePort" type="string" /> + <c:list-property name="networkConnections" description="The active network connections that were detected"> + <c:map-property name="networkConnection" description="An active network connection that was detected"> + <c:simple-property name="localHost" type="string" default="The address of the local side of the connection"/> + <c:simple-property name="localPort" type="string" default="The port of the local side of the connection "/> + <c:simple-property name="remoteHost" type="string" default="The address of the remote side of the connection"/> + <c:simple-property name="remotePort" type="string" default="The port of the remote side of the connection"/> </c:map-property> </c:list-property> </results>
rhq-commits@lists.fedorahosted.org