#!/usr/local/bin/perl -w # # Papercut health monitoring # # By Igor V. Gubenko (igubenko@Princeton.EDU), 08/03/2016 # # The program requires the JSON, REST::Client, and Try:Tiny libraries # Data::Dumper is for debugging, and is not required for normal operation # # The program assumes that HTML output is desired. If this is not the case, light modification (commenting out) of HTML markup is needed # Nagios requires "escape_html_tags=0" in cgi.cfg for HTML output # # Released under BSD 2-clause license # use strict; use warnings; use JSON; use REST::Client; use Data::Dumper; use Try::Tiny; # printserv => hostname or fqdn of the Papercut server # apikey => the apikey of Papercut installation # what => what to check - any of the keys of %queries below # whatarg => unused for now my ($printserv, $apikey, $what, $whatarg) = @ARGV; my ($respcode, $data); unless (@ARGV > 2) { print STDERR "Usage: $0 {printserv} {api_auth_key} {health|printers_in_error|printer_urls|device_urls|sixtyminutes|queue|sysinfo}\n"; exit (2); } # Associates queries with corresponding URLs my %queries = ( health => 'https://' . $printserv . ':9192/api/health/status?Authorization=' . $apikey, printers_in_error => 'https://' . $printserv . ':9192/api/health/printers/status?in-error-threshold=50&Authorization=' . $apikey, printer_urls => 'https://' . $printserv . ':9192/api/health/printers/urls?Authorization=' . $apikey, device_urls => 'https://' . $printserv . ':9192/api/health/devices/urls?Authorization=' . $apikey, sixtyminutes => 'https://' . $printserv . ':9192/api/stats/recent-pages-count?minutes=60&Authorization=' . $apikey, queue => 'https://' . $printserv . ':9192/api/stats/held-jobs-count?Authorization=' . $apikey, sysinfo => 'https://' . $printserv . ':9192/api/health?Authorization=' . $apikey, ); # Associates the functions to run to parse each query type my %functions; foreach (keys %queries) { $functions{$_} = \&$_; } ## In all of the functions below, if $data is not a hash, then we assume that $data is a string, and simply return it for output sub health { return (ref $data eq ref {}) ? (exists $data->{message} ? $data->{message} : $data->{comment}) . "\n" : $data; } sub printers_in_error { return (ref $data eq ref {}) ? (exists $data->{message} ? $data->{message} : $data->{comment}) . "\n" : $data; } sub printer_urls { # return (ref $data eq ref {}) ? $data->{printer_urls} . "\n" : $data; if (ref $data eq ref {}) { return ""; } else { # Remove the Unicode character $data =~ s/^\x{ef}\x{bb}\x{bf}//; my @rows = split /\n/, $data; # Create HTML table markups for nice output $data = ""; foreach (@rows) { my @cols = split /,/; $data = $data . ""; } $data .= "
" . join ("", @cols[0,1,2]) . "
"; return $data; } } sub device_urls { return (ref $data eq ref {}) ? $data->{device_urls} . "\n" : $data; } sub sixtyminutes { return (ref $data eq ref {}) ? "In the last 60 minutes there were " . $data->{recentPagesCount} . " pages printed\n" : $data; } sub queue { return (ref $data eq ref {}) ? "There are " . $data->{heldJobsCount} . " jobs currently held for release\n" : $data; } sub sysinfo { if (ref $data eq ref {}) { # Create nice, indented JSON output my $jsonny = JSON->new; my $jpretty = $jsonny->pretty->encode($data); # Replace newlines with HTML line breaks $jpretty =~ s#\n#
#g; # Replace each space with 2 HTML spaces for nice indent $jpretty =~ s#\s#\ \ #g; return $jpretty . "\n"; } return $data; } ### This is for reference # health => Status summary: primary health check #curl -k 'https://ss219w:9192/api/health/status?Authorization=apikey' # printers_in_error => Status summary: alert if >1 printers are in error #curl -k 'https://ss219w:9192/api/health/printers/status?in-error-threshold=1&Authorization=apikey' # printer_urls => Status per printer: display printer status URL's #curl -k 'https://ss219w:9192/api/health/printers/urls?Authorization=apikey' # device_urls => Status per device: display device status URL's #curl -k 'https://ss219w:9192/api/health/devices/urls?Authorization=apikey' # sixtyminutes => Real time system stats: pages printed in the last 60 minutes #curl -k 'https://ss219w:9192/api/stats/recent-pages-count?minutes=60&Authorization=apikey' # queue => Real time system stats: # of jobs in hold/release queue #curl -k 'https://ss219w:9192/api/stats/held-jobs-count?Authorization=apikey' # sysinfo => Detailed system info #curl -k 'https://ss219w:9192/api/health?Authorization=apikey' # Don't verify SSL hostname in case the certificate is self-signed $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0; my $client = REST::Client->new(); # Retrieve the relevant query using a REST client, since the output is almost always JSON $client -> GET ($queries{$what}); #print $client->responseCode, "\n"; #print $client->responseContent, "\n"; $respcode = $client->responseCode; try { # Try to decode the JSON into a hash $data = decode_json($client->responseContent); #print Dumper ($data); } catch { # Unable to decode JSON - take the response as a string $data = $client->responseContent; }; # Run the relevant parsing function print $functions{$what}(); # Depending on the HTTP return code, we return either OK or CRITICAL $respcode = ($respcode eq '200') ? 0 : 2; exit ($respcode);