diff --git a/docs/modules/operation/pages/deep-dive/events/scriptd.adoc b/docs/modules/operation/pages/deep-dive/events/scriptd.adoc index 262434d78c22..edf70f6a5384 100644 --- a/docs/modules/operation/pages/deep-dive/events/scriptd.adoc +++ b/docs/modules/operation/pages/deep-dive/events/scriptd.adoc @@ -6,12 +6,39 @@ It can generate new events based on incoming data, enrich events with new data, This feature enables better integration with external systems, based on data from sources internal and external to {page-component-title}. 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/` +Groovy 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. +When an event is published on the event bus that Scriptd is configured to listen for, it executes the script 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 callable closures that accept an immutable event `IEvent` as an argument, which is evaluated when scriptd starts, in the `start-script` block. +This makes the closure available within the context of `scriptd` so that it can be called from an `event-script` block. +Groovy scripts can also be embedded directly in the `start-script` or `event-script` blocks, using xml `CDATA` tags. + +IMPORTANT: Groovy is the only scripting language that ships with `scriptd`. +If you are upgrading from an earlier version that uses BeanShell, see <> for the changes you need to make to existing scripts. + +[[ga-scriptd-groovy-notes]] +== Writing Groovy scripts for scriptd + +Scriptd executes each `start-script`, `stop-script`, and `event-script` block separately, but all of them share a single set of variables called the _binding_. +Anything you want to reuse across blocks -- a logger, a helper object, a closure -- must live in that binding. +This leads to three rules that differ from the BeanShell scripts used in earlier releases: + +Assign shared variables without `def` or a type:: +An assignment such as `log = bsf.lookupBean("log")` places `log` in the shared binding, where later blocks can read it. +Writing `def log = ...` or `Logger log = ...` instead creates a variable local to that one block, and later blocks fail with a "No such property" error. + +Define reusable functions as closures, not methods:: +A method declared with `def myFunction() { ... }` belongs only to the script that declares it and is not visible to other blocks. +Assign a closure to a binding variable instead: `myFunction = { ... }`. +Closures stored in the binding can be called normally, including from inside other closures. + +Load external script files with `evaluate`, not `source`:: +Replace `source("/path/to/script.bsh")` with `evaluate(new File("/path/to/script.groovy"))`. +The evaluated file shares the calling script's binding, so any closures and variables it assigns without `def` become available to every later block. + +Beyond these rules, Groovy accepts most Java syntax, so much of an existing script will carry over unchanged. +The most common remaining edits are replacing the Java-style `for (item : collection)` loop with Groovy's `for (item in collection)`, replacing Java array literals such as `new int[]{1, 2, 4}` with Groovy list literals such as `[1, 2, 4]`, and adding imports for classes that BeanShell resolved implicitly. +Semicolons are optional in Groovy. == Examples @@ -24,108 +51,118 @@ The following example performs a reverse DNS lookup on the content of a specifie [source, xml] ---- - + - - log = bsf.lookupBean("log"); <1> - source("/opt/opennms/etc/scripts/scriptd-parm-rdns.bsh"); <2> + + log = bsf.lookupBean("log") <1> + evaluate(new File("/opt/opennms/etc/scripts/scriptd-parm-rdns.groovy")) <2> - - log.debug("executing a stop script"); + + log.debug("executing a stop script") - + <3> - appendUei = "WithLookup"; <4> - positions = new int[]{ 1, 2, 4 }; - event = bsf.lookupBean("event"); <5> - mangleEvent(event, appendUei, positions); <6> + appendUei = "WithLookup" <4> + positions = [1, 2, 4] <5> + event = bsf.lookupBean("event") <6> + mangleEvent(event, appendUei, positions) <7> ---- <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. + Note the absence of `def`, which keeps `log` in the shared binding so the other blocks can use it. +<2> The script is evaluated on startup to define the closures 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. +<5> A Groovy list literal; the equivalent BeanShell script used a Java array literal here. +<6> Fetch the incoming event. +<7> This closure is defined in `scriptd-parm-rdns.groovy`, evaluated by the `start-script` block. -.`$\{OPENNMS_HOME}/etc/scripts/scriptd-parm-rdns.bsh` -[source, beanshell] +.`$\{OPENNMS_HOME}/etc/scripts/scriptd-parm-rdns.groovy` +[source, groovy] ---- -import 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; +import java.net.InetAddress <1> +import java.net.UnknownHostException +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) <5> + +lookupParm = { IParm parm -> <6> + + def value = parm.getValue().getContent() + def hostname + try { + InetAddress ip = InetAddress.getByName(value) <7> + 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 + } -eventForwarder = BeanUtils.getBean("daemonContext", "eventForwarder", EventForwarder.class); + return new Parm(parm.getParmName() + "-hostname", hostname) <8> +} -void mangleEvent(IEvent event, String appendUei, int[] positions) { <5> +mangleEvent = { IEvent event, String appendUei, List positions -> <9> - log.debug("Mangling an event: {}", event.uei); <6> + log.debug("Mangling an event: {}", event.uei) - iparms = event.getParmCollection(); + def iparms = event.getParmCollection() <10> if (iparms == null) { - log.debug("Parameters null"); + log.debug("Parameters null") + return <11> } - 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("Parameters NOT null") + def newEvent = new EventBuilder(event.uei.concat(appendUei), "Scriptd", new Date()) <12> + .setNodeid(event.nodeid) + .setInterface(event.interfaceAddress) + .setService(event.service) + .getEvent() + for (p in iparms) { <13> + def parm = new Parm() + newEvent.addParm(parm.copyFrom(p)) //eventForwarder won't forward an event built with immutableParms } - 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 + for (i in positions) { + def lookMeUp = lookupParm(iparms.get(i - 1)) <14> + //log.debug("parm #{}", i) <15> + //log.debug("is appended as Name: {}", lookMeUp.getParmName()) + //log.debug(" with Value: {}", lookMeUp.getValue().getContent()) + newEvent.addParm(lookMeUp) <16> } - newParm = new Parm(parm.getParmName()+"-hostname", hostname); <12> - return newParm; + log.debug("New event {}", newEvent.toString()) + eventForwarder.sendNow(newEvent) <17> } ---- <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. + Groovy does not import the `java.net` package implicitly, so both it and `UnknownHostException` must be imported explicitly. +<2> Incoming events are immutable `IEvent` objects, and event parameters 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()` +<5> Assigned without `def` so that the closures below can resolve it from the shared binding. +<6> This defines the `lookupParm` closure, called by `mangleEvent` to perform the rDNS lookup on the original event parameter. + Assigning a closure rather than declaring a method is what makes it reusable from the other script blocks. +<7> Perform the rDNS lookup using `InetAddress.getByName()` from `java.net.InetAddress`. +<8> Create a new event `Parm` object using the original `Parameter` name appended with `'-hostname'`, using the value returned by `getCanonicalHostName()`. +<9> This defines the `mangleEvent` closure, called from the `event-script` block in `scriptd-configuration.xml`. +<10> Local variables that are not shared between blocks should use `def`, as they are here. +<11> Return early when the incoming event carries no parameters, as there is nothing to enrich. +<12> Create a new event using the `EventBuilder` using the new, appended UEI and "Scriptd" as the source. +<13> Groovy uses `for (item in collection)` where Java and BeanShell use `for (item : collection)`. +<14> Closures held in the binding can be called from inside another closure, exactly like a method. +<15> Additional debug logging can be added using the `log` object for troubleshooting; Groovy uses Java-style comments. +<16> This adds the event parameter containing the rDNS hostname to the new event being created. +<17> Using the `EventForwarder`, send the new event out on the event bus. [[ga-scriptd-forward-snmpv3]] === Example 2: Forward events to an external system using SNMPv3 @@ -137,12 +174,12 @@ The `snmpv3TrapHelper` will not forward an immutable `IEvent` or an event contai [source,xml] ---- - + - - log = bsf.lookupBean("log"); <2> + + log = bsf.lookupBean("log") <2> - snmpTrapHelper = new org.opennms.netmgt.scriptd.helper.SnmpTrapHelper(); <3> + 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 */ @@ -153,32 +190,32 @@ The `snmpv3TrapHelper` will not forward an immutable `IEvent` or an event contai "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()); + snmpv3TrapHelper.setEventPolicyRule(new org.opennms.netmgt.scriptd.helper.EventPolicyRuleDefaultImpl()) ]]> - - snmpTrapHelper.stop(); <5> + + snmpTrapHelper.stop() <5> - - iparms = event.getParmCollection(); <7> - newEvent = new org.opennms.netmgt.model.events.EventBuilder(event.uei, "Scriptd", new Date()) <8> + def iparms = event.getParmCollection() <7> + def 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 + .getEvent() + for (p in iparms) { <9> + def parm = new org.opennms.netmgt.xml.event.Parm() <10> + 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> + //log.debug("Forwarding SNMPv3 trap with: {}", snmpv3TrapHelper) <11> + snmpv3TrapHelper.flushEvent(newEvent) <12> } ]]> @@ -187,16 +224,19 @@ The `snmpv3TrapHelper` will not forward an immutable `IEvent` or an event contai <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. + Like `log`, it is assigned without `def` so that the `stop-script` block can still reach it. <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. + These values are only used within this block, so they are declared with `def`. <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. +<9> Groovy uses `for (item in collection)` where Java and BeanShell use `for (item : collection)`. +<10> Create a new, mutable event parameter `Parm` object and populate it from the immutable `IParm` with `copyFrom()`; the `snmpv3TrapHelper` will not forward events with immutable `IParm` parameters. +<11> Additional debug logging can be added using the `log` object for troubleshooting. +<12> Use the `snmpv3TrapHelper` to send the new, mutable event out to its destination. [[ga-scriptd-other]] === Other examples -Other scriptd examples are available in `$\{OPENNMS_HOME}/etc/examples/` directory of your {page-component-title} installation. +Other scriptd examples are available in `$\{OPENNMS_HOME}/etc/examples/` directory of your {page-component-title} installation. \ No newline at end of file diff --git a/docs/modules/reference/pages/provisioning/detectors/BsfDetector.adoc b/docs/modules/reference/pages/provisioning/detectors/BsfDetector.adoc index ac0b03028f0c..c97129d1c98f 100644 --- a/docs/modules/reference/pages/provisioning/detectors/BsfDetector.adoc +++ b/docs/modules/reference/pages/provisioning/detectors/BsfDetector.adoc @@ -7,6 +7,9 @@ The only requirement is that the script returns the string `OK` if it passes. The BSFDetector passes the `map`, `ip_addr`, `svc_name`, and `results` variables as beans to the script. +NOTE: Groovy is the scripting language that ships with {page-component-title}. +BeanShell is no longer supported; rewrite any existing `.bsh` scripts in Groovy and update the `bsfEngine` and `langClass` parameters of the affected detectors. + == Detector facts [options="autowidth"] @@ -32,16 +35,14 @@ The BSFDetector passes the `map`, `ip_addr`, `svc_name`, and `results` variables | Short name of the language the script is written in. Choices: -* jython -* beanshell * groovy +* jython | none | bsfEngine | BSF engine to use when running the script. Choices: -* `bsh.util.BeanShellBSFEngine` * `org.codehaus.groovy.bsf.GroovyEngine` * `org.apache.bsf.engines.jython.JythonEngine` | none @@ -91,15 +92,10 @@ The following table provides the required setup for commonly used languages. | bsfEngine parameter | Required library -| http://www.beanshell.org[BeanShell] -| beanshell -| bsh.util.BeanShellBSFEngine -| supported by default - | https://groovy-lang.org/[Groovy] | groovy | org.codehaus.groovy.bsf.GroovyEngine -| groovy-all-[version].jar +| ships with {page-component-title} | http://www.jython.org[Jython] | jython @@ -107,38 +103,13 @@ The following table provides the required setup for commonly used languages. | jython-[version].jar |=== -IMPORTANT: If you are using a Groovy or Jython script, you need to place the required library file in the `$\{OPENNMS_HOME}/lib` directory and restart the {page-component-title} service. +IMPORTANT: If you are using a Jython script, you need to place the required library file in the `$\{OPENNMS_HOME}/lib` directory and restart the {page-component-title} service. == Example configurations -=== BeanShell example - -.BeanShell example -[source, xml] ----- - - - - - - ----- - -.BeanShell example `MinimalBeanShell.bsh` script file -[source, java] ----- -File testFile = new File("/tmp/TestFile"); -if (testFile.exists()) { - return "OK"; -} else { - results.put("reason", "file does not exist"); - return "NOK"; -} ----- - === Groovy example -The Groovy language requires the installation of an additional library. +Groovy ships with {page-component-title}, so no additional library is required. .Groovy example for `run-type` of `eval` [source, xml] diff --git a/docs/modules/reference/pages/service-assurance/monitors/BSFMonitor.adoc b/docs/modules/reference/pages/service-assurance/monitors/BSFMonitor.adoc index f49fa49594ac..cf59f520c7e6 100644 --- a/docs/modules/reference/pages/service-assurance/monitors/BSFMonitor.adoc +++ b/docs/modules/reference/pages/service-assurance/monitors/BSFMonitor.adoc @@ -8,6 +8,9 @@ Users can write scripts to perform highly customized service checks. IMPORTANT: This monitor is not optimized for scale. It is intended for a small number of custom checks or prototyping of monitors. +NOTE: Groovy is the scripting language that ships with {page-component-title}. +BeanShell is no longer supported; rewrite any existing `.bsh` scripts in Groovy and update the `bsf-engine` and `lang-class` parameters of the affected services. + == BSFMonitor versus SystemExecuteMonitor The BSFMonitor avoids the overhead of fork(2) that the SystemExecuteMonitor uses. @@ -40,7 +43,6 @@ The BSFMonitor also grants access to a selection of {page-component-title} inter | bsf-engine | The BSF Engine to run the script in different languages: -* bsh.util.BeanShellBSFEngine * org.codehaus.groovy.bsf.GroovyEngine * org.apache.bsf.engines.jython.JythonEngine | n/a @@ -52,7 +54,7 @@ The BSFMonitor also grants access to a selection of {page-component-title} inter | eval | lang-class -| The BSF language class, like `groovy` or `beanshell` +| The BSF language class, like `groovy` | filename extension is interpreted by default | file-extensions @@ -155,7 +157,7 @@ If the response time should be persisted, add the following parameters: - + @@ -196,15 +198,10 @@ The following table provides the required setup for commonly used languages. | bsf-engine | required library -| http://www.beanshell.org[BeanShell] -| beanshell -| `bsh.util.BeanShellBSFEngine` -| supported by default - | https://groovy-lang.org/[Groovy] | groovy | `org.codehaus.groovy.bsf.GroovyEngine` -| `groovy-all-[version].jar` +| ships with {page-component-title} | http://www.jython.org[Jython] | jython @@ -212,38 +209,9 @@ The following table provides the required setup for commonly used languages. | `jython-[version].jar` |=== -== BeanShell example - -Note that you must include the `monitor` section for each service in your definition. - -.BeanShell example `poller-configuration.xml` -[source, xml] ----- - - - - - - ----- - -.BeanShell example `MinimalBeanShell.bsh` script file -[source, java] ----- -bsf_monitor.log("ERROR", "Starting MinimalBeanShell.bsf", null); -File testFile = new File("/tmp/TestFile"); -if (testFile.exists()) { - return "OK"; -} else { - results.put("reason", "file does not exist"); - return "NOK"; -} ----- - == Groovy example -The use of the Groovy language requires an additional library. -Copy a compatible `groovy-all.jar` into the `$\{OPENNMS_HOME}/lib` folder and restart {page-component-title} to make Groovy available for the BSFMonitor. +Groovy ships with {page-component-title}, so no additional library is required. Note that you must include the `monitor` section for each service in your definition. @@ -259,7 +227,7 @@ Note that you must include the `monitor` section for each service in your defini ---- .Groovy example `MinimalGroovy.groovy` script file for `run-type` set to `eval` -[source, java] +[source, groovy] ---- bsf_monitor.log("ERROR", "Starting MinimalGroovy.groovy", null); File testFile = new File("/tmp/TestFile"); @@ -284,7 +252,7 @@ if (testFile.exists()) { ---- .Groovy example `MinimalGroovy.groovy` script file for `run-type` set to `exec` -[source, java] +[source, groovy] ---- bsf_monitor.log("ERROR", "Starting MinimalGroovy", null); def testFile = new File("/tmp/TestFile"); @@ -362,7 +330,7 @@ For Debian/Ubuntu, use `/var/lib/opennms/rrd/response`. ---- .Groovy example Bean referencing script file -[source, java] +[source, groovy] ---- bsf_monitor.log("ERROR", "Starting MinimalGroovy", null); diff --git a/opennms-alarms/bsf-northbounder/pom.xml b/opennms-alarms/bsf-northbounder/pom.xml index ed566dff2a14..01dbe2fcf101 100644 --- a/opennms-alarms/bsf-northbounder/pom.xml +++ b/opennms-alarms/bsf-northbounder/pom.xml @@ -60,9 +60,12 @@ bsf bsf + - org.apache-extras.beanshell - bsh + org.opennms.dependencies + groovy-dependencies + pom + runtime diff --git a/opennms-alarms/bsf-northbounder/src/main/java/org/opennms/netmgt/alarmd/northbounder/bsf/BSFEngineHandler.java b/opennms-alarms/bsf-northbounder/src/main/java/org/opennms/netmgt/alarmd/northbounder/bsf/BSFEngineHandler.java index 128ddda5faab..eac132037318 100644 --- a/opennms-alarms/bsf-northbounder/src/main/java/org/opennms/netmgt/alarmd/northbounder/bsf/BSFEngineHandler.java +++ b/opennms-alarms/bsf-northbounder/src/main/java/org/opennms/netmgt/alarmd/northbounder/bsf/BSFEngineHandler.java @@ -59,15 +59,15 @@ public class BSFEngineHandler implements Destination { private String m_filter; /** The engine language. */ - @XmlElement(name = "language", required = false, defaultValue = "beanshell") + @XmlElement(name = "language", required = false, defaultValue = "groovy") private String m_language; /** The engine class name. */ - @XmlElement(name = "className", required = false, defaultValue = "bsh.util.BeanShellBSFEngine") + @XmlElement(name = "className", required = false, defaultValue = "org.codehaus.groovy.bsf.GroovyEngine") private String m_className; /** The engine file extensions. */ - @XmlElement(name = "extensions", required = false, defaultValue = "bsh") + @XmlElement(name = "extensions", required = false, defaultValue = "groovy,gy") private String m_extensions; /** The on-start content. */ @@ -136,7 +136,7 @@ public void setFilter(String filter) { * @return the language */ public String getLanguage() { - return m_language == null ? "beanshell" : m_language; + return m_language == null ? "groovy" : m_language; } /** @@ -154,7 +154,7 @@ public void setLanguage(String language) { * @return the class name */ public String getClassName() { - return m_className == null ? "bsh.util.BeanShellBSFEngine" : m_className; + return m_className == null ? "org.codehaus.groovy.bsf.GroovyEngine" : m_className; } /** @@ -172,7 +172,7 @@ public void setClassName(String className) { * @return the extensions */ public String getExtensions() { - return m_extensions == null ? "bsh" : m_extensions; + return m_extensions == null ? "groovy,gy" : m_extensions; } /** diff --git a/opennms-alarms/bsf-northbounder/src/main/resources/xsds/bsf-northbounder-configuration.xsd b/opennms-alarms/bsf-northbounder/src/main/resources/xsds/bsf-northbounder-configuration.xsd index 0296eebb6a46..772b6a87aaf3 100644 --- a/opennms-alarms/bsf-northbounder/src/main/resources/xsds/bsf-northbounder-configuration.xsd +++ b/opennms-alarms/bsf-northbounder/src/main/resources/xsds/bsf-northbounder-configuration.xsd @@ -20,9 +20,9 @@ - - - + + + diff --git a/opennms-base-assembly/src/main/filtered/etc/bsf-northbounder-configuration.xml b/opennms-base-assembly/src/main/filtered/etc/bsf-northbounder-configuration.xml index 92e59b046d0f..e9b07aa31934 100644 --- a/opennms-base-assembly/src/main/filtered/etc/bsf-northbounder-configuration.xml +++ b/opennms-base-assembly/src/main/filtered/etc/bsf-northbounder-configuration.xml @@ -10,19 +10,20 @@ Example ipAddr != '0.0.0.0' - beanshell - bsh.util.BeanShellBSFEngine - bsh + groovy + org.codehaus.groovy.bsf.GroovyEngine + groovy,gy - log = bsf.lookupBean("log"); - log.info("Starting..."); + // assign without 'def' so the binding is shared with onStop and onAlarm + log = bsf.lookupBean("log") + log.info("Starting...") - log.info("Stopping..."); + log.info("Stopping...") - a = bsf.lookupBean("alarm"); - log.info("processing alarm " + a); + a = bsf.lookupBean("alarm") + log.info("processing alarm " + a) --> diff --git a/opennms-base-assembly/src/main/filtered/etc/examples/event-proxy/scriptd-configuration.xml b/opennms-base-assembly/src/main/filtered/etc/examples/event-proxy/scriptd-configuration.xml index f84957ae993b..bf5d1b5d08ba 100644 --- a/opennms-base-assembly/src/main/filtered/etc/examples/event-proxy/scriptd-configuration.xml +++ b/opennms-base-assembly/src/main/filtered/etc/examples/event-proxy/scriptd-configuration.xml @@ -1,52 +1,53 @@ - - + + - import org.opennms.netmgt.scriptd.ins.events.InsServerListener; - import org.opennms.netmgt.config.DataSourceFactory; + import org.opennms.netmgt.scriptd.ins.events.InsServerListener + import org.opennms.netmgt.config.DataSourceFactory - log = bsf.lookupBean("log"); - log.debug("Starting Script"); + // assign without 'def' or a type so these stay in the binding shared + // with the stop-script and the event-script + log = bsf.lookupBean("log") + log.debug("Starting Script") - log.debug("Start TCP PROXY for INS Event "); + log.debug("Start TCP PROXY for INS Event ") + + isl = new InsServerListener() - InsServerListener isl = new InsServerListener(); - //optional (if not setted, default port (8154) is used) - //isl.setListeningPort(8152); - + //isl.setListeningPort(8152) + //optional (if not setted, no authentication is required) - //isl.setSharedASCIIString("1234567890"); - + //isl.setSharedASCIIString("1234567890") + //required properties - isl.setCriteriaRestriction("eventuei = 'uei.opennms.org/internal/alarms/AlarmRaised' and EXISTS (select 1 from alarms where alarmtype = 1 and severity > 3 and eventoperinstruct = alarmid and eventtime > lasteventtime)"); - isl.start(); + isl.setCriteriaRestriction("eventuei = 'uei.opennms.org/internal/alarms/AlarmRaised' and EXISTS (select 1 from alarms where alarmtype = 1 and severity > 3 and eventoperinstruct = alarmid and eventtime > lasteventtime)") + isl.start() - + - isl.interrupt(); - log.debug("executing a stop script"); + isl.interrupt() + log.debug("executing a stop script") - - event = bsf.lookupBean("event"); - + + event = bsf.lookupBean("event") + if ( (event.uei.equals("uei.opennms.org/internal/alarms/NotificationAlarm")) || (event.uei.equals("uei.opennms.org/internal/alarms/AlarmCleared")) || (event.uei.equals("uei.opennms.org/internal/alarms/AlarmRaised")) ) { - - isl.flushEvent(event); + + isl.flushEvent(event) } - - + - + \ No newline at end of file diff --git a/opennms-base-assembly/src/main/filtered/etc/examples/scriptd-configuration.xml b/opennms-base-assembly/src/main/filtered/etc/examples/scriptd-configuration.xml index e13d60c9b3cd..be13de6d1ccb 100644 --- a/opennms-base-assembly/src/main/filtered/etc/examples/scriptd-configuration.xml +++ b/opennms-base-assembly/src/main/filtered/etc/examples/scriptd-configuration.xml @@ -1,35 +1,36 @@ - + - + - import org.opennms.core.utils.InetAddressUtils; - import org.opennms.netmgt.snmp.SnmpTrapBuilder; - import org.opennms.netmgt.config.DataSourceFactory; - import org.opennms.netmgt.utils.SingleResultQuerier; - import org.opennms.netmgt.events.api.model.IEvent; + import org.opennms.core.utils.InetAddressUtils + import org.opennms.netmgt.snmp.SnmpTrapBuilder + import org.opennms.netmgt.config.DataSourceFactory + import org.opennms.netmgt.utils.SingleResultQuerier + import org.opennms.netmgt.events.api.model.IEvent - log = bsf.lookupBean("log"); - snmpTrapHelper = new org.opennms.netmgt.scriptd.helper.SnmpTrapHelper(); + // assign without 'def' so these stay in the binding shared with the + // stop-script, the event-script and the file evaluated below + log = bsf.lookupBean("log") + snmpTrapHelper = new org.opennms.netmgt.scriptd.helper.SnmpTrapHelper() + + evaluate(new File('${install.dir}/etc/scriptd-event-forwarder.groovy')) - source("${install.dir}/etc/scriptd-event-forwarder.bsh"); - - + - snmpTrapHelper.stop(); - log.debug("executing a stop script"); + snmpTrapHelper.stop() + log.debug("executing a stop script") - + - event = bsf.lookupBean("event"); - forwardEvent(event); + event = bsf.lookupBean("event") + forwardEvent(event) - - + \ No newline at end of file diff --git a/opennms-base-assembly/src/main/filtered/etc/examples/scriptd-event-forwarder.bsh b/opennms-base-assembly/src/main/filtered/etc/examples/scriptd-event-forwarder.groovy similarity index 58% rename from opennms-base-assembly/src/main/filtered/etc/examples/scriptd-event-forwarder.bsh rename to opennms-base-assembly/src/main/filtered/etc/examples/scriptd-event-forwarder.groovy index a51cb628d348..8821669604e4 100644 --- a/opennms-base-assembly/src/main/filtered/etc/examples/scriptd-event-forwarder.bsh +++ b/opennms-base-assembly/src/main/filtered/etc/examples/scriptd-event-forwarder.groovy @@ -1,119 +1,129 @@ +import org.opennms.core.utils.InetAddressUtils +import org.opennms.netmgt.events.api.model.IEvent +import org.opennms.netmgt.snmp.SnmpTrapBuilder -void forwardEvent(IEvent event) { +/* + * This file is loaded by the scriptd start-script via evaluate(new File(...)). + * Note that a Groovy method declared with 'def' would not be visible to the + * scripts that run later, so forwardEvent is assigned (without 'def') as a + * closure in the shared binding instead. The 'log', 'snmpTrapHelper' and 'bsf' + * variables likewise come from that shared binding. + */ +forwardEvent = { IEvent event -> if (event.snmp == null) { try { - log.debug("Forwarding an OpenNMS event."); + log.debug("Forwarding an OpenNMS event.") - SnmpTrapBuilder trap = snmpTrapHelper.createV1Trap(".1.3.6.1.4.1.5813.1", "172.20.1.11", 6, 1, 0); + SnmpTrapBuilder trap = snmpTrapHelper.createV1Trap(".1.3.6.1.4.1.5813.1", "172.20.1.11", 6, 1, 0) - /* This sends an enterprise id of ".1.3.6.1.4.1.5813.1" from agent "172.20.1.11" (einstein), + /* This sends an enterprise id of ".1.3.6.1.4.1.5813.1" from agent "172.20.1.11" (einstein), which should be the IP address of the OpenNMS system, generic value of 6 and specific value of 1 */ if (event.hasDbid()) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.1", "OctetString", "text", event.dbid.toString()); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.1", "OctetString", "text", event.dbid.toString()) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.1", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.1", "OctetString", "text", "null") if (event.distPoller != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.2", "OctetString", "text", event.distPoller); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.2", "OctetString", "text", event.distPoller) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.2", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.2", "OctetString", "text", "null") if (event.creationTime != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.3", "OctetString", "text", event.creationTime.toString()); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.3", "OctetString", "text", event.creationTime.toString()) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.3", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.3", "OctetString", "text", "null") if (event.masterStation != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.4", "OctetString", "text", event.masterStation); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.4", "OctetString", "text", event.masterStation) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.4", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.4", "OctetString", "text", "null") if (event.uei != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.6", "OctetString", "text", event.uei); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.6", "OctetString", "text", event.uei) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.6", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.6", "OctetString", "text", "null") if (event.source != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.7", "OctetString", "text", event.source); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.7", "OctetString", "text", event.source) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.7", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.7", "OctetString", "text", "null") if (event.hasNodeid()) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.8", "OctetString", "text", event.nodeid.toString()); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.8", "OctetString", "text", event.nodeid.toString()) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.8", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.8", "OctetString", "text", "null") if (event.time != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.9", "OctetString", "text", event.time.toString()); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.9", "OctetString", "text", event.time.toString()) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.9", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.9", "OctetString", "text", "null") if (event.host != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.10", "OctetString", "text", event.host); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.10", "OctetString", "text", event.host) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.10", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.10", "OctetString", "text", "null") if (event.getInterface() != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.11", "OctetString", "text", event.getInterface()); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.11", "OctetString", "text", event.getInterface()) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.11", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.11", "OctetString", "text", "null") if (event.snmphost != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.12", "OctetString", "text", event.snmphost); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.12", "OctetString", "text", event.snmphost) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.12", "OctetString", "text", "einstein.example.com"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.12", "OctetString", "text", "einstein.example.com") /* The snmphost field must be changed to the hostname of the OpenNMS system sending the event */ if (event.service != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.13", "OctetString", "text", event.service); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.13", "OctetString", "text", event.service) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.13", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.13", "OctetString", "text", "null") if (event.descr != null) { - descrString = event.descr.replaceAll("<.*>", " ").replaceAll(""", "\"").replaceAll("\\s+", " "); - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.16", "OctetString", "text", descrString); + def descrString = event.descr.replaceAll("<.*>", " ").replaceAll(""", "\"").replaceAll("\\s+", " ") + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.16", "OctetString", "text", descrString) } else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.16", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.16", "OctetString", "text", "null") if (event.logmsg.content != null) { - logString = event.logmsg.content.replaceAll("<.*>", " ").replaceAll("\\s+", " "); - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.17", "OctetString", "text", logString); + def logString = event.logmsg.content.replaceAll("<.*>", " ").replaceAll("\\s+", " ") + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.17", "OctetString", "text", logString) } else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.17", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.17", "OctetString", "text", "null") if (event.severity != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.18", "OctetString", "text", event.severity); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.18", "OctetString", "text", event.severity) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.18", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.18", "OctetString", "text", "null") if (event.pathoutage != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.19", "OctetString", "text", event.pathoutage); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.19", "OctetString", "text", event.pathoutage) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.19", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.19", "OctetString", "text", "null") if (event.operinstruct != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.20", "OctetString", "text", event.operinstruct); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.20", "OctetString", "text", event.operinstruct) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.20", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.20", "OctetString", "text", "null") - String retParmVal = null; + String retParmVal = null if (event.getInterface() != null) { try { - retParmVal = InetAddressUtils.addr(event.getInterface()).getHostName(); - } catch (java.net.UnknownHostException e) { + retParmVal = InetAddressUtils.addr(event.getInterface()).getHostName() + } catch (Exception e) { } } if (retParmVal != null) - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.21", "OctetString", "text", retParmVal); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.21", "OctetString", "text", retParmVal) else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.21", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.21", "OctetString", "text", "null") if (event.hasNodeid()) { - node = bsf.lookupBean("node"); - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.22", "OctetString", "text", node.label); + def node = bsf.lookupBean("node") + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.22", "OctetString", "text", node.label) } else - snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.22", "OctetString", "text", "null"); + snmpTrapHelper.addVarBinding(trap, ".1.3.6.1.4.1.5813.2.22", "OctetString", "text", "null") - trap.send("172.20.1.15", 162, "public"); + trap.send("172.20.1.15", 162, "public") /* 172.20.1.15 is the destination for the trap, the port (162) and the community string (usually public for traps) */ - } catch (e) { - sw = new StringWriter(); - pw = new PrintWriter(sw); - e.printStackTrace(pw); - log.debug(sw.toString()); + } catch (Exception e) { + def sw = new StringWriter() + def pw = new PrintWriter(sw) + e.printStackTrace(pw) + log.debug(sw.toString()) } } -} +} \ No newline at end of file diff --git a/opennms-base-assembly/src/main/filtered/etc/scriptd-configuration.xml b/opennms-base-assembly/src/main/filtered/etc/scriptd-configuration.xml index 5e7bd5a2f350..46311e16a18f 100644 --- a/opennms-base-assembly/src/main/filtered/etc/scriptd-configuration.xml +++ b/opennms-base-assembly/src/main/filtered/etc/scriptd-configuration.xml @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/opennms-config-model/src/test/java/org/opennms/netmgt/config/scriptd/ScriptdConfigurationTest.java b/opennms-config-model/src/test/java/org/opennms/netmgt/config/scriptd/ScriptdConfigurationTest.java index b8b666819fe9..e754d68b554d 100644 --- a/opennms-config-model/src/test/java/org/opennms/netmgt/config/scriptd/ScriptdConfigurationTest.java +++ b/opennms-config-model/src/test/java/org/opennms/netmgt/config/scriptd/ScriptdConfigurationTest.java @@ -40,10 +40,10 @@ public static Collection data() throws ParseException { { getConfig(), "\n" + - " \n" + - " println("start")\n" + - " println("stop")\n" + - " \n" + + " \n" + + " println("start")\n" + + " println("stop")\n" + + " \n" + " \n" + " println("onEvent")\n" + " \n" + @@ -60,23 +60,23 @@ private static ScriptdConfiguration getConfig() { ScriptdConfiguration config = new ScriptdConfiguration(); Engine engine = new Engine(); - engine.setLanguage("beanshell"); - engine.setClassName("bsh.util.BeanShellBSFEngine"); - engine.setExtensions("bsh"); + engine.setLanguage("groovy"); + engine.setClassName("org.codehaus.groovy.bsf.GroovyEngine"); + engine.setExtensions("groovy gy"); config.addEngine(engine); StartScript start = new StartScript(); - start.setLanguage("beanshell"); + start.setLanguage("groovy"); start.setContent("println(\"start\")"); config.addStartScript(start); StopScript stop = new StopScript(); - stop.setLanguage("beanshell"); + stop.setLanguage("groovy"); stop.setContent("println(\"stop\")"); config.addStopScript(stop); EventScript script = new EventScript(); - script.setLanguage("beanshell"); + script.setLanguage("groovy"); script.setContent("\n" + " println(\"onEvent\")\n" + " "); diff --git a/opennms-correlation/drools-correlation-engine/pom.xml b/opennms-correlation/drools-correlation-engine/pom.xml index 436b24433d2e..1e0a093bb5b9 100644 --- a/opennms-correlation/drools-correlation-engine/pom.xml +++ b/opennms-correlation/drools-correlation-engine/pom.xml @@ -94,10 +94,6 @@ org.opennms opennms-correlator - - org.apache-extras.beanshell - bsh - com.google.guava guava diff --git a/opennms-correlation/drools-correlation-engine/src/test/java/org/opennms/netmgt/correlation/drools/DroolsConfigurationTest.java b/opennms-correlation/drools-correlation-engine/src/test/java/org/opennms/netmgt/correlation/drools/DroolsConfigurationTest.java index bc453224a4b1..800ce8e6a287 100644 --- a/opennms-correlation/drools-correlation-engine/src/test/java/org/opennms/netmgt/correlation/drools/DroolsConfigurationTest.java +++ b/opennms-correlation/drools-correlation-engine/src/test/java/org/opennms/netmgt/correlation/drools/DroolsConfigurationTest.java @@ -32,8 +32,6 @@ import org.opennms.netmgt.correlation.drools.config.Global; import org.opennms.netmgt.correlation.drools.config.RuleSet; -import bsh.ParseException; - public class DroolsConfigurationTest extends XmlTest { public DroolsConfigurationTest(String schemaFile, EngineConfiguration sampleObject, String sampleXml) { @@ -96,7 +94,7 @@ public ConfigBuilder addGlobalRef(String name, Class type, String ref) { } @Parameters - public static Collection data() throws ParseException { + public static Collection data() { return Arrays.asList(new Object[][] { { "target/classes/xsds/drools-engine.xsd", new ConfigBuilder().get(), diff --git a/opennms-full-assembly/src/license/THIRD-PARTY.properties b/opennms-full-assembly/src/license/THIRD-PARTY.properties index 10758a32d478..01a27166ec08 100644 --- a/opennms-full-assembly/src/license/THIRD-PARTY.properties +++ b/opennms-full-assembly/src/license/THIRD-PARTY.properties @@ -1,6 +1,5 @@ alt.dev.jmta--jmta--1.0=Raphael Szwarc Public Source License, Version 1.0 avalon-framework--avalon-framework--4.1.5=apache_v1_1 -bsh--bsh--1.3.0=spl_v1_0 colt--colt--1.2.0=mit com.hubspot--algebra--1.5=apache_v2 com.hubspot.immutables--hubspot-style--1.4=apache_v2 diff --git a/opennms-services/pom.xml b/opennms-services/pom.xml index 0d636d13d4aa..ad271f77af45 100644 --- a/opennms-services/pom.xml +++ b/opennms-services/pom.xml @@ -175,9 +175,9 @@ pom test - + groovy on the classpath --> org.opennms.dependencies groovy-dependencies @@ -341,11 +341,6 @@ org.opennms.config-dao.poll-outages.impl ${project.version} - - org.apache-extras.beanshell - bsh - runtime - jakarta.mail jakarta.mail-api diff --git a/opennms-services/src/main/java/org/opennms/netmgt/notifd/BSFNotificationStrategy.java b/opennms-services/src/main/java/org/opennms/netmgt/notifd/BSFNotificationStrategy.java index a3181cc8bc92..171da6ed81cd 100644 --- a/opennms-services/src/main/java/org/opennms/netmgt/notifd/BSFNotificationStrategy.java +++ b/opennms-services/src/main/java/org/opennms/netmgt/notifd/BSFNotificationStrategy.java @@ -65,8 +65,9 @@ * things from the BSF era no longer exist: the implicit {@code bsf} helper * object BSF injected into engines, and the {@code bsf-engine} / * {@code file-extensions} switches (ignored with a warning). Script engines - * are discovered from the classpath; BeanShell and Groovy ship with - * OpenNMS.

+ * are discovered from the classpath; Groovy ships with OpenNMS. BeanShell + * was removed along with BSF, so {@code .bsh} scripts no longer resolve to + * an engine and must be rewritten in Groovy.

* * @author Jeff Gehlbach * @author interpreterClass = Class.forName("bsh.Interpreter"); - final Object interpreter = interpreterClass.getDeclaredConstructor().newInstance(); - final java.lang.reflect.Method set = interpreterClass.getMethod("set", String.class, Object.class); - for (Map.Entry entry : bindings.entrySet()) { - set.invoke(interpreter, entry.getKey(), entry.getValue()); - } - return interpreterClass.getMethod("eval", String.class).invoke(interpreter, source); - } catch (java.lang.reflect.InvocationTargetException e) { - final Throwable cause = e.getCause() != null ? e.getCause() : e; - final ScriptException scriptException = new ScriptException(cause.getMessage()); - scriptException.initCause(cause); - throw scriptException; - } catch (ReflectiveOperationException e) { - final ScriptException scriptException = new ScriptException("BeanShell interpreter not available: " + e); - scriptException.initCause(e); - throw scriptException; - } - } - private void warnAboutDeprecatedSwitches() { if (getBsfEngine() != null || getFileExtensions() != null) { LOG.warn("The 'bsf-engine' and 'file-extensions' switches are no longer supported now that the BSF notification strategy runs on JSR-223; they are ignored. Use 'lang-class' or the script file extension to select the engine."); diff --git a/opennms-services/src/main/java/org/opennms/netmgt/scriptd/helper/SnmpTrapHelper.java b/opennms-services/src/main/java/org/opennms/netmgt/scriptd/helper/SnmpTrapHelper.java index fffbe136d8c7..515a1c24bdc8 100644 --- a/opennms-services/src/main/java/org/opennms/netmgt/scriptd/helper/SnmpTrapHelper.java +++ b/opennms-services/src/main/java/org/opennms/netmgt/scriptd/helper/SnmpTrapHelper.java @@ -48,7 +48,7 @@ * forwarding SNMP traps. This class was created in order to make it easier to * write simple scripts to generate traps based on events or to forward traps, * using scripting languages that are able to access Java classes (such as - * BeanShell). + * Groovy). * * @author Jim Doble * @author OpenNMS.org diff --git a/opennms-services/src/test/java/org/opennms/netmgt/notifd/BSFNotificationStrategyIT.java b/opennms-services/src/test/java/org/opennms/netmgt/notifd/BSFNotificationStrategyIT.java index 7d30f47f40a2..e01c716e959e 100644 --- a/opennms-services/src/test/java/org/opennms/netmgt/notifd/BSFNotificationStrategyIT.java +++ b/opennms-services/src/test/java/org/opennms/netmgt/notifd/BSFNotificationStrategyIT.java @@ -95,19 +95,19 @@ public void tearDown() { } /** - * Verifies that we can invoke a BSH script and that + * Verifies that we can invoke a Groovy script and that * the an instance of the appropriate OnmsNode object is * passed to the script. */ @Test public void canUseNodeInScript() throws IOException { - // Create a simple BSH script that verifies the node bean - File notifyBsh = tempFolder.newFile("notify.bsh"); - FileUtils.write(notifyBsh, "results.put(\"status\", node.id == " + node1Id() + " ? \"OK\" : \"NOT_OK\");"); + // Create a simple Groovy script that verifies the node bean + File notifyScript = tempFolder.newFile("notify.groovy"); + FileUtils.write(notifyScript, "results.put(\"status\", node.id == " + node1Id() + " ? \"OK\" : \"NOT_OK\")"); List arguments = new ArrayList<>(); // Point to our script - arguments.add(new Argument("file-name", null, notifyBsh.getAbsolutePath(), false)); + arguments.add(new Argument("file-name", null, notifyScript.getAbsolutePath(), false)); // Reference node 1 arguments.add(new Argument(NotificationManager.PARAM_NODE, null, node1Id(), false)); @@ -116,19 +116,49 @@ public void canUseNodeInScript() throws IOException { } @Test - public void canEvalBeanshellScript() throws IOException { + public void canEvalScript() throws IOException { // Under run-type=eval the script's last expression becomes the status - File notifyBsh = tempFolder.newFile("notify-eval.bsh"); - FileUtils.write(notifyBsh, "node.id == " + node1Id() + " ? \"OK\" : \"NOT_OK\";"); + File notifyScript = tempFolder.newFile("notify-eval.groovy"); + FileUtils.write(notifyScript, "node.id == " + node1Id() + " ? \"OK\" : \"NOT_OK\""); List arguments = new ArrayList<>(); - arguments.add(new Argument("file-name", null, notifyBsh.getAbsolutePath(), false)); + arguments.add(new Argument("file-name", null, notifyScript.getAbsolutePath(), false)); arguments.add(new Argument("run-type", null, "eval", false)); arguments.add(new Argument(NotificationManager.PARAM_NODE, null, node1Id(), false)); assertEquals(0, bsfNotificationStrategy.send(arguments)); } + @Test + public void beanshellScriptIsNoLongerSupported() throws IOException { + // BeanShell was removed along with BSF; a .bsh script must now fail + // cleanly with a diagnosable message rather than silently doing nothing + File notifyBsh = tempFolder.newFile("notify-legacy.bsh"); + FileUtils.write(notifyBsh, "results.put(\"status\", \"OK\");"); + + List arguments = new ArrayList<>(); + arguments.add(new Argument("file-name", null, notifyBsh.getAbsolutePath(), false)); + + assertEquals(-1, bsfNotificationStrategy.send(arguments)); + MockLogAppender.assertLogMatched(Level.ERROR, "No JSR-223 script engine found"); + MockLogAppender.resetState(); + } + + @Test + public void beanshellLangClassIsNoLongerSupported() throws IOException { + // likewise for an explicit lang-class left over from a BSF-era config + File notifyScript = tempFolder.newFile("notify-legacy-lang.groovy"); + FileUtils.write(notifyScript, "results.put(\"status\", \"OK\")"); + + List arguments = new ArrayList<>(); + arguments.add(new Argument("file-name", null, notifyScript.getAbsolutePath(), false)); + arguments.add(new Argument("lang-class", null, "beanshell", false)); + + assertEquals(-1, bsfNotificationStrategy.send(arguments)); + MockLogAppender.assertLogMatched(Level.ERROR, "No JSR-223 script engine found"); + MockLogAppender.resetState(); + } + @Test public void canUseGroovyScript() throws IOException { File notifyGroovy = tempFolder.newFile("notify.groovy"); @@ -158,25 +188,26 @@ public void canResolveGyExtensionAsGroovy() throws IOException { public void canResolveEngineViaLangClass() throws IOException { // No usable extension; lang-class selects the engine by JSR-223 name File notifyTxt = tempFolder.newFile("notify.txt"); - FileUtils.write(notifyTxt, "results.put(\"status\", node.id == " + node1Id() + " ? \"OK\" : \"NOT_OK\");"); + FileUtils.write(notifyTxt, "results.put(\"status\", node.id == " + node1Id() + " ? \"OK\" : \"NOT_OK\")"); List arguments = new ArrayList<>(); arguments.add(new Argument("file-name", null, notifyTxt.getAbsolutePath(), false)); - arguments.add(new Argument("lang-class", null, "beanshell", false)); + arguments.add(new Argument("lang-class", null, "groovy", false)); arguments.add(new Argument(NotificationManager.PARAM_NODE, null, node1Id(), false)); assertEquals(0, bsfNotificationStrategy.send(arguments)); } @Test - public void nullVariablesStayDefinedInBeanshell() throws IOException { - // no -nodeid argument: node, node_label, foreign_source etc. are null; - // BSF defined them as null and scripts test them against null - File notifyBsh = tempFolder.newFile("notify-null.bsh"); - FileUtils.write(notifyBsh, "results.put(\"status\", (node == null && foreign_source == null) ? \"OK\" : \"NOT_OK\");"); + public void nullVariablesStayDefined() throws IOException { + // no -nodeid argument: node, node_label, foreign_source etc. are null. + // They must still be *defined* so scripts can test them against null, + // rather than failing with a missing-property error. + File notifyScript = tempFolder.newFile("notify-null.groovy"); + FileUtils.write(notifyScript, "results.put(\"status\", (node == null && foreign_source == null) ? \"OK\" : \"NOT_OK\")"); List arguments = new ArrayList<>(); - arguments.add(new Argument("file-name", null, notifyBsh.getAbsolutePath(), false)); + arguments.add(new Argument("file-name", null, notifyScript.getAbsolutePath(), false)); assertEquals(0, bsfNotificationStrategy.send(arguments)); } @@ -185,11 +216,11 @@ public void nullVariablesStayDefinedInBeanshell() throws IOException { public void fileNameFromSubstitutionWorks() throws IOException { // notifd passes "" as the value for switches without a notification // parameter; the command's must be honored then - File notifyBsh = tempFolder.newFile("notify-subst.bsh"); - FileUtils.write(notifyBsh, "results.put(\"status\", node.id == " + node1Id() + " ? \"OK\" : \"NOT_OK\");"); + File notifyScript = tempFolder.newFile("notify-subst.groovy"); + FileUtils.write(notifyScript, "results.put(\"status\", node.id == " + node1Id() + " ? \"OK\" : \"NOT_OK\")"); List arguments = new ArrayList<>(); - arguments.add(new Argument("file-name", notifyBsh.getAbsolutePath(), "", false)); + arguments.add(new Argument("file-name", notifyScript.getAbsolutePath(), "", false)); arguments.add(new Argument(NotificationManager.PARAM_NODE, null, node1Id(), false)); assertEquals(0, bsfNotificationStrategy.send(arguments)); @@ -230,7 +261,7 @@ public void editedGroovyScriptIsRecompiled() throws IOException { @Test public void missingScriptFileReturnsFailure() { List arguments = new ArrayList<>(); - arguments.add(new Argument("file-name", null, new File(tempFolder.getRoot(), "no-such-script.bsh").getAbsolutePath(), false)); + arguments.add(new Argument("file-name", null, new File(tempFolder.getRoot(), "no-such-script.groovy").getAbsolutePath(), false)); assertEquals(-1, bsfNotificationStrategy.send(arguments)); MockLogAppender.assertLogMatched(Level.WARN, "Cannot locate or read script file"); @@ -239,11 +270,11 @@ public void missingScriptFileReturnsFailure() { @Test public void nonOkStatusReturnsFailure() throws IOException { - File notifyBsh = tempFolder.newFile("notify-nok.bsh"); - FileUtils.write(notifyBsh, "results.put(\"status\", \"NOT_OK\");"); + File notifyScript = tempFolder.newFile("notify-nok.groovy"); + FileUtils.write(notifyScript, "results.put(\"status\", \"NOT_OK\")"); List arguments = new ArrayList<>(); - arguments.add(new Argument("file-name", null, notifyBsh.getAbsolutePath(), false)); + arguments.add(new Argument("file-name", null, notifyScript.getAbsolutePath(), false)); assertEquals(-1, bsfNotificationStrategy.send(arguments)); MockLogAppender.assertLogMatched(Level.WARN, "did not indicate successful notification"); @@ -252,11 +283,11 @@ public void nonOkStatusReturnsFailure() throws IOException { @Test public void invalidRunTypeReturnsFailure() throws IOException { - File notifyBsh = tempFolder.newFile("notify-bogus.bsh"); - FileUtils.write(notifyBsh, "results.put(\"status\", \"OK\");"); + File notifyScript = tempFolder.newFile("notify-bogus.groovy"); + FileUtils.write(notifyScript, "results.put(\"status\", \"OK\")"); List arguments = new ArrayList<>(); - arguments.add(new Argument("file-name", null, notifyBsh.getAbsolutePath(), false)); + arguments.add(new Argument("file-name", null, notifyScript.getAbsolutePath(), false)); arguments.add(new Argument("run-type", null, "bogus", false)); assertEquals(-1, bsfNotificationStrategy.send(arguments)); @@ -266,12 +297,13 @@ public void invalidRunTypeReturnsFailure() throws IOException { @Test public void deprecatedBsfEngineSwitchWarnsButStillWorks() throws IOException { - File notifyBsh = tempFolder.newFile("notify-deprecated.bsh"); - FileUtils.write(notifyBsh, "results.put(\"status\", node.id == " + node1Id() + " ? \"OK\" : \"NOT_OK\");"); + File notifyScript = tempFolder.newFile("notify-deprecated.groovy"); + FileUtils.write(notifyScript, "results.put(\"status\", node.id == " + node1Id() + " ? \"OK\" : \"NOT_OK\")"); List arguments = new ArrayList<>(); - arguments.add(new Argument("file-name", null, notifyBsh.getAbsolutePath(), false)); - arguments.add(new Argument("lang-class", null, "beanshell", false)); + arguments.add(new Argument("file-name", null, notifyScript.getAbsolutePath(), false)); + arguments.add(new Argument("lang-class", null, "groovy", false)); + // a genuine BSF-era value: it must be ignored, not acted on arguments.add(new Argument("bsf-engine", null, "bsh.util.BeanShellBSFEngine", false)); arguments.add(new Argument("file-extensions", null, "bsh", false)); arguments.add(new Argument(NotificationManager.PARAM_NODE, null, node1Id(), false)); diff --git a/pom.xml b/pom.xml index 99df2b1b9915..f2b052d72f50 100644 --- a/pom.xml +++ b/pom.xml @@ -1246,7 +1246,8 @@ asm:* org.ow2.asm:asm-all bouncycastle:* - bsh:* + bsh:* + org.apache-extras.beanshell:* c3p0:c3p0 commons-logging:* com.github.detro:* @@ -3980,11 +3981,6 @@
- - org.apache-extras.beanshell - bsh - 2.0b6 - org.mongodb bson