2013-04-28 18:39:35 +02:00
|
|
|
#!/usr/bin/env perl
|
|
|
|
|
|
|
|
use warnings;
|
|
|
|
use strict;
|
2014-12-11 17:32:39 +01:00
|
|
|
use HTTP::Request::Common;
|
2013-04-28 18:39:35 +02:00
|
|
|
use LWP::UserAgent;
|
2014-01-23 15:54:07 +01:00
|
|
|
use JSON;
|
2013-04-28 18:39:35 +02:00
|
|
|
use Nagios::Plugin;
|
|
|
|
use Data::Dumper;
|
|
|
|
|
2013-06-26 13:06:21 +02:00
|
|
|
my $np = Nagios::Plugin->new(
|
2015-12-16 19:12:56 +01:00
|
|
|
usage => "Usage: %s -u|--url <http://user:pass\@host:port/url> -a|--attributes <attributes> "
|
2014-09-26 19:01:12 +02:00
|
|
|
. "[ -c|--critical <thresholds> ] [ -w|--warning <thresholds> ] "
|
2014-05-16 17:39:08 +02:00
|
|
|
. "[ -e|--expect <value> ] "
|
2014-01-23 22:38:12 +01:00
|
|
|
. "[ -p|--perfvars <fields> ] "
|
2014-05-12 10:48:30 +02:00
|
|
|
. "[ -o|--outputvars <fields> ] "
|
2014-01-23 22:38:12 +01:00
|
|
|
. "[ -t|--timeout <timeout> ] "
|
|
|
|
. "[ -d|--divisor <divisor> ] "
|
2014-12-11 17:32:39 +01:00
|
|
|
. "[ -m|--metadata <content> ] "
|
2014-05-06 13:15:50 +02:00
|
|
|
. "[ -T|--contenttype <content-type> ] "
|
2014-05-06 14:42:58 +02:00
|
|
|
. "[ --ignoressl ] "
|
2017-08-30 21:30:18 +02:00
|
|
|
. "[ -A|--hattrib <value> ] "
|
|
|
|
. "[ -C|--hcon <value> ] "
|
2014-01-23 22:38:12 +01:00
|
|
|
. "[ -h|--help ] ",
|
2017-08-30 21:30:18 +02:00
|
|
|
version => '0.51',
|
2013-04-28 18:39:35 +02:00
|
|
|
blurb => 'Nagios plugin to check JSON attributes via http(s)',
|
|
|
|
extra => "\nExample: \n"
|
2014-09-26 19:01:12 +02:00
|
|
|
. "check_json.pl --url http://192.168.5.10:9332/local_stats --attributes '{shares}->{dead}' "
|
2014-05-12 10:48:30 +02:00
|
|
|
. "--warning :5 --critical :10 --perfvars '{shares}->{dead},{shares}->{live}' "
|
|
|
|
. "--outputvars '{status_message}'",
|
2013-04-28 20:30:44 +02:00
|
|
|
url => 'https://github.com/c-kr/check_json',
|
2013-04-28 18:39:35 +02:00
|
|
|
plugin => 'check_json',
|
|
|
|
timeout => 15,
|
2014-01-23 15:54:07 +01:00
|
|
|
shortname => "Check JSON status API",
|
2013-04-28 18:39:35 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
# add valid command line options and build them into your usage/help documentation.
|
|
|
|
$np->add_arg(
|
2014-01-23 22:38:12 +01:00
|
|
|
spec => 'url|u=s',
|
2015-11-28 17:34:16 +01:00
|
|
|
help => '-u, --url http://user:pass@192.168.5.10:9332/local_stats',
|
2013-04-28 18:39:35 +02:00
|
|
|
required => 1,
|
|
|
|
);
|
2014-05-12 10:48:30 +02:00
|
|
|
|
2013-04-28 18:39:35 +02:00
|
|
|
$np->add_arg(
|
2014-09-26 19:01:12 +02:00
|
|
|
spec => 'attributes|a=s',
|
|
|
|
help => '-a, --attributes {shares}->{dead},{shares}->{uptime}',
|
2013-04-28 18:39:35 +02:00
|
|
|
required => 1,
|
|
|
|
);
|
2014-05-12 10:48:30 +02:00
|
|
|
|
2013-04-28 20:30:44 +02:00
|
|
|
$np->add_arg(
|
2014-01-23 22:38:12 +01:00
|
|
|
spec => 'divisor|d=i',
|
|
|
|
help => '-d, --divisor 1000000',
|
2013-04-28 20:30:44 +02:00
|
|
|
);
|
2014-05-12 10:48:30 +02:00
|
|
|
|
2013-04-28 18:39:35 +02:00
|
|
|
$np->add_arg(
|
|
|
|
spec => 'warning|w=s',
|
2014-01-23 15:54:07 +01:00
|
|
|
help => '-w, --warning INTEGER:INTEGER . See '
|
2013-04-28 18:39:35 +02:00
|
|
|
. 'http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT '
|
|
|
|
. 'for the threshold format. ',
|
|
|
|
);
|
2014-05-12 10:48:30 +02:00
|
|
|
|
2013-04-28 18:39:35 +02:00
|
|
|
$np->add_arg(
|
|
|
|
spec => 'critical|c=s',
|
2014-01-23 15:54:07 +01:00
|
|
|
help => '-c, --critical INTEGER:INTEGER . See '
|
2013-04-28 18:39:35 +02:00
|
|
|
. 'http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT '
|
|
|
|
. 'for the threshold format. ',
|
|
|
|
);
|
2014-05-06 13:15:50 +02:00
|
|
|
|
2014-05-16 17:39:08 +02:00
|
|
|
$np->add_arg(
|
|
|
|
spec => 'expect|e=s',
|
|
|
|
help => '-e, --expect expected value to see for attribute.',
|
|
|
|
);
|
|
|
|
|
2014-01-23 15:54:07 +01:00
|
|
|
$np->add_arg(
|
|
|
|
spec => 'perfvars|p=s',
|
2014-09-26 19:01:12 +02:00
|
|
|
help => "-p, --perfvars eg. '* or {shares}->{dead},{shares}->{live}'\n "
|
2014-05-06 14:42:58 +02:00
|
|
|
. "CSV list of fields from JSON response to include in perfdata "
|
2014-01-23 15:54:07 +01:00
|
|
|
);
|
2013-04-28 18:39:35 +02:00
|
|
|
|
2014-05-12 10:48:30 +02:00
|
|
|
$np->add_arg(
|
|
|
|
spec => 'outputvars|o=s',
|
2014-09-26 19:01:12 +02:00
|
|
|
help => "-o, --outputvars eg. '* or {status_message}'\n "
|
2014-05-12 10:48:30 +02:00
|
|
|
. "CSV list of fields output in status message, same syntax as perfvars"
|
|
|
|
);
|
|
|
|
|
2014-12-11 17:32:39 +01:00
|
|
|
$np->add_arg(
|
|
|
|
spec => 'metadata|m=s',
|
|
|
|
help => "-m|--metadata \'{\"name\":\"value\"}\'\n "
|
|
|
|
. "RESTful request metadata in JSON format"
|
|
|
|
);
|
|
|
|
|
2014-05-06 13:15:50 +02:00
|
|
|
$np->add_arg(
|
|
|
|
spec => 'contenttype|T=s',
|
|
|
|
default => 'application/json',
|
2014-05-06 14:42:58 +02:00
|
|
|
help => "-T, --contenttype application/json \n "
|
|
|
|
. "Content-type accepted if different from application/json ",
|
|
|
|
);
|
2014-05-12 10:48:30 +02:00
|
|
|
|
2014-05-06 14:42:58 +02:00
|
|
|
$np->add_arg(
|
|
|
|
spec => 'ignoressl',
|
|
|
|
help => "--ignoressl\n Ignore bad ssl certificates",
|
2014-05-06 13:15:50 +02:00
|
|
|
);
|
|
|
|
|
2017-08-30 21:30:18 +02:00
|
|
|
$np->add_arg(
|
|
|
|
spec => 'hattrib|A=s',
|
|
|
|
help => "-A, --header-attrib STRING \n "
|
|
|
|
. "Additional Header attribute.",
|
|
|
|
);
|
|
|
|
$np->add_arg(
|
|
|
|
spec => 'hcon|C=s',
|
|
|
|
help => "-C, --header-content STRING \n "
|
|
|
|
. "Additional Header content.",
|
|
|
|
);
|
|
|
|
|
2014-01-23 15:54:07 +01:00
|
|
|
## Parse @ARGV and process standard arguments (e.g. usage, help, version)
|
2013-04-28 18:39:35 +02:00
|
|
|
$np->getopts;
|
2014-01-23 15:54:07 +01:00
|
|
|
if ($np->opts->verbose) { (print Dumper ($np))};
|
2013-04-28 18:39:35 +02:00
|
|
|
|
2017-10-18 13:04:38 +02:00
|
|
|
if ($np->opts->hattrib and not $np->opts->hcon) {
|
|
|
|
$np->nagios_exit(UNKNOWN,"Additional Header attribute provided without Additional Header content");
|
|
|
|
}
|
|
|
|
if ( not $np->opts->hattrib and $np->opts->hcon) {
|
|
|
|
$np->nagios_exit(UNKNOWN,"Additional Header content provided without Additional Header attribule");
|
|
|
|
}
|
|
|
|
|
2013-04-28 18:39:35 +02:00
|
|
|
## GET URL
|
|
|
|
my $ua = LWP::UserAgent->new;
|
|
|
|
|
2015-07-13 18:28:09 +02:00
|
|
|
$ua->env_proxy;
|
2014-09-29 13:34:35 +02:00
|
|
|
$ua->agent('check_json/0.5');
|
2013-06-26 13:06:21 +02:00
|
|
|
$ua->default_header('Accept' => 'application/json');
|
2017-10-18 13:04:38 +02:00
|
|
|
$ua->default_header($np->opts->hattrib => $np->opts->hcon) if ( $np->opts->hattrib and $np->opts->hcon );
|
2013-04-28 18:39:35 +02:00
|
|
|
$ua->protocols_allowed( [ 'http', 'https'] );
|
|
|
|
$ua->parse_head(0);
|
|
|
|
$ua->timeout($np->opts->timeout);
|
2014-05-06 14:42:58 +02:00
|
|
|
|
|
|
|
if ($np->opts->ignoressl) {
|
|
|
|
$ua->ssl_opts(verify_hostname => 0, SSL_verify_mode => 0x00);
|
|
|
|
}
|
|
|
|
|
2014-01-23 15:54:07 +01:00
|
|
|
if ($np->opts->verbose) { (print Dumper ($ua))};
|
2013-04-28 18:39:35 +02:00
|
|
|
|
2014-12-11 17:32:39 +01:00
|
|
|
my $response;
|
|
|
|
if ($np->opts->metadata) {
|
|
|
|
$response = $ua->request(GET $np->opts->url, 'Content-type' => 'application/json', 'Content' => $np->opts->metadata );
|
|
|
|
} else {
|
|
|
|
$response = $ua->request(GET $np->opts->url);
|
|
|
|
}
|
2013-04-28 18:39:35 +02:00
|
|
|
|
2013-04-28 20:07:31 +02:00
|
|
|
if ($response->is_success) {
|
2014-05-06 13:15:50 +02:00
|
|
|
if (!($response->header("content-type") =~ $np->opts->contenttype)) {
|
2013-04-28 20:07:31 +02:00
|
|
|
$np->nagios_exit(UNKNOWN,"Content type is not JSON: ".$response->header("content-type"));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$np->nagios_exit(CRITICAL, "Connection failed: ".$response->status_line);
|
2013-04-28 18:39:35 +02:00
|
|
|
}
|
|
|
|
|
2014-01-23 15:54:07 +01:00
|
|
|
## Parse JSON
|
2013-04-28 20:07:31 +02:00
|
|
|
my $json_response = decode_json($response->content);
|
2013-04-28 18:39:35 +02:00
|
|
|
if ($np->opts->verbose) { (print Dumper ($json_response))};
|
|
|
|
|
2014-09-26 19:01:12 +02:00
|
|
|
my @attributes = split(',', $np->opts->attributes);
|
2017-10-18 13:04:38 +02:00
|
|
|
my @warning;
|
|
|
|
if ($np->opts->warning) {
|
|
|
|
@warning = split(',', $np->opts->warning);
|
|
|
|
}
|
|
|
|
my @critical;
|
|
|
|
if ($np->opts->critical) {
|
|
|
|
@critical = split(',', $np->opts->critical);
|
|
|
|
}
|
2014-09-26 19:01:12 +02:00
|
|
|
my @divisor = $np->opts->divisor ? split(',',$np->opts->divisor) : () ;
|
|
|
|
my %attributes = map { $attributes[$_] => { warning => $warning[$_] , critical => $critical[$_], divisor => ($divisor[$_] or 0) } } 0..$#attributes;
|
|
|
|
|
|
|
|
my %check_value;
|
2014-01-23 15:54:07 +01:00
|
|
|
my $check_value;
|
2014-09-26 19:01:12 +02:00
|
|
|
my $result = -1;
|
2015-04-23 13:47:42 +02:00
|
|
|
my $resultTmp;
|
2014-01-23 15:54:07 +01:00
|
|
|
|
2014-09-26 19:01:12 +02:00
|
|
|
foreach my $attribute (sort keys %attributes){
|
|
|
|
my $check_value;
|
2016-08-15 13:40:22 +02:00
|
|
|
my $check_value_str = '$check_value = $json_response->'.$attribute;
|
2017-10-18 13:04:38 +02:00
|
|
|
|
2014-09-26 19:01:12 +02:00
|
|
|
if ($np->opts->verbose) { (print Dumper ($check_value_str))};
|
|
|
|
eval $check_value_str;
|
2014-01-23 15:54:07 +01:00
|
|
|
|
2014-09-26 19:01:12 +02:00
|
|
|
if (!defined $check_value) {
|
|
|
|
$np->nagios_exit(UNKNOWN, "No value received");
|
|
|
|
}
|
2013-04-28 18:39:35 +02:00
|
|
|
|
2014-09-26 19:01:12 +02:00
|
|
|
if ($attributes{$attribute}{'divisor'}) {
|
|
|
|
$check_value = $check_value/$attributes{$attribute}{'divisor'};
|
2013-04-28 20:30:44 +02:00
|
|
|
}
|
|
|
|
|
2014-05-16 17:39:08 +02:00
|
|
|
if (defined $np->opts->expect && $np->opts->expect ne $check_value) {
|
|
|
|
$np->nagios_exit(CRITICAL, "Expected value (" . $np->opts->expect . ") not found. Actual: " . $check_value);
|
2014-09-26 19:01:12 +02:00
|
|
|
}
|
2013-04-28 20:30:44 +02:00
|
|
|
|
2015-04-23 13:47:42 +02:00
|
|
|
if ( $check_value eq "true" or $check_value eq "false" ) {
|
|
|
|
if ( $check_value eq "true") {
|
|
|
|
$resultTmp = 0;
|
|
|
|
if ($attributes{$attribute}{'critical'} eq 1 or $attributes{$attribute}{'critical'} eq "true") {
|
|
|
|
$resultTmp = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ($attributes{$attribute}{'warning'} eq 1 or $attributes{$attribute}{'warning'} eq "true") {
|
|
|
|
$resultTmp = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( $check_value eq "false") {
|
|
|
|
$resultTmp = 0;
|
|
|
|
if ($attributes{$attribute}{'critical'} eq 0 or $attributes{$attribute}{'critical'} eq "false") {
|
|
|
|
$resultTmp = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ($attributes{$attribute}{'warning'} eq 0 or $attributes{$attribute}{'warning'} eq "false") {
|
|
|
|
$resultTmp = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$resultTmp = $np->check_threshold(
|
|
|
|
check => $check_value,
|
|
|
|
warning => $attributes{$attribute}{'warning'},
|
|
|
|
critical => $attributes{$attribute}{'critical'}
|
|
|
|
);
|
|
|
|
}
|
2014-09-26 19:01:12 +02:00
|
|
|
$result = $resultTmp if $result < $resultTmp;
|
|
|
|
|
|
|
|
$attributes{$attribute}{'check_value'}=$check_value;
|
|
|
|
}
|
2014-01-23 15:54:07 +01:00
|
|
|
|
2014-01-23 22:38:12 +01:00
|
|
|
my @statusmsg;
|
2014-01-23 15:54:07 +01:00
|
|
|
|
2014-09-26 19:01:12 +02:00
|
|
|
|
2014-01-23 15:54:07 +01:00
|
|
|
# routine to add perfdata from JSON response based on a loop of keys given in perfvals (csv)
|
|
|
|
if ($np->opts->perfvars) {
|
2014-11-05 16:04:56 +01:00
|
|
|
foreach my $key ($np->opts->perfvars eq '*' ? map { "{$_}"} sort keys %$json_response : split(',', $np->opts->perfvars)) {
|
2014-01-23 15:54:07 +01:00
|
|
|
# use last element of key as label
|
|
|
|
my $label = (split('->', $key))[-1];
|
2014-01-23 22:38:12 +01:00
|
|
|
# make label ascii compatible
|
2014-01-23 15:54:07 +01:00
|
|
|
$label =~ s/[^a-zA-Z0-9_-]//g ;
|
2014-01-23 23:46:19 +01:00
|
|
|
my $perf_value;
|
2017-10-18 13:04:38 +02:00
|
|
|
$perf_value = eval('$json_response->'.$key);
|
2014-01-23 23:46:19 +01:00
|
|
|
if ($np->opts->verbose) { print Dumper ("JSON key: ".$label.", JSON val: " . $perf_value) };
|
|
|
|
if ( defined($perf_value) ) {
|
2014-01-23 22:38:12 +01:00
|
|
|
# add threshold if attribute option matches key
|
2014-09-26 19:01:12 +02:00
|
|
|
if ($attributes{$key}) {
|
|
|
|
push(@statusmsg, "$label: $attributes{$key}{'check_value'}");
|
2014-01-23 22:38:12 +01:00
|
|
|
$np->add_perfdata(
|
|
|
|
label => lc $label,
|
2014-09-26 19:01:12 +02:00
|
|
|
value => $attributes{$key}{'check_value'},
|
|
|
|
threshold => $np->set_thresholds( warning => $attributes{$key}{'warning'}, critical => $attributes{$key}{'critical'}),
|
2014-01-23 22:38:12 +01:00
|
|
|
);
|
|
|
|
} else {
|
2014-01-23 23:46:19 +01:00
|
|
|
push(@statusmsg, "$label: $perf_value");
|
2014-01-23 22:38:12 +01:00
|
|
|
$np->add_perfdata(
|
|
|
|
label => lc $label,
|
2014-01-23 23:46:19 +01:00
|
|
|
value => $perf_value,
|
2017-10-18 13:04:38 +02:00
|
|
|
);
|
2014-01-23 22:38:12 +01:00
|
|
|
}
|
2014-01-23 15:54:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-05-01 15:01:23 +02:00
|
|
|
|
2017-10-18 13:04:38 +02:00
|
|
|
sub process_wildcard{
|
|
|
|
my($key,$json_response) = @_;
|
|
|
|
|
|
|
|
if ($np->opts->verbose) { (print "DEBUG: handling wildcard on key ". $key. "\n"); }
|
|
|
|
my @parts;
|
|
|
|
my @result;
|
|
|
|
if ($key !~ /\*/) {
|
|
|
|
$Data::Dumper::Terse = 1;
|
|
|
|
$Data::Dumper::Indent = 0;
|
|
|
|
if ($np->opts->verbose) { (print "DEBUG: Now checking: ". $key. " against: ". Dumper($json_response)."\n")};
|
|
|
|
my $output_value = Dumper(eval('$json_response->'.$key));
|
|
|
|
$Data::Dumper::Terse = 0;
|
|
|
|
$Data::Dumper::Indent = 1;
|
|
|
|
return $output_value;
|
|
|
|
} else {
|
|
|
|
@parts = split(/->[\{\[]?\*[\}\]]?->/,$key,2);
|
|
|
|
my $part1 = $parts[0];
|
|
|
|
my $part2 = $parts[1];
|
|
|
|
if ($np->opts->verbose) { (print "DEBUG: processing first part before wildcard: ". $part1 . "\n"); }
|
|
|
|
my $c = eval('$json_response->'.$part1);
|
|
|
|
return if (! $c);
|
|
|
|
if ($np->opts->verbose) { (print "DEBUG: process_wildcard: Fount childs: ".Dumper($c)."\n")};
|
|
|
|
foreach my $v (values($c)){
|
|
|
|
my $r = process_wildcard($part2,$v);
|
|
|
|
push(@result,$r) if $r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return @result;
|
|
|
|
}
|
|
|
|
|
2014-05-12 10:48:30 +02:00
|
|
|
# output some vars in message
|
|
|
|
if ($np->opts->outputvars) {
|
2014-11-05 16:04:56 +01:00
|
|
|
foreach my $key ($np->opts->outputvars eq '*' ? map { "{$_}"} sort keys %$json_response : split(',', $np->opts->outputvars)) {
|
2014-05-12 10:48:30 +02:00
|
|
|
# use last element of key as label
|
|
|
|
my $label = (split('->', $key))[-1];
|
2017-10-18 13:04:38 +02:00
|
|
|
# make label ascii compatible i.e. remove the { and }
|
2014-05-12 10:48:30 +02:00
|
|
|
$label =~ s/[^a-zA-Z0-9_-]//g;
|
2015-12-16 20:27:40 +01:00
|
|
|
my $output_value;
|
2017-10-18 13:04:38 +02:00
|
|
|
## Handle case of wildcard in the middle of the tree: {data}->*->{description}
|
|
|
|
$output_value = join(", ",process_wildcard($key,$json_response));
|
2015-12-16 20:27:40 +01:00
|
|
|
push(@statusmsg, "$label: $output_value");
|
2014-05-12 10:48:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-28 18:39:35 +02:00
|
|
|
$np->nagios_exit(
|
2013-05-01 15:01:23 +02:00
|
|
|
return_code => $result,
|
2017-10-18 13:04:38 +02:00
|
|
|
message => join('; ', @statusmsg),
|
2013-04-28 18:39:35 +02:00
|
|
|
);
|