#!/usr/bin/perl # # $Id$ # use strict; use warnings; use Getopt::Long; use LWP; use Crypt::OpenSSL::X509; use Date::Parse; use POSIX qw(mktime); use constant { OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => 3, DEPENDENT => 4, }; use constant { IDP => 'idp', JAVA => 'java', }; my $CODE2STRING = { 0 => 'OK', 1 => 'WARNING', 2 => 'CRITICAL', 3 => 'UNKNOWN', 4 => 'DEPENDENT', }; sub get_diff { my $ts = shift; my ($sec1, $min1, $hour1, $day1, $mon1, $year1) = strptime($ts); my ($sec2, $min2, $hour2, $day2, $mon2, $year2) = gmtime(time()); my $t1 = mktime($sec1, $min1, $hour1, $day1, $mon1, $year1); my $t2 = mktime($sec2, $min2, $hour2, $day2, $mon2, $year2); return $t1 - $t2; } sub status { my $code = shift; my $message = shift; $message =~ s/\n*$//; printf("%s: %s\n", $CODE2STRING->{$code}, $message); exit $code; } my $host = undef; my $url = 'idp/status'; my $use_ssl = 0; my $max_clock_diff = 120; my $cert_warn_days = 31; my $timeout = 10; my $verbose = 0; my $memory_warn = 80; my $memory_crit = 95; my $result = GetOptions('H=s' => \$host, 'u=s' => \$url, 't=i' => \$timeout, 'S' => \$use_ssl, 'D=i' => \$max_clock_diff, 'C=i' => \$cert_warn_days, 'v' => \$verbose, 'W=i' => \$memory_warn, 'X=i' => \$memory_crit); if (!($result)) { status(UNKNOWN, 'USAGE: -H [-u ] [-t ] [-S] ' . '[-D ] [-C ] [-W ]'); } if (!defined($host)) { status(UNKNOWN, 'missing manadorty parameter -H '); } if (($memory_warn < 0) || ($memory_warn > 100)) { status(UNKNOWN, 'parameter -W (memory warning) ' . 'must be between 0 and 100'); } if (($memory_crit < 0) || ($memory_crit > 100)) { status(UNKNOWN, 'parameter -X (memory critical) ' . 'must be between 0 and 100'); } if ($memory_warn > $memory_crit) { status(UNKNOWN, 'value for memory warning must be less than ' . 'value for memory critical'); } # # arm timeout alarm # local $SIG{ALRM} = sub { status(UNKNOWN, 'check timed out'); }; alarm $timeout; $url =~ s|^/+||g; $url =~ s|/+$||g; my $idp_status_url = sprintf('%s://%s/%s', ($use_ssl ? 'https' : 'http'), $host, $url); print STDERR "IDP URL: $idp_status_url\n" if ($verbose > 0); my $browser = LWP::UserAgent->new; my $response = $browser->get($idp_status_url); if ($response->is_success) { my $code = OK; my $message = undef; my $result = {}; eval { LINE: foreach my $line (split("\r*\n", $response->content)) { if (($line =~ m/^#/) || $line eq '') { next LINE; } if ($line =~ m/^(\w+):\s+(.*?)$/g) { $result->{$1} = $2; } } }; if ($@) { status(CRITICAL, "error parsing response: " . $@); } my $time = $result->{'current_time'}; my $diff = get_diff($time); print STDERR "time: $time, difference: $diff\n" if ($verbose > 0); if (abs($diff) > $max_clock_diff) { status(CRITICAL, sprintf('clock skew too large (IDP time: %s, skew %d)', $time, $diff)); } my $mem_used = $result->{'used_memory'}; my $mem_max = $result->{'maximum_memory'}; my $mem_percentage = -1.0; if (defined($mem_used) || defined($mem_max)) { $mem_used =~ s/MB$//; $mem_max =~ s/MB$//; $mem_percentage = int(($mem_used * 10000) / $mem_max / 100); printf("memory usage %s/%s (%d%%)\n", $mem_used, $mem_max, $mem_percentage) if ($verbose > 0); if ($mem_percentage > $memory_crit) { $code = CRITICAL; $message = sprintf('IDP is low on memory (%s MB/%s MB = %d%%)', $mem_used, $mem_max, $mem_percentage); } elsif ($mem_percentage > $memory_warn) { $code = WARNING; $message = sprintf('IDP is running low on memory ' . '(%s MB/%s MB = %d%%)', $mem_used, $mem_max, $mem_percentage); } } my $versions = { IDP => $result->{'idp_version'}, JAVA => $result->{'jdk_version'}, }; my $cert = undef; eval { my $cert_data = $result->{'default_signing_tls_key'}; $cert_data =~ s/(.{64})/$1\n/gs; $cert = Crypt::OpenSSL::X509->new_from_string( sprintf("-----BEGIN CERTIFICATE-----\n%s\n" . "-----END CERTIFICATE-----\n", $cert_data)); }; if ($@) { status(UNKNOWN, "cannot parse certificate data: $@"); } print STDERR "Certificate: " . $cert->subject() . ", validUntil: " . $cert->notAfter() . "\n" if ($verbose > 0); if ($cert->checkend(0)) { $code = CRITICAL; $message = sprintf('signing certificate is expired since %s', $cert->notAfter()); } elsif ($cert->checkend($cert_warn_days * 86400)) { my $expire_days = int(get_diff($cert->notAfter()) / 86400); $code = WARNING; $message = sprintf('signing certificate expires in %d day(s)', $expire_days); } if ($code != OK) { status($code, $message); } else { status(OK, sprintf('Shibboleth IDP version %s ' . '(Java version %s, %d%% memory used)', $versions->{IDP}, $versions->{JAVA}, $mem_percentage)); } } else { my $status = $response->status_line || 'unknown'; status(CRITICAL, sprintf('error fetching status: %s', $status)); } exit OK;