From 6530f60597ee7b91bfb3e9a1b6ccb64587771a6a Mon Sep 17 00:00:00 2001 From: Michael Howe Date: Sun, 24 Dec 2023 17:27:51 +0000 Subject: [PATCH] Add check_json plugin --- debian/changelog | 6 + debian/control | 3 + debian/nagios-plugins-local-server.install | 1 + plugins/check_json | 288 +++++++++++++++++++++ 4 files changed, 298 insertions(+) create mode 100755 plugins/check_json diff --git a/debian/changelog b/debian/changelog index 95480a7..02bda5f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nagios-plugins-local (0.28) unstable; urgency=medium + + * Add check_json from https://github.com/RustyDust/check_json/ + + -- Michael Howe Sun, 24 Dec 2023 17:27:41 +0000 + nagios-plugins-local (0.27+rebuild.0) unstable; urgency=medium * Bump version to fix package/upload issues diff --git a/debian/control b/debian/control index 5a463e0..82e756c 100644 --- a/debian/control +++ b/debian/control @@ -25,6 +25,9 @@ Depends: ${misc:Depends}, nagios-plugins-local-client (= ${source:Version}) , python3-requests , python3-paho-mqtt + , libjson-perl + , libmonitoring-plugin-perl + , libwww-perl Breaks: nagios-plugins-local (<0.11) Description: Local nagios plugins Nagios plugins for use on the michaelhowe.org nagios host. diff --git a/debian/nagios-plugins-local-server.install b/debian/nagios-plugins-local-server.install index 0e0383a..b878fad 100644 --- a/debian/nagios-plugins-local-server.install +++ b/debian/nagios-plugins-local-server.install @@ -3,3 +3,4 @@ /usr/lib/nagios/plugins/check_ldaps_ip /usr/lib/nagios/plugins/check_owntracks /usr/lib/nagios/plugins/check_mqtt +/usr/lib/nagios/plugins/check_json diff --git a/plugins/check_json b/plugins/check_json new file mode 100755 index 0000000..9830e80 --- /dev/null +++ b/plugins/check_json @@ -0,0 +1,288 @@ +#!/usr/bin/env perl +# +# From https://github.com/RustyDust/check_json/ + +use warnings; +use strict; +use HTTP::Request::Common; +use LWP::UserAgent; +use JSON; +use Monitoring::Plugin; +use Data::Dumper; + +my $np = Monitoring::Plugin->new( + usage => "Usage: %s -u|--url -a|--attributes " + . "[ -c|--critical ] [ -w|--warning ] " + . "[ -e|--expect ] " + . "[ -p|--perfvars ] " + . "[ -o|--outputvars ] " + . "[ -t|--timeout ] " + . "[ -d|--divisor ] " + . "[ -m|--metadata ] " + . "[ -T|--contenttype ] " + . "[ --ignoressl ] " + . "[ -x|--xauth ] " + . "[ -b|--bearer ] " + . "[ -h|--help ] ", + version => '0.5', + blurb => 'Nagios plugin to check JSON attributes via http(s)', + extra => "\nExample: \n" + . "check_json.pl --url http://192.168.5.10:9332/local_stats --attributes '{shares}->{dead}' " + . "--warning :5 --critical :10 --perfvars '{shares}->{dead},{shares}->{live}' " + . "--outputvars '{status_message}' -b ", + url => 'https://github.com/c-kr/check_json', + plugin => 'check_json', + timeout => 15, + shortname => "Check JSON status API", +); + + # add valid command line options and build them into your usage/help documentation. +$np->add_arg( + spec => 'url|u=s', + help => '-u, --url http://user:pass@192.168.5.10:9332/local_stats', + required => 1, +); + +$np->add_arg( + spec => 'attributes|a=s', + help => '-a, --attributes {shares}->{dead},{shares}->{uptime}', + required => 1, +); + +$np->add_arg( + spec => 'divisor|d=i', + help => '-d, --divisor 1000000', +); + +$np->add_arg( + spec => 'warning|w=s', + help => '-w, --warning INTEGER:INTEGER . See ' + . 'http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT ' + . 'for the threshold format. ', +); + +$np->add_arg( + spec => 'critical|c=s', + help => '-c, --critical INTEGER:INTEGER . See ' + . 'http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT ' + . 'for the threshold format. ', +); + +$np->add_arg( + spec => 'expect|e=s', + help => '-e, --expect expected value to see for attribute.', +); + +$np->add_arg( + spec => 'perfvars|p=s', + help => "-p, --perfvars eg. '* or {shares}->{dead},{shares}->{live}'\n " + . "CSV list of fields from JSON response to include in perfdata " +); + +$np->add_arg( + spec => 'outputvars|o=s', + help => "-o, --outputvars eg. '* or {status_message}'\n " + . "CSV list of fields output in status message, same syntax as perfvars" +); + +$np->add_arg( + spec => 'metadata|m=s', + help => "-m|--metadata \'{\"name\":\"value\"}\'\n " + . "RESTful request metadata in JSON format" +); + +$np->add_arg( + spec => 'contenttype|T=s', + default => 'application/json', + help => "-T, --contenttype application/json \n " + . "Content-type accepted if different from application/json ", +); + +$np->add_arg( + spec => 'ignoressl', + help => "--ignoressl\n Ignore bad ssl certificates", +); + +$np->add_arg( + spec => 'xauth|x=s', + help => "-x|--xauth\n Use X-Auth-Token in header", +); + +$np->add_arg( + spec => 'bearer|b=s', + help => "-b|--bearer\n Use Bearer Token authentication in header", +); + +## Parse @ARGV and process standard arguments (e.g. usage, help, version) +$np->getopts; +if ($np->opts->verbose) { (print Dumper ($np))}; + +## GET URL +my $ua = LWP::UserAgent->new; +$ua->env_proxy; +$ua->agent('check_json/0.5'); +$ua->default_header('Accept' => 'application/json'); +$ua->protocols_allowed( [ 'http', 'https'] ); +$ua->parse_head(0); +$ua->timeout($np->opts->timeout); + +if ($np->opts->xauth) { + $ua->default_header('Accept' => 'application/json', 'X-Auth-Token' => $np->opts->xauth ); +} + +if ($np->opts->bearer) { + $ua->default_header('Accept' => 'application/json', 'Authorization' => 'Bearer ' . $np->opts->bearer ); +} + +if ($np->opts->ignoressl) { + $ua->ssl_opts(verify_hostname => 0, SSL_verify_mode => 0x00); +} + +if ($np->opts->verbose) { (print Dumper ($ua))}; + +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); +} + +if ($response->is_success) { + if (!($response->header("content-type") =~ $np->opts->contenttype)) { + $np->nagios_exit(UNKNOWN,"Content type is not JSON: ".$response->header("content-type")); + } +} else { + $np->nagios_exit(CRITICAL, "Connection failed: ".$response->status_line); +} + +## Parse JSON +my $json_response = decode_json($response->content); +if ($np->opts->verbose) { (print Dumper ($json_response))}; + +my @attributes = split(',', $np->opts->attributes); +my @warning = split(',', $np->opts->warning); +my @critical = split(',', $np->opts->critical); +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; +my $check_value; +my $result = -1; +my $resultTmp; + +foreach my $attribute (sort keys %attributes){ + my $check_value; + my $check_value_str = '$check_value = $json_response->'.$attribute; + + if ($np->opts->verbose) { (print Dumper ($check_value_str))}; + eval $check_value_str; + + if (!defined $check_value) { + $np->nagios_exit(UNKNOWN, "No value received"); + } + + if ($attributes{$attribute}{'divisor'}) { + $check_value = $check_value/$attributes{$attribute}{'divisor'}; +} + +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); + } + + 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'} + ); + } + $result = $resultTmp if $result < $resultTmp; + + $attributes{$attribute}{'check_value'}=$check_value; +} + +my @statusmsg; + + +# routine to add perfdata from JSON response based on a loop of keys given in perfvals (csv) +if ($np->opts->perfvars) { + foreach my $key ($np->opts->perfvars eq '*' ? map { "{$_}"} sort keys %$json_response : split(',', $np->opts->perfvars)) { + # use last element of key as label + my $label = (split('->', $key))[-1]; + # make label ascii compatible + $label =~ s/[^a-zA-Z0-9_-]//g ; + + my $perf_value; + my $perf_value_str = '$perf_value = $json_response->'.$key; + # $perf_value = $json_response->{$key}; + eval $perf_value_str; + + if ($np->opts->verbose) { print Dumper ("JSON key: ".$label.", JSON val: " . $perf_value) }; + if ( defined($perf_value) ) { + # add threshold if attribute option matches key + if ($attributes{$key}) { + push(@statusmsg, "$label: $attributes{$key}{'check_value'}"); + $np->add_perfdata( + label => lc $label, + value => $attributes{$key}{'check_value'}, + threshold => $np->set_thresholds( warning => $attributes{$key}{'warning'}, critical => $attributes{$key}{'critical'}), + ); + } else { + push(@statusmsg, "$label: $perf_value"); + $np->add_perfdata( + label => lc $label, + value => $perf_value, + ); + } + } + } +} + +# output some vars in message +if ($np->opts->outputvars) { + foreach my $key ($np->opts->outputvars eq '*' ? map { "{$_}"} sort keys %$json_response : split(',', $np->opts->outputvars)) { + # use last element of key as label + my $label = (split('->', $key))[-1]; + # make label ascii compatible + $label =~ s/[^a-zA-Z0-9_-]//g; + my $output_value; + my $output_value_str = '$output_value = $json_response->'.$key; + eval $output_value_str; + # $output_value = $json_response->{$key}; + if ( defined($output_value) ){ + push(@statusmsg, "$label: $output_value"); + } + } +} + +$np->nagios_exit( + return_code => $result, + message => join(', ', @statusmsg), +); -- 2.39.5