Created
September 21, 2012 09:17
-
-
Save n8v/3760536 to your computer and use it in GitHub Desktop.
Sample Nagios plugin to check # of Facebook friends.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
/* -*- js2 -*- */ | |
var util = require('util'); | |
/* ************************************************************* */ | |
// Set up classes to support Range objects. Ported from | |
// Nagios::Plugin::Range. See named functions below. | |
// TODO: Modularize properly/idiomatically. | |
/* | |
* Represents a Nagios plugin range object. | |
* @constructor | |
* */ | |
function Range(start, end, alert_on_outside) { | |
this.start = start; | |
this.end = end; | |
this.alert_on_outside = alert_on_outside; | |
} | |
Range.prototype = { | |
toString: RangeToString, | |
check: RangeCheck | |
}; | |
/* ************************************************************* */ | |
/* | |
* Get command line parameters. | |
* */ | |
var plugin_name = 'CHECK_FB_FRIENDS'; | |
// Set up command line args and usage etc using commander.js. | |
var cli = require('commander'); | |
cli | |
.version('0.0.1') | |
.option('-u, --user <username or id>', 'REQUIRED. Facebook vanity username or id# of the user to check.') | |
.option('-c, --critical <critical threshold>', 'Critical threshold using standard format. @8 == CRITICAL if --user has less than 8 friends.', parseRangeString) | |
.option('-w, --warning <warning threshold>', 'Warning threshold using standard format', parseRangeString) | |
.parse(process.argv); | |
if (! cli.user) { | |
nagios_exit(plugin_name, 'UNKNOWN', 'SYNTAX ERROR: -u / --user parameter required!'); | |
} | |
// There are almost a billion facebook modules for Node. Using DracoBlue's, | |
// https://github.com/DracoBlue/node-facebook-client | |
// installed with | |
// npm install -g facebook-client | |
var FacebookClient = require("facebook-client").FacebookClient; | |
// var FacebookClient = require("./node-facebook-client").FacebookClient; // Local git checkout for hacking | |
// First I went to https://developers.facebook.com/apps and set up a New App. It gave me these values: | |
// NJVNagiosTestApp | |
// App ID: 287316424715230 | |
// App Secret: 16628ab43bf3ce6878501ba885c69f16(reset) | |
// I also had to make it ask for user_relationships permissions, and I | |
// had to go to the app and give it those permissions. | |
var facebook_client = new FacebookClient( | |
"287316424715230", | |
"16628ab43bf3ce6878501ba885c69f16", | |
{ | |
"timeout": 10000 // modify the global timeout for facebook calls (Default: 10000) | |
} | |
); | |
var fb_user = cli.user; | |
// See Authenticating as an App: | |
// http://developers.facebook.com/docs/authentication/applications/ | |
// https://graph.facebook.com/oauth/access_token? | |
// client_id=YOUR_APP_ID | |
// &client_secret=YOUR_APP_SECRET | |
// &grant_type=client_credentials | |
// e.g. https://graph.facebook.com/oauth/access_token?client_id=287316424715230&client_secret=16628ab43bf3ce6878501ba885c69f16&grant_type=client_credentials | |
// VERY IMPORTANT: I had trouble granting permission from my user to my | |
// app, but I found how by clicking on stuff in the Access Token Tool at | |
// https://developers.facebook.com/tools/access_token/ | |
var token = ''; | |
facebook_client.getAccessToken({grant_type: 'client_credentials'})(function(newtoken, expires) { | |
// console.log('got access token', newtoken, expires); | |
token = newtoken; | |
// You could also paste a temporary token like this from the Graph API Explorer, but it will expire. | |
// token = 'AAACEdEose0cBAMQbCfjwq3Uok32iJ266jt7Tq5w2jh6tJkFfmUv8nPeIwBWjFit1hanbZBdKH3wkRPGdr0wd78tTZBBu5Djf46ZAWs2yVkXxKMBEdMk'; | |
facebook_client.getSessionByAccessToken(token)(function(facebook_session) { | |
// session is either undefined or a valid FacebookSession | |
if (facebook_session) { | |
// console.log('Got session.'); | |
facebook_session.graphCall("/" + fb_user + "/friends", { | |
// facebook_session.graphCall("/" + fb_user, { | |
})(function(result) { | |
if (result && result.data) { | |
num_friends = result.data.length; | |
var message = util.format("%s has %d friends from %s to %s", | |
cli.user, | |
num_friends, | |
result.data[0].name, | |
result.data[num_friends -1].name); | |
var perfdata = "'Friends'=" + num_friends + ';' + cli.warning + ';' + cli.critical + ';'; | |
if (cli.critical && cli.critical.check(num_friends)) { | |
nagios_exit(plugin_name, "CRITICAL", message, perfdata); | |
} | |
else if (cli.warning && cli.warning.check(num_friends)) { | |
nagios_exit(plugin_name, "WARNING", message, perfdata); | |
} | |
else { | |
nagios_exit(plugin_name, "OK", message, perfdata); | |
} | |
} | |
else { | |
var wtf = util.format('WTF result: %j', result); | |
nagios_exit(plugin_name, 'UNKNOWN', wtf); | |
} | |
}); | |
} | |
else { | |
nagios_exit(plugin_name, 'UNKNOWN', 'FAIL getting Facebook session'); | |
} | |
}); | |
}); | |
/* ************************************************************* */ | |
/* | |
* Standard stringification a la | |
* http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT | |
* | |
* E.g. @10:~ means "outside the range 10 to Infinity" | |
*/ | |
function RangeToString() { | |
return ( this.alert_on_outside ? '' : '') + | |
(this.start == Number.NEGATIVE_INFINITY ? '~' : this.start) + | |
':' + | |
(this.end == Infinity ? '' : this.end) ; | |
}; | |
/* | |
* Returns true if an alert should be raised (the value is outside | |
* of the range).a | |
* | |
* @param v Number The value to be checked. | |
* @return boolean | |
*/ | |
function RangeCheck (v) { | |
var alerty = false || ! this.alert_on_outside; | |
if (this.start <= v && v <= this.end) { | |
return alerty; | |
} | |
else { | |
return ! alerty; | |
} | |
} | |
/* | |
* See | |
* http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT | |
* | |
* @param t String The string with a range definition. | |
*/ | |
function parseRangeString(t) { | |
var start = 0; | |
var end = Number.POSITIVE_INFINITY; | |
var alert_on_outside = true; | |
var valid = false; | |
// console.log('parsing Range %j', t); | |
// Strip whitespace. | |
t = t.toString().replace(/\s/g, ''); | |
// Validate | |
if ( ! /[\d~]/.test(t) || | |
! /^\@?(-?[\d.]+|~)?(:(-?[\d.]+)?)?$/.test(t) | |
) { | |
console.error('Invalid range definition %j', t); | |
process.exit(3); | |
} | |
if ( /^@/.test(t) ) { | |
alert_on_outside = false; | |
t = t.substring(1); | |
} | |
if ( /^~:/.test(t) ) { // '~:x' | |
start = Number.NEGATIVE_INFINITY; | |
t = t.substring(2); | |
valid = true; | |
} | |
var m = t.match(/^([\d\.-]+)?:/); // '10:' | |
if (m != null ) { | |
start = m[1]; | |
t = t.replace(/^([-\d\.]+)?:/, ''); | |
valid = true; | |
} | |
m = t.match(/^([-\d\.]+)$/); // 'x:10' or '10' | |
if (m != null ) { | |
end = m[1]; | |
valid = true; | |
} | |
if (valid && start <= end) { | |
return new Range(start, end, alert_on_outside); | |
} | |
else { | |
console.error('Invalid range definition %j', t); | |
process.exit(3); | |
} | |
return null; | |
} | |
// End Range stuff | |
/* | |
* Exit the plugin with Nagios specified output. See | |
* http://nagiosplug.sourceforge.net/developer-guidelines.html#PLUGOUTPUT | |
* | |
* @param plugin_name String The name of the plugin e.g. 'CHECK_STUFF'. | |
* @param state String "OK", "WARNING", "CRITICAL" or defaults to "UNKNOWN". | |
* @param message String Human-readable message. | |
* @param perfdata String Nagios formatted perfomance data string. | |
*/ | |
function nagios_exit (plugin_name, state, message, perfdata) { | |
var exit_code, valid_state; | |
switch (state.toUpperCase()) { | |
case 'CRITICAL': | |
valid_state = state; | |
exit_code = 2; | |
break; | |
case 'WARNING': | |
valid_state = state; | |
exit_code = 1; | |
break; | |
case 'OK': | |
valid_state = state; | |
exit_code = 0; | |
break; | |
default: | |
valid_state = 'UNKNOWN'; | |
exit_code = 3; | |
} | |
console.log(plugin_name + ' ' + valid_state + ':' + message + '|' + perfdata); | |
process.exit(exit_code); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment