/opt/opennms-pris └── requisitions | └── myRequisitionConfiguration | └── requisition.properties └── scriptsteps └── default | └── reverseDNS.groovy | └── requisitionRename.groovy | └── IgnoreNodeByCategory.groovy └── custom └── myScript.groovy
After the mapper has delivered its requitition, multiple script steps can be used to customize the result. These script steps can change the requisition initially provided by the mapper. Script steps provide a requisition as their results, which allows the chaining of script steps. Every script step has access to the latest version of the requisition. The first script step reads the requisition from the mapper. The second script step reads the requisition provided by the first script step and so on. Additionally every script step can access the configuration of PRIS and the raw result of the source. The script steps are executed by the JVM following the JSR-223 specification. Therefore all JSR-223 supported languages can be used to write script steps. By default runtimes for Groovy 2.3.3 and Beanshell 2.0b5 are provided out of the box.
Every script step has to provide a Requisition object as its result. For every request of a requisition each script step is reloaded.
Script steps are configured in the requisition.properties
for the requisition.
/opt/opennms-pris └── requisitions | └── myRequisitionConfiguration | └── requisition.properties └── scriptsteps └── default | └── reverseDNS.groovy | └── requisitionRename.groovy | └── IgnoreNodeByCategory.groovy └── custom └── myScript.groovy
### File: requisition.properties
## source configuration part
source = ...
## Run a no operation mapper
mapper = echo
# run script step
script.file = ../../scriptsteps/default/requisitionRename.groovy, ../../scriptsteps/default/IgnoreNodeByCategory.groovy
/**
* This script renames the requisition to the value in the newName variable.
* If newBuilding is set to true, each node gets the newName set as building
*/
import org.opennms.pris.model.Requisition
import org.opennms.pris.model.RequisitionNode
logger.info("starting requisitionRename.groovy")
String newName = "myNewRequisitionName"
Boolean newBuilding = false // true
requisition.setForeignSource(newName)
if (newBuilding) {
for (RequisitionNode node : requisition.getNodes()) {
node.setBuilding(newName)
}
}
logger.info("done with requisitionRename.groovy")
return requisition
/**
* This script step removes every node from the requisiton that has the "ignore" category assigned to it.
* The category match ignores case.
**/
import org.opennms.pris.model.Requisition
import org.opennms.pris.model.RequisitionNode
import org.opennms.pris.model.RequisitionCategory
import org.opennms.pris.util.RequisitionUtils
logger.info("starting IgnoreNodeByCategory.groovy")
final String IGNORE_CATEGORY = "ignore"
List <RequisitionNode> nodes = new ArrayList<>();
for (RequisitionNode node : requisition.getNodes()) {
if (RequisitionUtils.hasCategory(node, IGNORE_CATEGORY, true)) {
logger.debug("node '{}' has to be ignored", node.getForeignId())
} else {
nodes.add(node)
logger.debug("node '{}' is ok", node.getForeignId())
}
}
requisition.unsetNodes()
requisition.withNodes(nodes)
logger.info("done with IgnoreNodeByCategory.groovy")
return requisition
/**
* This script step sets the nodelabel based on a reverse dns lookup of the ip interfaces.
* It reverse dns lookups all interfaces for each node until it findes a dns name for a node.
* If a dns name was found it is set as nodelabel and no other interface of the nodes will be checked.
* If no dns name was found the nodelabel will be changed.
*/
import org.opennms.pris.model.Requisition
import org.opennms.pris.model.RequisitionNode
import org.opennms.pris.model.RequisitionInterface
logger.info("starting reverseDNS.groovy")
for (RequisitionNode node : requisition.getNodes()) {
for (RequisitionInterface myInterface : node.getInterfaces()) {
String ipAddress = myInterface.getIpAddr()
String dnsNodeLabel = InetAddress.getByName(ipAddress).getCanonicalHostName()
logger.debug("For foreignID '{}' dnsNodeLabel for IP '{}' is '{}'", node.getForeignId(), ipAddress, dnsNodeLabel)
if (!ipAddress.equals(dnsNodeLabel)) {
logger.info("Using '{}' as NodeLabel for foreignId '{}' based on IP '{}'", dnsNodeLabel, node.getForeignId(), ipAddress)
node.setNodeLabel(dnsNodeLabel)
break
}
}
}
logger.info("done with reverseDNS.groovy")
return requisition
/**
* This script forces a hard failure if the requisition is empty.
* This can avoid provisioning an empty requisition,
* including removing the existing nodes, on a failure of a source or mapper.
**/
import org.slf4j.Logger
import org.opennms.pris.model.Requisition
logger.info("starting failOnEmpty.groovy")
logger.debug("Amount of nodes in the requisition '{}'", (requisition.getNodes().size()))
if (requisition.getNodes().size() == 0) {
throw new Exception("The requisition '" + requisition.getForeignSource() + "' had no nodes. The failOnEmpty.groovy script is failing the request on purpose.")
}
logger.info("done with failOnEmpty.groovy")
return requisition
/**
* This script provides backwards compatibility with OpenNMS 1.12 in regards to Assets.
**/
import org.opennms.pris.model.Requisition
import org.opennms.pris.model.RequisitionNode
import org.opennms.pris.model.RequisitionAsset
import org.opennms.pris.util.RequisitionUtils
import org.opennms.pris.model.AssetField_1_12
import org.opennms.pris.util.AssetUtils
logger.info("starting OpenNMS_Assets_1_12.groovy")
List<RequisitionAsset> assetsToRemove = new ArrayList<>();
for (RequisitionNode node : requisition.getNodes()) {
for (RequisitionAsset asset : node.getAssets()) {
if (asset.getName().equalsIgnoreCase("managedObjectInstance") || asset.getName().equalsIgnoreCase("managedObjectType") ) {
assetsToRemove.add(asset);
logger.info("Remove from node '{}' the asset '{}' with the value '{}'", node.getNodeLabel(), asset.getName(), asset.getValue());
} else {
for (AssetField_1_12 assetField : AssetField_1_12.values()) {
if (asset.getName().equalsIgnoreCase(assetField.name())) {
String assetValue_1_12 = AssetUtils.assetStringCleaner(asset.getValue(), assetField.maxLength);
if (!assetValue_1_12.equals(asset.getValue())) {
logger.info("For node '{}' asset '{}' was changed from '{}' to '{}'" , node.getNodeLabel(), asset.getName(), asset.getValue(), assetValue_1_12)
asset.setValue(assetValue_1_12);
}
break;
}
}
}
}
node.getAssets().removeAll(assetsToRemove);
assetsToRemove = new ArrayList<>();
}
logger.info("done with OpenNMS_Assets_1_12.groovy")
return requisition
Every script step can reference variables from the runtime of PRIS. The following script shows the provided objects:
/**
* This sample script step demonstrates all objects provided by the pris runtime.
* The objects are casted to there exact type and logged.
**/
import java.nio.file.Path
import org.slf4j.Logger
import org.opennms.pris.model.Requisition
import org.opennms.pris.util.InterfaceUtils
import org.opennms.pris.config.InstanceApacheConfiguration
logger.info("starting Sample.groovy")
logger.debug("script '{}'", ((Path)script))
logger.debug("data '{}'", ((Object)data))
logger.debug("requisition '{}'", ((Requisition)requisition))
logger.debug("logger '{}'", ((Logger)logger))
logger.debug("config '{}'", ((InstanceApacheConfiguration)config))
logger.debug("config '{}'", ((InterfaceUtils)interfaceUtils))
logger.info("done with Sample.groovy")
return requisition
The following two script steps provide a mechanism to fail the requisition on purpose if the amount of nodes has changed to drastically to the previous run. The setup contains of two scripts that have to be included as script steps in order.
/**
* This script persists the amount of nodes delivered for the last request into a previousSize.txt file next to the requisition.properties.
* To configure the script provide a script.sizeChangeAbs parameter in the requisition.properties.
**/
import org.slf4j.Logger
import org.opennms.pris.model.Requisition
import javax.xml.bind.JAXBContext
import java.io.StringWriter
logger.info("starting failOnSizeChange.groovy")
String fileName = "previousSize.txt"
String sizeChangeAbsParam = "sizeChangeAbs"
logger.info("Is '{}' set in config? '{}'", sizeChangeAbsParam ,config.containsKey(sizeChangeAbsParam))
if (config.containsKey(sizeChangeAbsParam)) {
logger.info("fail on size change bigger than '{}'", config.getInt(sizeChangeAbsParam))
int sizeChangeThreshold = config.getInt(sizeChangeAbsParam)
File previousSizeFile = new File("requisitions" + File.separator + requisition.getForeignSource() + File.separator + fileName)
if (previousSizeFile.exists() && previousSizeFile.canRead()) {
int previousSize = previousSizeFile.getText('UTF-8').toInteger()
logger.info("previousSize from file is '{}'. New size is '{}'", previousSize, requisition.getNodes().size())
int sizeChange = (previousSize - requisition.getNodes().size()).abs()
if (sizeChange > sizeChangeThreshold) {
throw new Exception("The requisition '" + requisition.getForeignSource() + "' changed size by '" + sizeChange + "' nodes. The configured limit for size change is '" + sizeChangeThreshold + "' Failed on purpose.")
}
} else {
logger.info("No " + fileName + " found. Deliver requisition.")
}
}
logger.info("done with failOnSizeChange.groovy")
return requisition
The persistens of the previous requistion size is provided by the second script step of the setup.
/**
* This script persists the amount of nodes delivered for the last request into a previousSize.txt file next to the requisition.properties.
**/
import org.slf4j.Logger
import org.opennms.pris.model.Requisition
import javax.xml.bind.JAXBContext
import java.io.StringWriter
logger.info("starting persistRequisitionSize.groovy")
JAXBContext jc = JAXBContext.newInstance(Requisition)
StringWriter sw = new StringWriter()
jc.createMarshaller().marshal(requisition, sw)
String xml = sw.toString()
File file = new File("requisitions" + File.separator + requisition.getForeignSource() + File.separator + "previousSize.txt")
file.write requisition.getNodes().size() + ""
logger.info("persisted a requisition size of {}", requisition.getNodes().size())
logger.info("done with persistRequisitionSize.groovy")
return requisition