node-red-nagios-nsca-send
Version:
A Node-RED node to forward to Nagios using NSCA send
211 lines (181 loc) • 8.65 kB
JavaScript
module.exports = function(RED) {
"use strict";
var exec = require('child_process').exec; // this will execute the bash command for send_nsca
function NagiosNSCASend(config) {
var node = this;
RED.nodes.createNode(node, config);
//RED.comms.publish("debug",{msg:JSON.stringify(node),format:'number'});
//console.log( "in NagiosNSCASend(config) this", JSON.stringify(node) );
//console.log( "config", JSON.stringify(config) );
/* get the config data */
node.perfname = config.perfname;
node.nagioshost = config.nagioshost;
node.nscaport = config.nscaport ? parseInt(config.nscaport, 10) : 5667; // make sure only numbers are transmitted
node.host = config.host;
node.service = config.service;
node.send_nsca_script = config.send_nsca_script;
node.send_nsca_config = config.send_nsca_config;
node.perfdata = config.perfdata;
//RED.comms.publish("debug",{msg:JSON.stringify(this),format:'number'});
this.on('input', function(msg) {
// Get the value by the type of source and return it.
function getValue( type, value ) {
// console.log("type = " + type + ", value = " + value);
switch (type) {
case 'msg' :
return parseFloat( RED.util.getMessageProperty(msg,value) ) || 0;
break;
case 'flow' :
return parseFloat( node.context().flow.get(value) ) || 0;
break;
case 'global' :
return parseFloat( node.context().global.get(value) ) || 0;
break;
case 'str' :
return parseFloat( value ) || 0;
break;
case 'num' :
return parseFloat( value ) || 0;
break;
case 'json' :
return parseFloat( JSON.parse(value) ) || 0;
break;
case 'jsonata' :
return parseFloat( value.evaluate({msg:msg}) ) || 0;
break;
default :
return null;
break;
}
}
// create the syntax for nagios performance data ranges and return it as a string
function getRange( type, low, high ) {
switch (type) {
case 'above' : // [h .. +∞]
return "~:" + high;
break;
case 'below' : // [-∞ .. l]
return "" + low + ":";
break;
case 'between' : // [l .. h]
return "@" + low + ":" + high;
break;
case 'outside' : // ]l .. h[
return "" + low + ":" + high;
break;
default:
return "";
}
};
// returns true if a given value is in a given range
function isInRange ( value, type, low, high ) {
switch (type) {
case 'above' :
return value > high;
break;
case 'below' :
return low < value;
break;
case 'between' :
return low <= value & value <= high;
break;
case 'outside' :
return value < low | high < value;
break;
default:
return "";
}
}
// returns the status calculated by the values position in the range
// priority is critical, then warning, then ok
function getStatus ( value, warn, crit ) {
if ( isInRange( value, crit.type, crit.l, crit.h ) ) {
return 2; // critical
} else if ( isInRange( value, warn.type, warn.l, warn.h ) ) {
return 1; // warning
} else {
return 0; // okay
}
}
//console.log( "in input" + JSON.stringify(node) );
//console.log( "msg.payload" + JSON.stringify(msg.payload) );
//console.log( "config"+ JSON.stringify(msg) );
//console.log( "this" + JSON.stringify(this) );
//console.log( "node.perfdata.length = " + JSON.stringify(node.perfdata.length) );
// compose the command used for transfer to nagios nsca service
var command = node.send_nsca_script
+ " -H " + node.nagioshost
+ " -p " + node.nscaport
+ " -c " + node.send_nsca_config;
var status = 0; // by default the status is ok, if the performance data does not violate the ranges of critical or warning
var service_value = []; // there is no singular value for the service, all values come with the performance data
var perfstr = ""; // by default the performance string is empty, because it is optional
if (node.perfdata.length > 0) { // if there is performance data then
var perfdatastr = [] // we create a perfdata string for each performance data
for (var i=0; i<node.perfdata.length; i++) { // for each performance data do
var perfd = node.perfdata[i]; // get the performance data
var value = getValue( perfd.value_fromt, perfd.value_from ); // get the value of the performance data
// create the key-value pair
var key_value = "'" + perfd.perfname.replace(/"/g, '\\"').replace(/['=]/g, '') + "'=" + value;
service_value.push( key_value ); // key-value-pair is used as Service output.
var wl = getValue( perfd.warn_lt, perfd.warn_l ); // get lower warning range value by type and value
var wh = getValue( perfd.warn_ht, perfd.warn_h ); // get higher warning range value by type and value
var cl = getValue( perfd.crit_lt, perfd.crit_l ); // get lower critical range value by type and value
var ch = getValue( perfd.crit_ht, perfd.crit_h ); // get higher critical range value by type and value
// compose the perfdata string for the current perfdata
// the name may be surrounded by single quotation marks followed by an equal sign
// then the value and the unit of meassure
// after that, each separated by semicolon the ranges for warning and critical state
// followed by minimal expected value and maximal expected value
// the name may not contain single quotation marks nor equal signs. Double quotes must be escaped.
var perfpart = key_value + perfd.uom + ";"
+ getRange( perfd.warn_t, wl, wh ) + ";"
+ getRange( perfd.crit_t, cl, ch ) + ";"
+ perfd.min + ";" + perfd.max;
// add it to the array
perfdatastr.push( perfpart );
// change the status if needed. Priority is critical, then warning, then ok
// getStatus gets the status based on the current performance data block
status = Math.max( status, getStatus( value, {type:perfd.warn_t,l:wl,h:wh}, {type:perfd.crit_t,l:cl,h:ch} ) );
}
// compose the whole perfomance data string. Starting with a pipe and each performance data block separated by a blank space
perfstr = "|" + perfdatastr.join(" ");
}
service_value = service_value.join(" "); // make the array a string, containing all the perfdata key and value pairs.
// compose the nsca-message for using with send_nsca
// doublequotes must be escaped
var nsca_msg = node.host.replace(/"/g, '\\"') + "\t"
+ node.service.replace(/"/g, '\\"') + "\t"
+ status + "\t"
+ service_value
+ perfstr;
// compose the whole command to be executed.
var wholecommand = "/bin/echo -e \"" + nsca_msg + "\" | " + command;
//console.log( "wholecommand = " + wholecommand );
node.log(JSON.stringify(msg.payload));
// execute the command
exec( wholecommand, function (error, stdout, stderr) {
// process the returned values
if (error !== null) {
// errors will be printed
console.log("exec error: " + error);
}
if (stdout !== "" && stdout !== null) {
// if the return on stdout is not the expected default text, print it as a warning
if (stdout !== "1 data packet(s) sent to host successfully.\n") {
node.warn(stdout);
}
}
// if there is something on the stderr then print it as an error
if (stderr !== "" && stderr !== null) {
node.error("stderr = " + stderr);
}
}
);
/* client.send(nagioshost, msg.payload, msg.nscaport || node.nscaport); */
});
/* */
}
// register the action for this node
RED.nodes.registerType("nagios-nsca-send", NagiosNSCASend);
};