Creating a Detector

From OpenNMS
Jump to: navigation, search

Creating a detector for a new management protocol or data acquisition method can be a fun exercise!

Overview

I've created a Detector for a new network management protocol (XMP) I'm developing. XMP is a connection-oriented management protocol that uses XML for data definition and transfer over a TCP connection encapsulated within SSL. It uses a relatively simple data model based on that used by the Internet Management Framework (SNMP).

Detectors are used by Provisiond to test and probe for particular protocols and services.


Files

  • detectors.xml This XML config file is placed in the following directory in your source hierarchy and is used by the Spring framework and java reflection to properly load and call methods in your Detector. The following detectors.xml file can be cut/paste to your detectors.xml file. Just change the name of the detector in the base-package.

/path/to/source/protocols/xmp/src/main/resources/META-INF/opennms/detectors.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx" 
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-2.5.xsd">

  <context:component-scan
      base-package="org.opennms.protocols.xmp.detector" 
      name-generator="org.opennms.netmgt.provision.support.DetectorBeanNameGenerator"/>
</beans>
  • XmpDetector.java The detector Java code itself. My detector consists of a single Java class file implementing the SyncServiceDetector interface located in the provisiond API code hierarchy.

/path/to/source/protocols/xmp/src/main/java/org/opennms/netmgt/protocols/xmp/XmpDetector.java

package org.opennms.protocols.xmp.detector;

@Component
/**
 * XmpDetector class
 * @author rdk <rdk@krupczak.org>
 * @version $Id: $
 *
 */
@Scope("prototype")
public class XmpDetector implements SyncServiceDetector
{

}
  • default-foreign-source.xml This file is used for testing only. There is no need to hand-create this file and place in the OpenNMS install etc directory anymore. Once your detector is coded and installed, go through the ONMS Web UI to add the detector into operation. If you place this file in ONMS install etc, ONMS will read it and substitute this configuration for the builtin default-foreign-source.xml file and it will disable all the other detectors.

/path/to/source/protocols/xmp/src/test/resources/default-foreign-source.xml

<foreign-source name="default" xmlns="http://xmlns.opennms.org/xsd/config/foreign-source">
<scan-interval>1d</scan-interval>
<detectors>
  <detector name="XMP" class="org.opennms.protocols.xmp.detector.XmpDetector" />
</detectors>
</foreign-source>

Detector Code

I created a simple synchronous protocol detector using a Xmp protocol jar I had previously submitted to the ONMS. If you have a simple TCP based protocol, you could use the TCP detector and configure the port for it. That detector would do a simple TCP connection test to the specified port and if connection is established, the protocol is assumed to be supported.

I wanted to write a detector that went a little deeper when detecting since my protocol runs over SSL.

I chose to implement the SyncServiceDetector interface. Here is the skeleton class.

package org.opennms.protocols.xmp.detector;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
/**
 * XmpDetector class
 * @author rdk <rdk@krupczak.org>
 * @version $Id: $
 *
 */
@Scope("prototype")
public class XmpDetector implements SyncServiceDetector
{

    public XmpDetector(String serviceName, int port) { }

    public void init() { onInit(); }

    public void onInit()

    public int getPort()
    
    public void setPort(int newPort)

    public void setIpMatch(String ipMatch)

    public String getIpMatch()

    public int getTimeout()

    public void setTimeout(int newTimeout) 

    public void dispose()

    public final boolean isServiceDetected(InetAddress address)

}
  • XmpDetector Name of class that implements the detector. This class name and package name are used in the default-foreign-source XML file and in the entry. Obviously, everything needs to match exactly. My detector is simply implementing the SyncServiceDetector interface plus it implements the isServiceDetected() method. For a variety of software engineering reasons, isServiceDetected() is not defined in the base interface. Include the specified Spring packages (others are omitted for brevity's sake) and make sure to add the annotations for Component and Scope so that the Bean glue will work.
  • Constructor creates the class by allocating/creating and setting instance variables. I use the constructor to allocate XMP socket options and configuration information. I also set my service name to 'XMP'. Be sure to set your m_ipMatch string to NULL rather than empty string.
  • getServiceName() and setServiceName() Get and set the service name for this detector. In my case, mostly unused.
  • getPort() and setPort() Get and set the protocol port number used by this server. In my case, mostly unused since my detector uses my default protocol port as assigned by IANA.
  • getIpMatch() and setIpMatch() Get and set the ipMatch instance variable possibly used for narrowing down which addresses are scanned by this detector. Since I'm detecting for all systems, I set this string to a NULL object. Do not set to empty string.
  • getTimeout() and setTimeout() Exactly as the name says. Get and set the detector timeout (presumably) in milliseconds.
  • dispose() Dispose of anything like sessions and instance objects. Invoked when scanning complete.
  • isServiceDetected() Given an InetAddress object, determine if that system supports your protocol/service. Return false if no, true if yes. How you do this is up to you and is protocol specific.

Building

Once your files are in the proper places, building/assembling is the same as always.

Build OpenNMS by running build from the top-level source directory via.

./compile.pl -Dopennms.home=/opt/opennms
./assemble.pl

Further, if you haven't made any changes to the rest of the source tree, you can compile your jar directly in your code directory and avoid re-assembling.

cd protocols/xmp
../../compile.pl 
ls target

Notes

  • Bean annotations @Component and @Scope are needed by the Spring Framework in order to find and glue in your collector code.
  • Do not put a single-entry default-foreign-source.xml file in your ONMS/etc subdirectory. If you do that, you'll break scanning for all other protocols. Add your detector via the Web GUI and it will then write out a complete default-foreign-source.xml file.

default-foreign-source.xml notes

  • Detectors have an IP address matching method associated with them. Return a NULL object rather than an empty string. Otherwise, your detector may not be invoked to scan a system. I submitted a fix for this bug in provisiond and its been incorporated into 15.0 but earlier versions may not have this.
  • Discovery simply finds nodes via ICMP but provisiond is what periodically scans them using detectors to figure out what those systems do. If you want to speed up the re-scan interval, edit this field via the Web UI and/or by editing the default-foreign-source.xml file if its already present. Remember, don't go create one by hand.

See Also