#!/usr/bin/perl -w
#
# Nagios plugin to return a WARNING if a newer kernel package is available 
#   than the kernel that is running.
#

use strict;
use File::Basename;
BEGIN {
  use lib dirname($0);
  use Nagios::Plugin;
}

my $VERSION = '0.2 [http://www.openfusion.com.au/labs/nagios/]';

my $USAGE = qq(usage: %s [--pkg <pkgmgr>] [-v]\n);
my $pkg = 'rpm';
my @SPEC = (
  "pkg|p" => [ \$pkg, 
  q(-p, --pkg
   Package manager to use to locate alternative kernels.
   Currently only 'rpm' is supported.) ],
);

# ----------------------------------------------------------------------------
# Subroutines

# Canonicalise version numbers to work around bad numeric comparisons
sub canonical
{
  my $version = shift;
  my @canonical = ();
  for my $comp (split /\W+/, $version) {
    if ($comp =~ m/^(\d+)(.*?)/) {
      push @canonical, sprintf "%03d%s", $1, $2;
    }
  }
  return join '.', @canonical;
}

# ----------------------------------------------------------------------------

parse_args(
  version => $VERSION,
  usage => $USAGE,
  spec => \@SPEC,
);

# Exit with an error if we're not on Linux
&exit("UNKNOWN", "$plugin only works on Linux") unless $^O eq 'linux';

alarm($timeout);

# Get current kernel version
my $CURRENT = `uname -r`;
chomp $CURRENT;
exit("UNKNOWN", "cannot determine current kernel version ('$CURRENT')")
  unless $CURRENT;
my $CANONICAL = canonical($CURRENT);
print STDERR "+ current kernel: $CURRENT (canonical $CANONICAL)\n" 
  if $verbose;

# Get available packages
my ($AVAILABLE, $prefix);
if (lc $pkg eq 'rpm') {
  my $kernel = 'kernel';
  $kernel .= '-smp' if $CURRENT =~ m/smp$/;
  $AVAILABLE = "rpm -q $kernel";
  $prefix = "$kernel-";
}
else {
  &exit("UNKNOWN", "unsupported pkg manager '$pkg'");
}

exit("UNKNOWN", "no output from '$AVAILABLE': $!") 
  unless open QUERY, "$AVAILABLE|";
my @avail = <QUERY>;
close QUERY;
chomp foreach @avail;
exit("UNKNOWN", "no output from '$AVAILABLE'") unless @avail;
if ($prefix) {
  s/^$prefix// foreach @avail;
}
print STDERR "+ available kernels:\n  " . join("\n  ",@avail) . "\n" if $verbose;
my %avail = map { canonical($_) => $_ } @avail;
my @latest = reverse sort keys %avail;
print STDERR "+ canonical available kernels:\n  " . join("\n  ",@latest) . "\n" 
  if $verbose;
my $latest = $avail{$latest[0]};
printf STDERR "+ latest is %s (canonical %s)\n", $latest, $latest[0]
  if $verbose;

$latest .= 'smp' if $CURRENT =~ m/smp$/;
my $results = sprintf "latest available kernel is %s, running is %s", 
  $latest, $CURRENT;
if ($latest[0] gt $CANONICAL) {
  exit("WARNING", $results);
}
else {
  exit("OK", $results);
}

# arch-tag: a1cd19f6-dc75-4cec-9508-c16313e20e4b
# vim:ft=perl:ai:sw=4
