summaryrefslogtreecommitdiff
path: root/nagios-checks
diff options
context:
space:
mode:
Diffstat (limited to 'nagios-checks')
-rwxr-xr-xnagios-checks/nagios-check-apt-updates230
-rwxr-xr-xnagios-checks/nagios-check-default-gw70
-rwxr-xr-xnagios-checks/nagios-check-hpacucli216
-rwxr-xr-xnagios-checks/nagios-check-libs199
-rw-r--r--nagios-checks/nagios-check-libs.conf19
-rwxr-xr-xnagios-checks/nagios-check-owfs-temp136
-rwxr-xr-xnagios-checks/nagios-check-printer-status90
-rwxr-xr-xnagios-checks/nagios-check-printer-supplies205
-rwxr-xr-xnagios-checks/nagios-check-raid-3ware134
-rwxr-xr-xnagios-checks/nagios-check-raid-gdth21
-rwxr-xr-xnagios-checks/nagios-check-raid.pl136
-rwxr-xr-xnagios-checks/nagios-check-rdiff-backup154
-rwxr-xr-xnagios-checks/nagios-check-running-kernel107
-rwxr-xr-xnagios-checks/nagios-check-soas128
-rw-r--r--nagios-checks/nagios-checks-README6
15 files changed, 1851 insertions, 0 deletions
diff --git a/nagios-checks/nagios-check-apt-updates b/nagios-checks/nagios-check-apt-updates
new file mode 100755
index 0000000..5413b1f
--- /dev/null
+++ b/nagios-checks/nagios-check-apt-updates
@@ -0,0 +1,230 @@
+#!/usr/bin/perl -Tw
+
+# $Id$
+
+# nagios check for debian (security) updates,
+# based on net-snmp glue to security updates via apt-get.
+# Copyright (C) 2004 SILVER SERVER Gmbh
+# Copyright (C) 2004, 2005, 2006, 2007, 2008 Peter Palfrader
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+use strict;
+use English;
+use Getopt::Long;
+use IO::Handle;
+use IPC::Open2;
+
+$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin';
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
+
+my $APT = '/usr/bin/apt-get';
+my $VERBOSE;
+
+sub do_check($$$$$$) {
+ my ($pre_command, $timeout, $noupdate, $name, $updates_security, $updates_other) = @_;
+ my $fh;
+ my $pid;
+ my @command;
+
+ unless ($noupdate) {
+ print STDERR "Running $APT update in $name\n" if $VERBOSE;
+ @command = ($APT, 'update');
+ unshift @command, @$pre_command;
+ $fh = new IO::Handle;
+ $pid = open2($fh, \*STDIN, @command) or die ("Cannot run $APT update in $name: $!\n");
+ local $SIG{ALRM} = sub { die "Timeout for apt-get update.\n" };
+ alarm $timeout;
+ my @ignore=<$fh>;
+ alarm 0;
+ close $fh;
+ waitpid $pid, 0;
+ if ($CHILD_ERROR) { # program failed
+ die("$APT update returned with non-zero exit code in $name: ".($CHILD_ERROR / 256)."\n");
+ };
+ };
+
+ print STDERR "Running $APT --simulate upgrade in $name\n" if $VERBOSE;
+ @command = ($APT, qw{--simulate upgrade});
+ unshift @command, @$pre_command;
+ $fh = new IO::Handle;
+ $pid = open2($fh, \*STDIN, @command) or die ("Cannot run $APT --simulate upgrade | sort -u in $name: $!\n");
+ local $SIG{ALRM} = sub { die "Timeout for apt-get --simulate upgrade.\n" };
+ alarm $timeout;
+ my @lines=<$fh>;
+ close $fh;
+ alarm 0;
+ waitpid $pid, 0;
+ if ($CHILD_ERROR) { # program failed
+ die("$APT --simulate upgrade | sort -u returned with non-zero exit code in $name: ".($CHILD_ERROR / 256)."\n");
+ };
+
+ @lines = sort {$a cmp $b} @lines;
+ my %uniq;
+ @lines = grep {!$uniq{$_}++} @lines;
+
+ print STDERR "Processing information for $name\n" if $VERBOSE;
+ for my $line (@lines) {
+ if ($line =~ m/^Inst\s+(\S+)\s+/) {
+ my $package = $1;
+ if ($line =~ m/^Inst\s+\S+\s+.*security/i) {
+ push @$updates_security, $package.($name ne '/' ? "($name)" : '');
+ } else {
+ push @$updates_other, $package.($name ne '/' ? "($name)" : '');
+ };
+ }
+ }
+}
+
+
+
+my $VERSION = '0.0.3 - $Rev$';
+my $use_sudo = 1;
+my $params;
+
+# nagios exit codes
+my $OK = 0;
+my $WARNING = 1;
+my $CRITICAL = 2;
+my $UNKNOWN = 3;
+
+$params->{'chroots'} = [];
+$params->{'vservers'} = [];
+$params->{'timeout'} = 20;
+Getopt::Long::config('bundling');
+if (!GetOptions (
+ '--help' => \$params->{'help'},
+ '--version' => \$params->{'version'},
+ '--sudo' => \$params->{'sudo'},
+ '--noupdate' => \$params->{'noupdate'},
+ '--nosudo' => \$params->{'nosudo'},
+ '--verbose' => \$params->{'verbose'},
+ '--warnifupdates' => \$params->{'warnifupdates'},
+ '--timeout=i' => \$params->{'timeout'},
+ '--chroot=s' => $params->{'chroots'},
+ '--vserver=s' => $params->{'vservers'}
+ )) {
+ die ("Usage: $PROGRAM_NAME [--help|--version] [--sudo|--nosudo] [--timeout=<timeout>] [--verbose]\n");
+};
+if ($params->{'help'}) {
+ print "nagios-check-apt-updates $VERSION\n";
+ print "Usage: $PROGRAM_NAME [--help|--version] [--sudo|--nosudo] [--verbose]\n";
+ print "Reports packages to upgrade, updating the list if necessary.\n";
+ print "\n";
+ print " --help Print this short help.\n";
+ print " --version Report version number.\n";
+ print " --sudo Use sudo to call apt-get (default).\n";
+ print " --noupdate Do not run apt-get update first.\n";
+ print " --nosudo Do not use sudo to call apt-get.\n";
+ print " --warnifupdates Exit with a WARNING status if any updates are available.\n";
+ print " --timeout=<timeout> Timeout in seconds for each of the two apt-get runs.\n";
+ print " --verbose Be a little verbose.\n";
+ print " --chroot=<path> Run check in path.\n";
+ print " --vserver=<vserver> Run check in vserver.\n";
+ print "\n";
+ print "Note that for --sudo (default) you will need entries in /etc/sudoers like these:\n";
+ print "nagios ALL=(ALL) NOPASSWD: /usr/bin/apt-get update\n";
+ print "nagios ALL=(ALL) NOPASSWD: /usr/bin/apt-get --simulate upgrade\n";
+ print "nagios ALL=(ALL) NOPASSWD: /usr/sbin/chroot /chroot-ia32 /usr/bin/apt-get update\n";
+ print "nagios ALL=(ALL) NOPASSWD: /usr/sbin/chroot /chroot-ia32 /usr/bin/apt-get --simulate upgrade\n";
+ print "nagios ALL=(ALL) NOPASSWD: /usr/sbin/vserver phpserver exec /usr/bin/apt-get update\n";
+ print "nagios ALL=(ALL) NOPASSWD: /usr/sbin/vserver phpserver exec /usr/bin/apt-get --simulate upgrade\n";
+ print "\n";
+ exit (0);
+};
+if ($params->{'version'}) {
+ print "nagios-check-apt-updates $VERSION\n";
+ print "nagios check for availability of debian (security) updates\n";
+ print "Copyright (c) 2004 SILVER SERVER Gmbh\n";
+ print "Copyright (c) 2004,2005 Peter Palfrader <peter\@palfrader.org>\n";
+ exit (0);
+};
+if ($params->{'sudo'} && $params->{'nosudo'}) {
+ die ("$PROGRAM_NAME: --sudo and --nosudo are mutually exclusive.\n");
+};
+if ($params->{'sudo'}) {
+ $use_sudo = 1;
+};
+if ($params->{'nosudo'}) {
+ $use_sudo = 0;
+};
+if (scalar @{$params->{'chroots'}} == 0 && scalar @{$params->{'vservers'}} == 0) {
+ $params->{'chroots'} = ['/'];
+};
+$VERBOSE = $params->{'verbose'};
+
+
+$SIG{'__DIE__'} = sub {
+ print STDERR @_;
+ exit $UNKNOWN;
+};
+
+
+my @updates_security;
+my @updates_other;
+
+
+# Make sure chroot paths are nice;
+my @chroots = ();
+for my $root (@{$params->{'chroots'}}) {
+ if ($root =~ m#^(/[a-zA-Z0-9/.-]*)$#) {
+ push @chroots, $1;
+ } else {
+ die ("Chroot path $root is not nice.\n");
+ };
+};
+for my $root (@chroots) {
+ my @pre_command = ();
+ unshift @pre_command, 'chroot', $root if ($root ne '/');
+ unshift @pre_command, 'sudo' if $use_sudo;
+ do_check(\@pre_command, $params->{'timeout'}, $params->{'noupdate'}, $root, \@updates_security, \@updates_other);
+}
+
+# Make sure vserver names are nice;
+my @vservers = ();
+for my $vserver (@{$params->{'vservers'}}) {
+ if ($vserver =~ m#^([a-zA-Z0-9.-]+)$#) {
+ push @vservers, $1;
+ } else {
+ die ("Vserver name $vserver is not nice.\n");
+ };
+};
+for my $vserver (@vservers) {
+ my @pre_command = ();
+ unshift @pre_command, '/usr/sbin/vserver', $vserver, 'exec';
+ unshift @pre_command, 'sudo' if $use_sudo;
+ do_check(\@pre_command, $params->{'timeout'}, $params->{'noupdate'}, $vserver, \@updates_security, \@updates_other);
+}
+
+
+
+
+my $exit = $OK;
+
+my $updateinfo;
+if (@updates_security) {
+ $updateinfo .= 'Security updates ('.(scalar @updates_security).'): '.join(', ', @updates_security)."; ";
+ $exit = $CRITICAL;
+}
+if (@updates_other) {
+ $updateinfo .= 'Other Updates ('.(scalar @updates_other).'): '.join(', ', @updates_other)."; ";
+ $exit = $WARNING if ($params->{'warnifupdates'} and $exit == $OK);
+};
+$updateinfo = 'No updates available' unless defined $updateinfo;
+
+
+print $updateinfo,"\n";
+exit $exit;
diff --git a/nagios-checks/nagios-check-default-gw b/nagios-checks/nagios-check-default-gw
new file mode 100755
index 0000000..5efc930
--- /dev/null
+++ b/nagios-checks/nagios-check-default-gw
@@ -0,0 +1,70 @@
+#!/usr/bin/ruby
+
+# Copyright (c) 2006 Peter Palfrader <peter@palfrader.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+require 'optparse'
+
+NAGIOS_STATUS = { :OK => 0, :WARNING => 1, :CRITICAL => 2, :UNKNOWN => -1 };
+@verbose = 0;
+@additional_nameservers = []
+
+def show_help(parser, code=0, io=STDOUT)
+ program_name = File.basename($0, '.*')
+ io.puts "Usage: #{program_name} [options]"
+ io.puts parser.summarize
+ exit(code)
+end
+ARGV.options do |opts|
+ opts.on_tail("-h", "--help" , "Display this help screen") { show_help(opts) }
+ opts.parse!
+end
+show_help(ARGV.options, 1, STDERR) if ARGV.length > 0
+
+unless File.executable?('/sbin/ip')
+ puts "/sbin/ip is not executable"
+ exit NAGIOS_STATUS[:UNKNOWN]
+end
+
+ip_output = nil
+IO.popen("-") do |f|
+ unless f # child
+ begin
+ exec('/sbin/ip', 'route', 'show', '0.0.0.0/0')
+ rescue => e
+ puts "Cannot exec ip: "+e.message
+ exit 1
+ end
+ end
+ ip_output = f.readlines
+end
+
+if $? != 0
+ puts "Child exited with non-zero exit code(%d): %s"%[$? >> 8, ip_output]
+else
+ if ip_output.length > 0
+ puts "OK: %s" % [ip_output.join(' ')]
+ exit NAGIOS_STATUS[:OK]
+ else
+ puts "CRITICAL: no default route found."
+ exit NAGIOS_STATUS[:CRITICAL]
+ end
+end
diff --git a/nagios-checks/nagios-check-hpacucli b/nagios-checks/nagios-check-hpacucli
new file mode 100755
index 0000000..a347388
--- /dev/null
+++ b/nagios-checks/nagios-check-hpacucli
@@ -0,0 +1,216 @@
+#!/usr/bin/perl -w
+
+# check _physical_ disk status of disks on HP smart array controllers
+# requires hpacucli
+#
+# does _not_ check raid status. use arrayprobe for that.
+
+# Copyright (c) 2008 Peter Palfrader <peter@palfrader.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+use strict;
+
+# nagios exit codes
+my %CODE = (
+ 'OK' => 0,
+ 'WARNING' => 1,
+ 'CRITICAL' => 2,
+ 'UNKNOWN' => 3
+);
+
+my $EXITCODE = 'OK';
+
+$SIG{'__DIE__'} = sub {
+ print STDERR @_;
+ exit $CODE{'UNKNOWN'};
+};
+
+sub runcmd($) {
+ my ($cmd) = @_;
+ $cmd = "sudo hpacucli $cmd";
+ open(FH, $cmd."|") or die ("Cannot run $cmd: $!");
+ my @lines = <FH>;
+ close FH;
+ die ("no results from $cmd\n") if (scalar @lines == 0);
+ return \@lines;
+}
+
+sub record($) {
+ my ($newexit) = @_;
+ die "code $newexit not defined\n" unless defined $CODE{$newexit};
+
+ if ($CODE{$newexit} > $CODE{$EXITCODE}) {
+ $EXITCODE = $newexit;
+ };
+}
+
+
+my $ctrlallshow = runcmd("controller all show");
+my @controllers;
+for (@$ctrlallshow) {
+ chomp;
+ next if /^$/;
+ if (/in Slot ([0-9]+) /) {
+ push @controllers, $1;
+ next;
+ };
+ die ("Cannot read line '$_' gotten from hpacucli controller all show\n");
+};
+
+if (scalar @controllers == 0) {
+ print "UNKNONW: No smartarray controllers found with hpacucli\n";
+ exit $CODE{'UNKNOWN'}
+};
+
+my @resultstr;
+
+for my $slot (sort @controllers) {
+ my $pds = runcmd("controller slot=$slot pd all show");
+ my @drives;
+ my $nodrives = 0;
+ my %status;
+ for (@$pds) {
+ chomp;
+ next if /^$/;
+ next if (/^\S.*in Slot $slot/);
+ next if /^ *array [A-Z]$/;
+ if (/^ *(array [A-Z]) \(Failed\)$/) {
+ record('CRITICAL');
+ push @{$status{'Failed'}}, $1;
+ } elsif (/^Error: The specified controller does not have any physical drives on it.$/) {
+ $nodrives = 1;
+ } elsif (/^ *physicaldrive (\S+) .* (OK|Predictive Failure|Failed|Rebuilding)(?:, spare)?\)$/) {
+ my $drive = $1;
+ my $status = $2;
+ push @{$status{$status}}, $drive;
+ if ($status eq 'OK') {
+ } elsif ($status eq 'Predictive Failure' ||
+ $status eq 'Rebuilding') {
+ record('WARNING');
+ } elsif ($status eq 'Failed') {
+ record('CRITICAL');
+ } else {
+ record('UNKNOWN');
+ };
+ push @drives, $drive;
+ } else {
+ die ("Cannot read line '$_' gotten from hpacucli controller slot=$slot pd all show\n");
+ };
+ };
+
+ # Check that all drives have the proper transfer speed.
+ # sometimes stuff breaks and they fall back to 10mb/sec.
+ for my $drive (@drives) {
+ # skip drives that are known to have failed
+ next if (exists $status{'Failed'} && grep {$drive eq $_} @{$status{'Failed'}});
+ my $type;
+ if ($drive =~ /^[0-9]+:[0-9]+$/) { # scsi drives
+ $type = 'SCSI';
+ } elsif ($drive =~ /^[0-9]+I:[0-9]+:[0-9]+$/) { # SAS
+ $type = 'SAS';
+ } else {
+ # I'm not going to run pass arguments of unknown form to the shell..
+ warn ("Unknown diskdrive ID $drive\n");
+ next;
+ }
+
+ my $pd = runcmd("controller slot=$slot pd $drive show");
+ while (defined $pd->[0] && !($pd->[0] =~ /physicaldrive/)) {
+ shift @$pd;
+ };
+ shift @$pd;
+ my %value;
+ for (@$pd) {
+ if (m/^\s*(.*?):\s*(.*?)\s*$/) {
+ $value{$1} = $2;
+ }
+ }
+
+ my $key;
+ my $expected;
+ if ($type eq 'SCSI') {
+ $key = 'Transfer Speed';
+ if (!defined $value{'Transfer Mode'}) {
+ record('WARNING');
+ push @{$status{'unknown transfer mode'}}, $drive;
+ next;
+ } elsif ($value{'Transfer Mode'} eq 'Ultra 3 Wide') {
+ $expected = '160 MB/Sec';
+ } elsif ($value{'Transfer Mode'} eq 'Ultra 320 Wide') {
+ $expected = '320 MB/Sec';
+ } else {
+ record('WARNING');
+ push @{$status{'unknown transfer mode'}}, $drive."(".$value{'Transfer Mode'}.")";
+ next;
+ };
+ } elsif ($type eq 'SAS') {
+ $key = 'PHY Transfer Rate';
+ if ($value{'PHY Count'} eq '2') {
+ $expected = '3.0GBPS, Unknown';
+ } else {
+ $expected = '3.0GBPS';
+ }
+ } else {
+ warn "Should not be here. Do not know what to do with type '$type'\n";
+ next;
+ }
+
+ if (!defined $value{$key}) {
+ record('WARNING');
+ push @{$status{'unknown transfer speed'}}, $drive;
+ } elsif ($value{$key} ne $expected) {
+ record('WARNING');
+ push @{$status{'bad transfer speed'}}, $drive."(".$value{$key}.")";
+ };
+ };
+
+ if ($nodrives && scalar keys %status > 0) {
+ push @resultstr, "Slot $slot: have no drives but status results?";
+ record('UNKNOWN');
+ next;
+ } elsif ($nodrives) {
+ push @resultstr, "Slot $slot: no drives";
+ next;
+ };
+
+ my $cst = runcmd("controller slot=$slot show status");
+ for (@$cst) {
+ chomp;
+ next if /^$/;
+ next if (/^\S.*in Slot $slot/);
+ if (/^ *(.*) Status: (.*)$/) {
+ my $system = $1;
+ my $status = $2;
+ push @{$status{$status}}, $system;
+ if ($status ne 'OK') {
+ record('WARNING');
+ };
+ } else {
+ die ("Cannot read line '$_' gotten from hpacucli controller slot=$slot show status\n");
+ };
+ };
+
+ my $status = join(" - ", (map { $_.": ".join(", ", @{$status{$_}}) } keys %status));
+ push @resultstr, "Slot $slot: $status";
+};
+
+print "$EXITCODE: ", join(" --- ", @resultstr), "\n";
+exit $CODE{$EXITCODE};
diff --git a/nagios-checks/nagios-check-libs b/nagios-checks/nagios-check-libs
new file mode 100755
index 0000000..4406413
--- /dev/null
+++ b/nagios-checks/nagios-check-libs
@@ -0,0 +1,199 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007, 2008, 2012 Peter Palfrader <peter@palfrader.org>
+# 2012 Uli Martens <uli@youam.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+use strict;
+use English;
+use Getopt::Long;
+
+$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin';
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
+
+my $LSOF = '/usr/bin/lsof -F0';
+my $VERSION = '0.2012042101';
+
+# nagios exit codes
+my $OK = 0;
+my $WARNING = 1;
+my $CRITICAL = 2;
+my $UNKNOWN = 3;
+
+my $params;
+my $config;
+
+Getopt::Long::config('bundling');
+
+sub dief {
+ print STDERR @_;
+ exit $UNKNOWN;
+}
+
+if (!GetOptions (
+ '--help' => \$params->{'help'},
+ '--version' => \$params->{'version'},
+ '--quiet' => \$params->{'quiet'},
+ '--verbose' => \$params->{'verbose'},
+ '--config=s' => \$params->{'config'},
+ )) {
+ dief ("$PROGRAM_NAME: Usage: $PROGRAM_NAME [--help|--version] [--verbose] [--quiet] [--config=<CONFIGFILE>]\n");
+};
+if ($params->{'help'}) {
+ print "$PROGRAM_NAME: Usage: $PROGRAM_NAME [--help|--version] [--verbose] [--quiet] [--config=<CONFIGFILE>]\n";
+ print "Reports processes that are linked against libraries that no longer exist.\n";
+ print "The optional config file can specify ignore rules - see the sample config file.\n";
+ exit (0);
+};
+if ($params->{'version'}) {
+ print "nagios-check-libs $VERSION\n";
+ print "nagios check for availability of debian (security) updates\n";
+ print "Copyright (c) 2005, 2006, 2007, 2008, 2012 Peter Palfrader <peter\@palfrader.org>\n";
+ exit (0);
+};
+
+if (! defined $params->{'config'}) {
+ $params->{'config'} = '/etc/nagios/check-libs.conf';
+} elsif (! -e $params->{'config'}) {
+ dief("Config file $params->{'config'} does not exist.\n");
+}
+
+if (-e $params->{'config'}) {
+ eval "use YAML::Syck; 1" or dief "you need YAML::Syck (libyaml-syck-perl) to load a config file";
+ open(my $fh, '<', $params->{'config'}) or dief "Cannot open config file $params->{'config'}: $!";
+ $config = LoadFile($fh);
+ close($fh);
+ if (!(ref($config) eq "HASH")) {
+ dief("Loaded config is not a hash!\n");
+ }
+} else {
+ $config = {
+ 'ignorelist' => [
+ '$path =~ m#^/proc/#',
+ '$path =~ m#^/var/tmp/#',
+ '$path =~ m#^/SYS#',
+ '$path =~ m#^/drm$# # xserver stuff',
+ '$path =~ m#^/dev/zero#',
+ '$path =~ m#^/dev/shm/#',
+ ]
+ };
+}
+
+if (! exists $config->{'ignorelist'}) {
+ $config->{'ignorelist'} = [];
+} elsif (! (ref($config->{'ignorelist'}) eq 'ARRAY')) {
+ dief("Config->ignorelist is not an array!\n");
+}
+
+
+my %processes;
+
+sub getPIDs($$) {
+ my ($user, $process) = @_;
+ return join(', ', sort keys %{ $processes{$user}->{$process} });
+};
+sub getProcs($) {
+ my ($user) = @_;
+
+ return join(', ', map { $_.' ('.getPIDs($user, $_).')' } (sort {$a cmp $b} keys %{ $processes{$user} }));
+};
+sub getUsers() {
+ return join('; ', (map { $_.': '.getProcs($_) } (sort {$a cmp $b} keys %processes)));
+};
+sub inVserver() {
+ my ($f, $key);
+ if (-e "/proc/self/vinfo" ) {
+ $f = "/proc/self/vinfo";
+ $key = "XID";
+ } else {
+ $f = "/proc/self/status";
+ $key = "s_context";
+ };
+ open(F, "< $f") or return 0;
+ while (<F>) {
+ my ($k, $v) = split(/: */, $_, 2);
+ if ($k eq $key) {
+ close F;
+ return ($v > 0);
+ };
+ };
+ close F;
+ return 0;
+}
+
+my $INVSERVER = inVserver();
+
+print STDERR "Running $LSOF -n\n" if $params->{'verbose'};
+open (LSOF, "$LSOF -n|") or dief ("Cannot run $LSOF -n: $!\n");
+my @lsof=<LSOF>;
+close LSOF;
+if ($CHILD_ERROR) { # program failed
+ dief("$LSOF -n returned with non-zero exit code: ".($CHILD_ERROR / 256)."\n");
+};
+
+my ($process, $pid, $user);
+LINE: for my $line (@lsof) {
+ if ( $line =~ /^p/ ) {
+ my %fields = map { m/^(.)(.*)$/ ; $1 => $2 } grep { defined $_ and length $_ >1} split /\0/, $line;
+ $process = $fields{c};
+ $pid = $fields{p};
+ $user = $fields{L};
+ next;
+ }
+
+ unless ( $line =~ /^f/ ) {
+ dief("UNKNOWN strange line read from lsof\n");
+ # don't print it because it contains NULL characters...
+ }
+
+ my %fields = map { m/^(.)(.*)$/ ; $1 => $2 } grep { defined $_ and length $_ >1} split /\0/, $line;
+
+ my $fd = $fields{f};
+ my $inode = $fields{i};
+ my $path = $fields{n};
+ if ($path =~ m/\.dpkg-/ || $path =~ m/\(deleted\)/ || $path =~ /path inode=/ || $fd eq 'DEL') {
+ $path =~ s/^\(deleted\)//; # in some cases "(deleted)" is at the beginning of the string
+ for my $i (@{$config->{'ignorelist'}}) {
+ my $ignore = eval($i);
+ next LINE if $ignore;
+ }
+ next if ($INVSERVER && ($process eq 'init') && ($pid == 1) && ($user eq 'root'));
+ if ( $params->{'verbose'} ) {
+ print STDERR "adding $process($pid) because of [$path]:\n";
+ print STDERR $line;
+ }
+ $processes{$user}->{$process}->{$pid} = 1;
+ };
+};
+
+
+
+my $message='';
+my $exit = $OK;
+if (keys %processes) {
+ $exit = $WARNING;
+ $message = 'The following processes have libs linked that were upgraded: '. getUsers()."\n";
+} else {
+ $message = "No upgraded libs linked in running processes\n" unless $params->{'quiet'};
+};
+
+print $message;
+exit $exit;
diff --git a/nagios-checks/nagios-check-libs.conf b/nagios-checks/nagios-check-libs.conf
new file mode 100644
index 0000000..0fe7678
--- /dev/null
+++ b/nagios-checks/nagios-check-libs.conf
@@ -0,0 +1,19 @@
+---
+ ignorelist:
+ - '$path =~ m#^/proc/#'
+ - '$path =~ m#^/var/tmp/#'
+ - '$path =~ m#^/tmp/#'
+ - '$path =~ m#^/var/run/#'
+ - '$path =~ m#^/run/#'
+ - '$path =~ m#^/dev/pts/#'
+ - '$path =~ m#^/SYS#'
+ - '$path =~ m#^/sys/#'
+ - '$path =~ m#^/drm$# # xserver stuff'
+ - '$path =~ m#^/dev/zero#'
+ - '$path =~ m#^/dev/shm/#'
+ - '$path =~ m#^/var/lib/postgresql/#'
+ - '$path =~ m#^/var/log/#'
+ - '$path =~ m#^/var/spool/#'
+ - '$path =~ m#^/var/lib/ganeti/#'
+ - '$path =~ m#^/usr/lib/locale/locale-archive#'
+# vim:syn=yaml
diff --git a/nagios-checks/nagios-check-owfs-temp b/nagios-checks/nagios-check-owfs-temp
new file mode 100755
index 0000000..f7e938d
--- /dev/null
+++ b/nagios-checks/nagios-check-owfs-temp
@@ -0,0 +1,136 @@
+#!/usr/bin/ruby
+#
+# Copyright (c) 2006,2007 Peter Palfrader
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+require 'optparse'
+
+NAGIOS_STATUS = { :OK => 0, :WARNING => 1, :CRITICAL => 2, :UNKNOWN => -1 };
+
+$owfs_path = '/var/lib/owfs'
+$owfs_path = ENV['OWFSPATH'] if ENV['OWFSPATH']
+
+def bail_out(m)
+ STDERR.puts "#{$0}: #{m}"
+ exit 1
+end
+
+def runcmd(command, input)
+ rdin , wrin = IO.pipe
+ rdout, wrout = IO.pipe
+ rderr, wrerr = IO.pipe
+
+ pid = fork
+ unless pid
+ # child
+ wrin.close
+ rdout.close
+ rderr.close
+ STDIN.reopen rdin
+ STDOUT.reopen wrout
+ STDERR.reopen wrerr
+ exec(*command)
+ throw("fell through exec(). WTF.")
+ end
+ rdin.close
+ wrout.close
+ wrerr.close
+
+ out = []
+ err = []
+ tin = Thread.new { wrin.print input; wrin.close }
+ tout = Thread.new { out = rdout.readlines }
+ terr = Thread.new { err = rderr.readlines }
+ tin.join
+ tout.join
+ terr.join
+ Process.wait pid
+
+ exitstatus = $?.exitstatus
+
+ [exitstatus, out, err]
+end
+
+def report(device)
+ Process.gid=0
+ Process.egid=0
+
+ # fuse does weird checks. this fails:
+ # File.new($owfs_path+'/'+device+'/temperature', "r") ---> FAILS: in `initialize': Permission denied - /var/lib/owfs/10.D234EE000800/temperature (Errno::EACCES)
+
+ # Sometimes the directory in OWFS does not exist, and cat will say
+ # cat: /var/lib/owfs/10.D234EE000800/temperature: Invalid argument
+ # so retry it a few times, since ls'ing the directory helps on the command line at least
+ 5.times do
+ exitstatus, out, err = runcmd(['cat', $owfs_path+'/'+device+'/temperature'], '')
+ if exitstatus != 0
+ STDERR.puts "Child exited with non-zero exit code(%d): %s"%[exitstatus >> 8, err.join]
+ runcmd(['ls', $owfs_path], '')
+ sleep 1
+ else
+ STDERR.puts "command succeeded but returned something on stderr: #{err.join}" if err.size > 0
+ return out.join.to_f
+ end
+ end
+ puts "Could not get data for #{device}."
+ exit NAGIOS_STATUS[:UNKNOWN];
+end
+
+
+@lowcrit = 10;
+@lowwarn = 15;
+@highwarn = 25;
+@highcrit = 30;
+
+def show_help(parser, code=0, io=STDOUT)
+ program_name = File.basename($0, '.*')
+ io.puts "Usage: #{program_name} [options]"
+ io.puts parser.summarize
+ exit(code)
+end
+ARGV.options do |opts|
+ opts.on_tail("-h", "--help" , "Display this help screen") { show_help(opts) }
+ opts.on("-d", "--device=<ow device>" , String, "Device ID") { |x| @device = x }
+ opts.on("-n", "--name=<name>" , String, "Human readable device specifier") { |x| @name = x }
+ opts.on("-w", "--high-warn=integer" , Integer, "Upper warning limit") { |x| @highwarn = x }
+ opts.on("-c", "--high-crit=integer" , Integer, "Upper critical limit") { |x| @highcrit = x }
+ opts.on("-W", "--low-warn=integer" , Integer, "Lower warning limit") { |x| @lowwarn = x }
+ opts.on("-C", "--low-crit=integer" , Integer, "Lower critical limit") { |x| @lowcrit = x }
+ opts.parse!
+end
+show_help(ARGV.options, 1, STDERR) if ARGV.length != 0
+show_help(ARGV.options, 1, STDERR) unless @device
+
+@name = @device unless @name;
+
+temp = report @device
+
+
+if temp > @highcrit or temp < @lowcrit
+ puts "CRITICAL: device #{@name} is at #{temp}"
+ exit NAGIOS_STATUS[:CRITICAL]
+elsif temp > @highwarn or temp < @lowwarn
+ puts "WARN: device #{@name} is at #{temp}"
+ exit NAGIOS_STATUS[:WARNING]
+else
+ puts "OK: device #{@name} is at #{temp}"
+ exit NAGIOS_STATUS[:OK]
+end
diff --git a/nagios-checks/nagios-check-printer-status b/nagios-checks/nagios-check-printer-status
new file mode 100755
index 0000000..a815c6c
--- /dev/null
+++ b/nagios-checks/nagios-check-printer-status
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+
+# really quick and dirty
+
+# Copyright (c) 2006 Peter Palfrader <peter@palfrader.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+# my %ERRORS = ( OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => -1 );
+
+use English;
+use strict;
+
+my %CODE = (
+ 'UNDEF' => -1,
+ 'OK' => 0,
+ 'WARNING' => 1,
+ 'CRITICAL' => 2,
+ 'UNKNOWN' => 3
+);
+
+sub usage($$) {
+ my ($fh, $exit) = @_;
+ print $fh "Usage: $PROGRAM_NAME -H <host> -p <printer>\n";
+ exit $exit;
+}
+
+my $host;
+my $printer;
+
+while (@ARGV) {
+ my $a = shift @ARGV;
+
+ if ($a eq '-h') {
+ usage(*STDOUT,0);
+ };
+ if ($a eq '-H') {
+ usage(*STDERR,1) unless @ARGV;
+ $host = shift;
+ next;
+ };
+ if ($a eq '-p') {
+ usage(*STDERR,1) unless @ARGV;
+ $printer = shift;
+ next;
+ };
+
+ usage(*STDERR,1);
+}
+usage(*STDERR,1) unless $host;
+usage(*STDERR,1) unless $printer;
+if ($host =~ /[^A-Za-z0-9-.]/) {
+ die "Evil chars in hostname '$host'\n";
+}
+if ($printer =~ /[^A-Za-z0-9-.]/) {
+ die "Evil chars in printername '$printer'\n";
+}
+
+my $exit = 'OK';
+my @msg;
+
+open(LP, "/usr/bin/lpstat -h $host -p $printer |") or die ("Cannot exec/open lpstat: $!\n");
+while (<LP>) {
+ chomp;
+ if (/disabled/) {
+ $exit = 'CRITICAL';
+ }
+ push @msg, $_;
+};
+close (LP);
+
+print "$exit: ".(join "; ", @msg)."\n";
+exit $CODE{$exit};
diff --git a/nagios-checks/nagios-check-printer-supplies b/nagios-checks/nagios-check-printer-supplies
new file mode 100755
index 0000000..0d1abd1
--- /dev/null
+++ b/nagios-checks/nagios-check-printer-supplies
@@ -0,0 +1,205 @@
+#!/usr/bin/perl -w
+#
+# Checks HP printers for supplies
+#
+# Copyright (c) 2006 Peter Palfrader <peter@palfrader.org>
+#
+#
+# Based on snmp__supplies, a munin plugin for graphing supplies:
+#
+# Copyright (C) Rune Nordboe Skillingstad, Sveinung Marvik
+# Reports supplies (ie. toner level) on printers adhering to RFC1759
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2 dated June,
+# 1991.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+use strict;
+use English;
+use Net::SNMP;
+use Getopt::Long;
+
+my $VERSION = '$Revision$';
+
+
+# nagios exit codes
+my %CODE = (
+ 'UNDEF' => -1,
+ 'OK' => 0,
+ 'WARNING' => 1,
+ 'CRITICAL' => 2,
+ 'UNKNOWN' => 3
+);
+
+my $EXITCODE = 'UNDEF';
+my $MESSAGE = {};
+
+
+
+my $params = {
+ 'port' => 161,
+ 'community' => 'public',
+ 'timeout' => 10,
+ 'warning' => 15,
+ 'critical' => 5,
+ 'verbose' => 0,
+};
+my %cache;
+my %supplies;
+my $session;
+
+
+
+sub version($$) {
+ my ($fd, $exit) = @_;
+ print $fd "nagios-check-printer-supplies $VERSION\n";
+ print $fd "Copyright (c) 2006 Peter Palfrader <peter\@palfrader.org>\n";
+ print $fd "Also Copyright Rune Nordboe Skillingstad, Sveinung Marvik\n";
+ exit 0 if $exit;
+};
+
+sub help($$) {
+ my ($exitcode, $fd) = @_;
+ version ($fd, 0);
+ print $fd "Usage: $PROGRAM_NAME --version\n";
+ print $fd "Usage: $PROGRAM_NAME [--verbose [--verbose ..]] [--community <community>] [--timeout <timeout>] [--port <port>] [--critical <critical>] [--warning <warning>] --host <hostname>\n";
+ exit $exitcode
+};
+
+
+sub record($$) {
+ my ($newexit, $msg) = @_;
+ die "code $newexit not defined" unless defined $CODE{$newexit};
+
+ if ($CODE{$newexit} > $CODE{$EXITCODE}) {
+ $EXITCODE = $newexit;
+ };
+ push @{$MESSAGE->{$newexit}}, $msg
+}
+
+sub get_multiple($$$) {
+ my $handle = shift;
+ my $oid = shift;
+ my $type = shift;
+
+ print STDERR "# Getting table $oid...\n" if ($params->{'verbose'} > 0);
+
+ my $response = $handle->get_table($oid);
+
+ if(!defined($response)) {
+ record 'UKNOWN', "Did not get a respons when asking for $handle";
+ } else {
+ for my $key (keys(%{$response})) {
+ $supplies{keyname($key)}{$type} = $response->{$key};
+ print STDERR "$key -> ".$response->{$key}."\n" if ($params->{'verbose'} > 0);
+ }
+ }
+}
+
+sub keyname($) {
+ my $key = shift;
+ return $cache{$key} if (defined $cache{$key});
+
+ my $tkey = $key;
+ $tkey =~ s/.*(\d+\.\d+)$/$1/;
+ $tkey =~ s/\./_/;
+ $cache{$key} = $tkey;
+
+ return $tkey;
+}
+
+
+
+
+
+
+Getopt::Long::config('bundling');
+if (!GetOptions (
+ 'h|help' => \$params->{'help'},
+ 'V|version' => \$params->{'version'},
+ 'v|verbose+' => \$params->{'verbose'},
+
+ 'H|host=s' => \$params->{'host'},
+ 'p|port=i' => \$params->{'port'},
+ 'C|community=s' => \$params->{'community'},
+ 't|timeout=i' => \$params->{'timeout'},
+
+ 'c|critical=i' => \$params->{'critical'},
+ 'w|warning=i' => \$params->{'warning'},
+ )) {
+ die ("$PROGRAM_NAME: Usage: $PROGRAM_NAME [-fwhv]\n");
+};
+
+version(*STDOUT, 1) if $params->{'version'};
+help(0, *STDOUT) if $params->{'help'};
+help(1, *STDERR) unless defined $params->{'host'};
+help(1, *STDERR) if scalar @ARGV > 0;
+
+
+
+
+my $error;
+($session, $error) = Net::SNMP->session(
+ -hostname => $params->{'host'},
+ -community => $params->{'community'},
+ -port => $params->{'port'},
+ -timeout => $params->{'timeout'}
+);
+
+if(!defined ($session)) {
+ die "Croaking: $error";
+}
+
+get_multiple ($session, "1.3.6.1.2.1.43.11.1.1.6", "desc");
+get_multiple ($session, "1.3.6.1.2.1.43.11.1.1.8", "max");
+get_multiple ($session, "1.3.6.1.2.1.43.11.1.1.9", "level");
+
+
+# Get rid of supply-levels reporting negative values
+{
+ for my $supply (keys (%supplies)) {
+ if ($supplies{$supply}{level} < 0) {
+ delete $supplies{$supply};
+ print STDERR "# Deleting entry $supply: supply level unknown.\n" if ($params->{'verbose'} > 0);
+ }
+ }
+}
+
+
+# Values
+if (keys(%supplies) > 0) {
+ for my $supply (keys(%supplies)) {
+ my $level = ($supplies{$supply}{level}/$supplies{$supply}{max})*100;
+ my $desc = $supplies{$supply}{desc};
+ $level = sprintf("%.2f", $level);
+ if ($level < $params->{'critical'}) {
+ record 'CRITICAL', "$desc is at $level";
+ } elsif ($level < $params->{'warning'}) {
+ record 'WARNING', "$desc is at $level";
+ } else {
+ record 'OK', "$desc is at $level";
+ }
+ }
+}
+
+if ($EXITCODE eq 'UNDEF') {
+ record 'UNKNOWN', "no data found"
+}
+
+my @msg;
+my $message = '';
+for my $i (qw{UNKNOWN CRITICAL WARNING OK}) {
+ push @msg, @{$MESSAGE->{$i}} if defined $MESSAGE->{$i};
+};
+print $EXITCODE, ': ', join('; ', @msg). "\n";
+exit $CODE{$EXITCODE};
diff --git a/nagios-checks/nagios-check-raid-3ware b/nagios-checks/nagios-check-raid-3ware
new file mode 100755
index 0000000..8d767b8
--- /dev/null
+++ b/nagios-checks/nagios-check-raid-3ware
@@ -0,0 +1,134 @@
+#!/usr/bin/perl -Tw
+
+# Copyright (C) 2006,2008,2009 Peter Palfrader <peter@palfrader.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+# Need to allow /usr/local/bin/tw_cli info c0 u0 status in sudoers:
+#
+# nagios ALL=(ALL) NOPASSWD: /usr/local/bin/tw_cli info c0 u0 status
+#
+
+use strict;
+use English;
+use Getopt::Long;
+
+$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin';
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
+
+my $TW_CLI = '/usr/local/bin/tw_cli';
+my $SVN_REVISION_STRING = '$Rev$';
+my ($SVN_REVISION) = ($SVN_REVISION_STRING =~ /([0-9]+)/);
+ $SVN_REVISION = 'unknown' unless defined $SVN_REVISION;
+my $VERSION = '0.0.0.'.$SVN_REVISION;
+
+# nagios exit codes
+my $UNKNOWN = -1;
+my $OK = 0;
+my $WARNING = 1;
+my $CRITICAL = 2;
+
+my $params = {
+ 'no-sudo' => 0,
+ 'controller' => 0,
+ 'unit' => 0
+ };
+
+Getopt::Long::config('bundling');
+if (!GetOptions (
+ '--help' => \$params->{'help'},
+ '--version' => \$params->{'version'},
+ '--verbose' => \$params->{'verbose'},
+ '--controller=i' => \$params->{'controller'},
+ '--unit=i' => \$params->{'unit'},
+ '--no-sudo' => \$params->{'no-sudo'},
+ )) {
+ die ("$PROGRAM_NAME: Usage: $PROGRAM_NAME [--help|--version] [--verbose] [--no-sudo] [--controller=<n>] [--unit=<n>]\n");
+};
+if ($params->{'help'}) {
+ print "$PROGRAM_NAME: Usage: $PROGRAM_NAME [--help|--version] [--verbose] [--no-sudo] [--controller=<n>] [--unit=<n>]\n";
+ print "Checks status of 3ware raid arrays.\n";
+ exit (0);
+};
+if ($params->{'version'}) {
+ print "nagios-check-raid-3ware $VERSION\n";
+ print "nagios check for 3ware raids\n";
+ print "Copyright (c) 2006 Peter Palfrader <peter\@palfrader.org>\n";
+ exit (0);
+};
+
+$SIG{'__DIE__'} = sub {
+ print STDERR @_;
+ exit $UNKNOWN;
+};
+
+unless (-e $TW_CLI) {
+ print "Cannot find '$TW_CLI'.\n";
+ exit $UNKNOWN;
+};
+
+my $sudo = $params->{'no-sudo'} ? '' : 'sudo ';
+my $command = "$sudo $TW_CLI info c$params->{'controller'} u$params->{'unit'} status";
+print STDERR "Running $command\n" if $params->{'verbose'};
+open (TW, "$command|") or die ("Cannot run $command: $!\n");
+my @tw=<TW>;
+close TW;
+if ($CHILD_ERROR) { # program failed
+ die("$command returned with non-zero exit code: ".($CHILD_ERROR / 256)."\n");
+};
+
+
+my $exit = $UNKNOWN;
+my $msg = '';
+for my $line (@tw) {
+ chomp $line;
+ next if $line =~ /^$/;
+ my ($device, $status) = $line =~ m#^(/c[0-9]+/u[0-9]+) status = ([A-Z]+)$#;
+ unless (defined($device) && defined($status)) {
+ print "Cannot parse line '$line'\n";
+ exit $UNKNOWN;
+ };
+ if ($status eq 'OK' ||
+ $status eq 'VERIFYING') {
+ $msg .= ($msg eq '' ? '' : '; '). "$device: $status";
+ $exit = $exit > $OK ? $exit : $OK;
+ } elsif ($status eq 'REBUILDING') {
+ $msg .= ($msg eq '' ? '' : '; '). "$device: $status";
+ $exit = $exit > $WARNING ? $exit : $WARNING;
+ } elsif ($status eq 'DEGRADED') {
+ $msg .= ($msg eq '' ? '' : '; '). "$device: $status";
+ $exit = $exit > $CRITICAL ? $exit : $CRITICAL;
+ } elsif ($status eq 'OFFLINE') {
+ $msg .= ($msg eq '' ? '' : '; '). "$device: $status";
+ $exit = $exit > $CRITICAL ? $exit : $CRITICAL;
+ } else {
+ $msg .= ($msg eq '' ? '' : '; '). "$device: UNKNOWN STATUS '$status'";
+ $exit = $exit > $UNKNOWN ? $exit : $UNKNOWN;
+ };
+};
+
+if ($msg eq '') {
+ $msg = "No devices found";
+ die ("exit is not UNKNOWN but $exit") if ($exit != $UNKNOWN);
+}
+
+print $msg,"\n";
+exit $exit;
diff --git a/nagios-checks/nagios-check-raid-gdth b/nagios-checks/nagios-check-raid-gdth
new file mode 100755
index 0000000..a57639d
--- /dev/null
+++ b/nagios-checks/nagios-check-raid-gdth
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+# really quick and dirty
+
+# my %ERRORS = ( OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => -1 );
+
+if ! [ -e "/root/gdth-status-all-ok" ] ; then
+ echo "/root/gdth-status-all-ok not found." >&2
+ exit -1
+fi
+if ! [ -e "/proc/scsi/gdth/0" ] ; then
+ echo "/proc/scsi/gdth/0 not found." >&2
+ exit -1
+fi
+if diff /root/gdth-status-all-ok /proc/scsi/gdth/0 > /dev/null; then
+ echo "Raid status matches known-good copy."
+ exit 0
+else
+ echo "Raid status does NOT match known-good copy. RAID FAILED?"
+ exit 2
+fi
diff --git a/nagios-checks/nagios-check-raid.pl b/nagios-checks/nagios-check-raid.pl
new file mode 100755
index 0000000..f971d66
--- /dev/null
+++ b/nagios-checks/nagios-check-raid.pl
@@ -0,0 +1,136 @@
+#!/usr/bin/perl -w
+# ------------------------------------------------------------------------------
+# File Name: chech_raid.pl
+# Author: Thomas Nilsen - Norway
+# Date: 14/06/2003
+# Version: 0.1
+# Description: This script will check to see if any software raid
+# devices are down.
+# Email: thomas.nilsen@doc-s.co.uk
+# WWW: www.doc-s.co.uk
+# ------------------------------------------------------------------------------
+# Copyright 2003 (c) Thomas Nilsen
+# Credits go to Ethan Galstad for coding Nagios
+# License GPL
+# ------------------------------------------------------------------------------
+# Date Author Reason
+# ---- ------ ------
+# 2008-03-31 Peter Palfrader Return warning on running resync
+# 2007-11-07 Peter Palfrader Return unknown if /proc/mdstat does not exist
+# 05/10/2004 Peter Palfrader Make it work without that 'use util (vars)'
+# 14/06/2003 TN Initial Release
+# - Format of mdstat assumed to be "2 line" per
+# device with [??] on the second line.
+# ------------------------------------------------------------------------------
+
+use strict;
+use warnings;
+use Getopt::Long;;
+use vars qw($opt_V $opt_h $opt_t $opt_F $PROGNAME);
+use lib '/usr/local/nagios/libexec/';
+my $TIMEOUT=15;
+my %ERRORS = ( OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => -1 );
+
+
+$PROGNAME="check_raid";
+
+sub print_help ();
+sub print_usage ();
+
+$ENV{'PATH'}='';
+$ENV{'BASH_ENV'}='';
+$ENV{'ENV'}='';
+my ( $line, $stat, $state ,@device, $msg, $status, $timeout);
+
+$stat="/proc/mdstat";
+
+#Option checking
+Getopt::Long::Configure('bundling');
+$status = GetOptions(
+ "V" => \$opt_V, "version" => \$opt_V,
+ "h" => \$opt_h, "help" => \$opt_h,
+ "F" => \$opt_F, "filename" => \$opt_F,
+ "t" => \$opt_t, "timeout" => \$opt_t);
+# Version
+if ($opt_V) {
+ print($PROGNAME,': $Revision: 0.1 $');
+ exit $ERRORS{'OK'};
+}
+# Help
+if ($opt_h) {
+ print_help();
+ exit $ERRORS{'OK'};
+}
+# Filename supplied
+if ($opt_F) {
+ $opt_F = shift;
+ $stat = $1 if ($opt_F =~ /^(.*)$/);
+
+ if ( ! -r $stat ) {
+ print "Invalid mdstat file: $opt_F\n";
+ exit $ERRORS{'UNKNOWN'};
+ }
+}
+
+$timeout = $TIMEOUT;
+($opt_t) && ($opt_t =~ /^([0-9]+)$/) && ($timeout = $1);
+
+# Just in case of problems, let's not hang Nagios
+$SIG{'ALRM'} = sub {
+ print ("ERROR: No response (alarm)\n");
+ exit $ERRORS{'UNKNOWN'};
+};
+alarm($timeout);
+
+# Start checking the file...
+open (FH, $stat) or print("UNKNOWN: Cannot open $stat: $!\n"), exit $ERRORS{'UNKNOWN'};
+$state = $ERRORS{'OK'};
+$msg ="";
+
+my @resyncing = ();
+my $device = '';
+
+# Now check the mdstat file..
+while (<FH>) {
+ $line = $_;
+ if ($line =~ /^(md\S*) /) {
+ $device = $1;
+ } elsif( $line =~ / \[_|_\]|U_|_U /) {
+ $state = $ERRORS{'CRITICAL'};
+ $msg = $msg . $device . ": - ";
+ }
+ elsif ( $line =~ / resync /) {
+ # [==>..................] resync = 10.3% (15216320/146994624) finish=2153.2min speed=1018K/sec
+ my ($percent) = ($line =~ m# resync = ([0-9.]+%)#);
+ my ($finish) = ($line =~ m# finish=([0-9.]+min)#);
+ my ($speed) = ($line =~ m# speed=([0-9.]+K/sec)#);
+ push @resyncing, "$device ($percent done, finish in $finish at $speed)";
+ }
+}
+close (FH);
+
+if ( $state == $ERRORS{'CRITICAL'} ) {
+ print "CRITICAL - Device(s) $msg have failed\n";
+} elsif ( scalar @resyncing > 0 ) {
+ print "WARNING: Resyncing: ".(join "; ", @resyncing)."\n";
+ $state = $ERRORS{'WARNING'};
+} elsif ( $state == $ERRORS{'OK'} )
+ { print "OK - All devices are online\n"; }
+exit $state;
+
+
+sub print_usage () {
+ print "Usage: $PROGNAME -t <timeout> -F <filename>\n";
+}
+
+sub print_help () {
+ print_revision($PROGNAME,'$Revision: 0.1 $');
+ print "Copyright (c) 2003 Thomas Nilsen/Karl DeBisschop\n";
+ print "\n";
+ print_usage();
+ print "Checks the mdstat file for errors on any configured software raid.\n
+-t ( --timeout=INTEGER)
+ Seconds before script times out (default: 10)\n
+-F ( --filename=FILE)
+ Full path and name to mdstat file (usually '/proc/mdstat') \n\n";
+}
diff --git a/nagios-checks/nagios-check-rdiff-backup b/nagios-checks/nagios-check-rdiff-backup
new file mode 100755
index 0000000..1f8b30b
--- /dev/null
+++ b/nagios-checks/nagios-check-rdiff-backup
@@ -0,0 +1,154 @@
+#!/usr/bin/python
+
+# Copyright 2010, 2011 Peter Palfrader
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import datetime
+import dateutil.parser
+import optparse
+import os
+import re
+import sys
+import glob
+
+
+parser = optparse.OptionParser()
+parser.set_usage("%prog [options] <backuprepository>")
+parser.add_option("-q", "--quiet", dest="quiet", default=False, action="store_true",
+ help="Silent mode (exit code only)")
+parser.add_option("-w", "--warn", metavar="AGE", dest="warn",
+ help="Warn if backup older than (default: 28h)")
+parser.add_option("-c", "--critical", metavar="AGE", dest="critical",
+ help="Warn if backup older than (default: 72h)")
+(options, args) = parser.parse_args()
+
+if len(args) == 0:
+ parser.print_help()
+ sys.exit(1)
+
+log = []
+exitcode = 0
+backup_per_code = {}
+
+def code_to_prefix(code):
+ if code == 3: return 'UNKNOWN: '
+ elif code == 2: return 'CRITICAL: '
+ elif code == 1: return 'WARNING: '
+ elif code == 0: return 'OK: '
+ else: raise ValueError
+
+def convert_time(s, default_unit='h'):
+ m = re.match('([0-9]+)([smhdw])?$', s)
+ if m is None: raise ValueError
+ ticks = int(m.group(1))
+ unit = m.group(2)
+ if unit is None: unit = default_unit
+
+ if unit == 's': None
+ elif unit == 'm': ticks *= 60
+ elif unit == 'h': ticks *= 60*60
+ elif unit == 'd': ticks *= 60*60*24
+ elif unit == 'w': ticks *= 60*60*24*7
+ else: raise ValueError
+ return ticks
+
+def record(code, base, msg):
+ global exitcode
+
+ if not code in backup_per_code: backup_per_code[code] = []
+ backup_per_code[code].append(base)
+
+ prefix = code_to_prefix(code)
+ log.append("%s%s: %s"%(prefix, base, msg))
+
+ if code > exitcode: exitcode = code
+
+def get_ts_from_fn(base, fn):
+ m = re.match('current_mirror\.(.*)\.data$', fn)
+ if m is None:
+ record(2, base, "backup wedged - cannot parse current mirrors filename '%s'."%(fn))
+ return None
+ try:
+ ts = dateutil.parser.parse(m.group(1))
+ except ValueError:
+ record(2, base, "backup wedged - cannot parse datestring '%s' from filename '%s'."%(m.group(1), fn))
+ return None
+ return ts
+
+if options.warn is None: options.warn = '28'
+if options.critical is None: options.critical = '72'
+options.warn = datetime.timedelta(seconds = convert_time(options.warn))
+options.critical = datetime.timedelta(seconds = convert_time(options.critical))
+
+
+for base in args:
+ data_dir = os.path.join(base, 'rdiff-backup-data')
+
+ if not os.path.exists(base):
+ record(2, base, "not a directory")
+ continue
+ if not os.path.isdir(data_dir):
+ record(2, base, "does not seem to be an rdiff-backup backup directory")
+ continue
+ os.chdir(data_dir)
+
+ current_mirrors = glob.glob('current_mirror.*.data')
+ if len(current_mirrors) == 0:
+ record(2, base, "no current backups? (current_mirror.* not found)")
+ continue
+ elif len(current_mirrors) == 2: # one backup is currently running, presumably
+ current_mirrors.sort()
+ elif len(current_mirrors) == 1: # only one backup is current, good.
+ None
+ else:
+ record(2, base, "backup wedged - too many current_mirror.* files")
+ continue
+
+ ts = get_ts_from_fn(base, current_mirrors[0])
+ age = datetime.datetime.now(ts.tzinfo) - ts
+ if age > options.critical:
+ record(2, base, "backup is old (%s)."%(age))
+ continue
+ elif age > options.warn:
+ record(1, base, "backup is old (%s)."%(age))
+ continue
+ else:
+ record(0, base, "backup is current (age: %s)."%(age))
+ continue
+
+
+
+
+def record(code, base, msg):
+
+ if not code in backup_per_code: backup_per_code[code] = []
+ backup_per_code[code].append(base)
+
+report = []
+keys = backup_per_code.keys()
+keys.sort(reverse=True)
+for code in keys:
+ prefix = code_to_prefix(code)
+ report.append( prefix + ', '.join(backup_per_code[code]) )
+if not options.quiet:
+ print '; '.join(report)
+ for l in log: print l
+sys.exit(exitcode)
diff --git a/nagios-checks/nagios-check-running-kernel b/nagios-checks/nagios-check-running-kernel
new file mode 100755
index 0000000..818288f
--- /dev/null
+++ b/nagios-checks/nagios-check-running-kernel
@@ -0,0 +1,107 @@
+#!/bin/bash
+
+# Check if the running kernel has the same version string as the on-disk
+# kernel image.
+
+# Copyright 2008 Peter Palfrader
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+OK=0;
+WARNING=1;
+CRITICAL=2;
+UNKNOWN=3;
+
+get_offset() {
+ local file needle
+
+ file="$1"
+ needle="$2"
+ perl -e '
+ undef $/;
+ $i = index(<>, "'"$needle"'");
+ if ($i < 0) {
+ exit 1;
+ };
+ print $i,"\n"' < "$file"
+}
+
+get_image() {
+ local image GZHDR1 GZHDR2 off
+
+ image="$1"
+
+ GZHDR1="\x1f\x8b\x08\x00"
+ GZHDR2="\x1f\x8b\x08\x08"
+
+ off=`get_offset "$image" $GZHDR1`
+ [ "$?" != "0" ] && off="-1"
+ if [ "$off" -eq "-1" ]; then
+ off=`get_offset "$image" $GZHDR2`
+ [ "$?" != "0" ] && off="-1"
+ fi
+ if [ "$off" -eq "0" ]; then
+ zcat < "$image"
+ return
+ elif [ "$off" -ne "-1" ]; then
+ (dd ibs="$off" skip=1 count=0 && dd bs=512k) < "$image" 2>/dev/null | zcat 2>/dev/null
+ return
+ fi
+
+ echo "ERROR: Unable to extract kernel image." 2>&1
+ exit 1
+}
+
+searched=""
+for on_disk in \
+ "/boot/vmlinuz-`uname -r`"\
+ "/boot/vmlinux-`uname -r`"; do
+
+ if [ -e "$on_disk" ]; then
+ on_disk_version="`get_image "$on_disk" | strings | grep 'Linux version' | head -n1`"
+ [ -z "$on_disk_version" ] || break
+ on_disk_version="`cat "$on_disk" | strings | grep 'Linux version' | head -n1`"
+ [ -z "$on_disk_version" ] || break
+
+ echo "UNKNOWN: Failed to get a version string from image $on_disk"
+ exit $UNKNOWN
+ fi
+ searched="$searched $on_disk"
+done
+
+if ! [ -e "$on_disk" ]; then
+ echo "WARNING: Did not find a kernel image (checked$searched) - I have no idea which kernel I am running"
+ exit $WARNING
+fi
+
+
+running_version="`cat /proc/version`"
+if [ -z "$running_version" ] ; then
+ echo "UNKNOWN: Failed to get a version string from running system"
+ exit $UNKNOWN
+fi
+
+if [ "$running_version" != "$on_disk_version" ]; then
+ echo "WARNING: Running kernel does not match on-disk kernel image: [$running_version != $on_disk_version]"
+ exit $WARNING
+else
+ echo "OK: Running kernel matches on disk image: [$running_version]"
+ exit $OK
+fi
diff --git a/nagios-checks/nagios-check-soas b/nagios-checks/nagios-check-soas
new file mode 100755
index 0000000..3b8e546
--- /dev/null
+++ b/nagios-checks/nagios-check-soas
@@ -0,0 +1,128 @@
+#!/usr/bin/ruby
+
+# Copyright 2006, 2012 Peter Palfrader
+# 2012 Uli Martens
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+require 'ipaddr'
+require 'resolv'
+require 'optparse'
+require 'yaml'
+
+NAGIOS_STATUS = { :OK => 0, :WARNING => 1, :CRITICAL => 2, :UNKNOWN => -1 };
+@verbose = 0;
+@additional_nameservers = []
+@check_soa_nameservers = true;
+
+def show_help(parser, code=0, io=STDOUT)
+ program_name = File.basename($0, '.*')
+ io.puts "Usage: #{program_name} [options] <domainname> [<domainname> ...]"
+ io.puts parser.summarize
+ exit(code)
+end
+ARGV.options do |opts|
+ opts.on_tail("-h", "--help" , "Display this help screen") { show_help(opts) }
+ opts.on("-v", "--verbose" , String, "Be verbose") { @verbose += 1 }
+ opts.on("-a", "--add=HOST" , String, "Also check SOA on <nameserver>") { |val| @additional_nameservers << val }
+ opts.on("-n", "--no-soa-ns" , String, "Don't query SOA record for list of nameservers") { @check_soa_nameservers = false }
+ opts.parse!
+end
+show_help(ARGV.options, 1, STDERR) if ARGV.length == 0
+
+if @additional_nameservers.count <= 1 and not @check_soa_nameservers
+ program_name = File.basename($0, '.*')
+ STDERR.puts "#{program_name}: Only know about #{@additional_nameservers.count} nameserver(s) and --no-soa-ns specified. I want at least two."
+ exit(1)
+end
+
+warnings = []
+oks = []
+
+def resolve_ns(dns, domain, nameserver)
+ puts "Getting A record for nameserver #{nameserver} for #{domain}" if @verbose > 0
+ arecords = dns.getresources(nameserver, Resolv::DNS::Resource::IN::A)
+ warnings << "Nameserver #{nameserver} for #{domain} has #{arecords.length} A records" if arecords.length != 1
+ addresses = arecords.map { |a| a.address.to_s }
+ puts "Addresses for nameserver #{nameserver} for #{domain}: #{addresses.join(', ')}" if @verbose > 0
+ return addresses
+end
+
+dns = Resolv::DNS.new
+ARGV.each{ |domain|
+ serial = []
+ nameserver_addresses = {}
+ if @check_soa_nameservers
+ nameservers = dns.getresources(domain, Resolv::DNS::Resource::IN::NS)
+ nameservernames = nameservers.collect{ |ns| ns.name.to_s }
+ nameservernames.each do |nameserver|
+ addrs = resolve_ns(dns, domain, nameserver)
+ warnings << "Duplicate nameserver #{nameserver} for #{domain}" if nameserver_addresses[nameserver]
+ nameserver_addresses[nameserver] = addrs
+ end
+ end
+ @additional_nameservers.each do |ns|
+ begin
+ ipa = IPAddr.new(ns) # check if it's an address
+ addrs = [ns]
+ rescue ArgumentError
+ addrs = resolve_ns(dns, domain, ns)
+ end
+ warnings << "Duplicate nameserver #{ns} for #{domain}" if nameserver_addresses[ns]
+ nameserver_addresses[ns] = addrs
+ end
+
+ nameserver_addresses.each_pair do |nameserver, addrs|
+ puts "Testing nameserver #{nameserver} for #{domain}" if @verbose > 0
+ addrs.each do |a|
+ puts " Nameserver #{nameserver} is at #{a}" if @verbose > 0
+ begin
+ resolver = Resolv::DNS.new({:nameserver => a})
+ soas = resolver.getresources(domain, Resolv::DNS::Resource::IN::SOA)
+ rescue SystemCallError => e
+ warnings << "Could not resolve #{domain} on #{nameserver}: #{e.message}"
+ else
+ resolver.close
+ warnings << "Nameserver #{nameserver} for #{domain} returns #{soas.length} SOAs" if soas.length != 1
+ soas.each do |soa|
+ puts " Nameserver #{nameserver} returns serial #{soa.serial} for #{domain}" if @verbose > 0
+ serial << soa.serial unless serial.include? soa.serial
+ end
+ end
+ end
+ end
+ case serial.length
+ when 0
+ warnings << "Found no serials for #{domain}"
+ when 1
+ oks << "#{domain} is at #{serial.first}"
+ else
+ warnings << "Nameservers disagree on serials for #{domain}: found #{serial.join(', ')}" if serial.length != 1
+ end
+}
+dns.close
+
+if warnings.length > 0
+ puts warnings.join('; ')
+ exit NAGIOS_STATUS[:WARNING]
+else
+ puts oks.join('; ')
+ exit NAGIOS_STATUS[:OK]
+end
diff --git a/nagios-checks/nagios-checks-README b/nagios-checks/nagios-checks-README
new file mode 100644
index 0000000..3acc4c6
--- /dev/null
+++ b/nagios-checks/nagios-checks-README
@@ -0,0 +1,6 @@
+Many of these checks are now maintained as part of the debian-admin group's
+nagios packages.
+
+See http://git.debian.org/?p=mirror/dsa-nagios.git;a=tree;f=dsa-nagios-checks/checks
+
+-- Peter, 2010-10-14