Scriptd
Scriptd can transform and enhance Horizon events generated by other daemons. It can generate new events based on incoming data, enrich events with new data, and forward events as SNMP traps to external systems amongst other uses. This feature enables better integration with external systems, based on data from sources internal and external to Horizon.
The ${OPENNMS_HOME}/etc/scriptd-configuration.xml file contains elements and attributes that define how scriptd processes events and executes scripts.
Beanshell scripts executed by scriptd should be placed in ${OPENNMS_HOME}/etc/scripts/
When an event is published on the event bus that Scriptd is configured to listen for, it executes the beanscript associated with that event.
A common (though not only, as you can see in the examples) usage pattern is to compose a script that defines one or more a callable functions that accept an immutable event IEvent as a argument, which is sourced when scriptd starts, in start-script block.
This makes the function available within the context of scriptd so that the script function can be called from an event-script block.
Beanshell script can also be embedded directly in the start-script or event-script blocks, using xml CDATA tags.
Examples
Example 1: Enriching an event
The following example performs a reverse DNS lookup on the content of a specified event parameter, and emits a new event with a distinct UEI and a new parameter containing the rDNS name.
${OPENNMS_HOME}/etc/scriptd-configuration.xml<scriptd-configuration xmlns="http://xmlns.opennms.org/xsd/config/scriptd" transactional="false">
<engine language="beanshell" className="bsh.util.BeanShellBSFEngine" extensions="bsh"/>
<start-script language="beanshell">
log = bsf.lookupBean("log"); (1)
source("/opt/opennms/etc/scripts/scriptd-parm-rdns.bsh"); (2)
</start-script>
<stop-script language="beanshell">
log.debug("executing a stop script");
</stop-script>
<event-script language="beanshell">
<uei name="uei.opennms.org/corporate_networks/traps/OSPF-State"/> (3)
<uei name="uei.opennms.org/corporate_networks/traps/OSPFNbrState"/>
appendUei = "WithLookup"; <!-- the resulting event appends this to the UEI --> (4)
positions = new int[]{ 1, 2, 4 }; <!-- Do the work on parms parm[2] and parm[4] -->
event = bsf.lookupBean("event"); (5)
mangleEvent(event, appendUei, positions); (6)
</event-script>
</scriptd-configuration>
| 1 | Boilerplate to define the log object, used for logging within your script. |
| 2 | The script is sourced on startup to define the functions it contains. |
| 3 | The uei for which to listen that will execute this event-script block. |
| 4 | This value is appended to the resulting event uei, making the emitted event uei uei.opennms.org/corporate_networks/traps/OSPF-StateWithLookup. |
| 5 | Fetch the incoming event. |
| 6 | This function is defined in scriptd-parm-rdns.bsh, sourced by the start-script block. |
${OPENNMS_HOME}/etc/scripts/scriptd-parm-rdns.bshimport java.net.InetAddress; (1)
import org.opennms.core.spring.BeanUtils;
import org.opennms.netmgt.events.api.model.IEvent; (2)
import org.opennms.netmgt.events.api.model.IParm;
import org.opennms.netmgt.events.api.EventForwarder;
import org.opennms.netmgt.model.events.EventBuilder; (3)
import org.opennms.netmgt.xml.event.Event; (4)
import org.opennms.netmgt.xml.event.Parm;
eventForwarder = BeanUtils.getBean("daemonContext", "eventForwarder", EventForwarder.class);
void mangleEvent(IEvent event, String appendUei, int[] positions) { (5)
log.debug("Mangling an event: {}", event.uei); (6)
iparms = event.getParmCollection();
if (iparms == null) {
log.debug("Parameters null");
}
else {
log.debug("Parameters NOT null");
newEvent = new EventBuilder(event.uei.concat(appendUei), "Scriptd", new Date()) (6)
.setNodeid(event.nodeid)
.setInterface(event.interfaceAddress)
.setService(event.service)
.getEvent();
for(p : iparms) {
parm = new Parm();
newEvent.addParm(parm.copyFrom(p)); //eventForwarder won't forward an event built with immutableParms
}
for( i : positions ) {
lookMeUp = lookupParm(iparms.get(i-1));
//log.debug("parm #{}", i); (7)
//log.debug("is appended as Name: {}", lookMeUp.getParmName());
//log.debug(" with Value: {}", lookMeUp.getValue().getContent());
newEvent.addParm(lookMeUp); (8)
}
}
log.debug("New event {}", newEvent.toString());
eventForwarder.sendNow(newEvent); (9)
}
Parm lookupParm(IParm parm) { (10)
value = parm.getValue().getContent();
try {
InetAddress ip = InetAddress.getByName(value); (11)
hostname = ip.getCanonicalHostName();
} catch ( UnknownHostException e ) {
log.debug("Reverse DNS lookup failed for {}", value);
hostname = value; //if the lookup fails, keep the original parm value
}
newParm = new Parm(parm.getParmName()+"-hostname", hostname); (12)
return newParm;
}
| 1 | java.net.InetAddress is used to perform the reverse DNS lookup. |
| 2 | Incoming events are immutable IEvent objects, and event paramters are immutable IParm objects. |
| 3 | The EventBuilder is used to create new events. |
| 4 | The EventForwarder requires mutable Event and Parm objects. |
| 5 | This defines the mangleEvent function, called from the event-script block in scripts-configuration.xml. |
| 6 | Create a new event using the EventBuilder using the new, appended UEI and "Scriptd" as the source. |
| 7 | Additional debug logging can be added using the log object for troubleshooting; beanshell uses Java-style comments. |
| 8 | This adds the event parameter containing the rDNS hostname to the new event being created. |
| 9 | Using the EventForwarder, send the new event out on the event bus. |
| 10 | This function is called by mangleEvent to perform the rDNS lookup on the original event parameter. |
| 11 | Perform the rDNS loookup using InetAddress.getByName() from java.net.InetAddress. |
| 12 | Create a new event Parm object using the original Parameter name appended with '-hostname', using the value returned by the getByName() |
Example 2: Forward events to an external system using SNMPv3
This example uses the snmpv3TrapHelper to forward events to an external system.
The snmpv3TrapHelper will not forward an immutable IEvent or an event containing immutable IParms, and so we create a new, mutable Event object and copy the parameters to new, mutable Parm objects.
${OPENNMS_HOME}/etc/scriptd-configuration.xml<scriptd-configuration xmlns="http://xmlns.opennms.org/xsd/config/scriptd" transactional="false">
<engine language="beanshell" className="bsh.util.BeanShellBSFEngine" extensions="bsh"/>
<start-script language="beanshell"><![CDATA[ (1)
log = bsf.lookupBean("log"); (2)
snmpTrapHelper = new org.opennms.netmgt.scriptd.helper.SnmpTrapHelper(); (3)
snmpv3TrapHelper = new org.opennms.netmgt.scriptd.helper.SnmpV3TrapEventForwarder( (4)
"192.168.1.202", /* destination ip */
162, /* destination port */
3, /* security level: noAuth,noPriv=1, auth,noPriv=2, auth,priv=3 */
"opennmsUser", /* security name */
"0p3nNMSv3", /* auth pass phrase */
"MD5", /* auth protocol: MD5, SHA */
"0p3nNmsv3", /* priv pass phrase */
"DES", /* priv protocol: DES, AES, AES192, AES256 */
snmpTrapHelper /* helper object */
);
// Use the default policy rule that forwards all events - we can manage the filtering ourselves in this script
snmpv3TrapHelper.setEventPolicyRule(new org.opennms.netmgt.scriptd.helper.EventPolicyRuleDefaultImpl());
]]>
</start-script>
<stop-script language="beanshell">
snmpTrapHelper.stop(); (5)
</stop-script>
<event-script language="beanshell"><![CDATA[
event = bsf.lookupBean("event");
if (event != null && !event.getSource().equals("trapd")) { (6)
iparms = event.getParmCollection(); (7)
newEvent = new org.opennms.netmgt.model.events.EventBuilder(event.uei, "Scriptd", new Date()) (8)
.setNodeid(event.nodeid)
.setInterface(event.interfaceAddress)
.setService(event.service)
.getEvent();
for(p : iparms) {
parm = new org.opennms.netmgt.xml.event.Parm(); (9)
newEvent.addParm(parm.copyFrom(p)); //eventForwarder won't forward an event built with immutableParms
}
//log.debug("Forwarding SNMPv3 trap with: {}", snmpv3TrapHelper); (10)
snmpv3TrapHelper.flushEvent(newEvent); (11)
}
]]>
</event-script>
</scriptd-configuration>
| 1 | Here we wrap the script content in CDATA tags directly in the start-script |
| 2 | Boilerplate to define the log object, used for logging within the script. |
| 3 | Create a new snmpTrapHelper object. |
| 4 | Create a new snmpv3TrapHelper with the desired parameters. |
| 5 | The stop-script block can be used to clean up on scriptd restart. |
| 6 | This checks if the incoming event originated from a daemon other than Trapd and is not null. |
| 7 | Fetch all immutable IParm event parameters from the incoming event; incoming events are always immutable. |
| 8 | Create a new Event using the EventBuilder and set the desired event attributes; the snmpv3TrapHelper will not forward immutable IEvent events. |
| 9 | Create a new, mutable event parameter Parm object; the snmpv3TrapHelper will not forward events with immutable IParm parameters. |
| 10 | Populate the new Parm object with the content of the IParm with copyFrom(). |
| 11 | Use the snmpv3TrapHelper to send the new, mutable event out to its destination. |