From 8e233f74d3e218de01003a88a4e34d681001f712 Mon Sep 17 00:00:00 2001 From: Peter Palfrader Date: Wed, 3 Sep 2014 11:37:35 +0200 Subject: Move files around --- nagios-checks/nagios-check-apt-updates | 230 ++++++++++++++++++++++++++++ nagios-checks/nagios-check-default-gw | 70 +++++++++ nagios-checks/nagios-check-hpacucli | 216 ++++++++++++++++++++++++++ nagios-checks/nagios-check-libs | 199 ++++++++++++++++++++++++ nagios-checks/nagios-check-libs.conf | 19 +++ nagios-checks/nagios-check-owfs-temp | 136 ++++++++++++++++ nagios-checks/nagios-check-printer-status | 90 +++++++++++ nagios-checks/nagios-check-printer-supplies | 205 +++++++++++++++++++++++++ nagios-checks/nagios-check-raid-3ware | 134 ++++++++++++++++ nagios-checks/nagios-check-raid-gdth | 21 +++ nagios-checks/nagios-check-raid.pl | 136 ++++++++++++++++ nagios-checks/nagios-check-rdiff-backup | 154 +++++++++++++++++++ nagios-checks/nagios-check-running-kernel | 107 +++++++++++++ nagios-checks/nagios-check-soas | 128 ++++++++++++++++ nagios-checks/nagios-checks-README | 6 + 15 files changed, 1851 insertions(+) create mode 100755 nagios-checks/nagios-check-apt-updates create mode 100755 nagios-checks/nagios-check-default-gw create mode 100755 nagios-checks/nagios-check-hpacucli create mode 100755 nagios-checks/nagios-check-libs create mode 100644 nagios-checks/nagios-check-libs.conf create mode 100755 nagios-checks/nagios-check-owfs-temp create mode 100755 nagios-checks/nagios-check-printer-status create mode 100755 nagios-checks/nagios-check-printer-supplies create mode 100755 nagios-checks/nagios-check-raid-3ware create mode 100755 nagios-checks/nagios-check-raid-gdth create mode 100755 nagios-checks/nagios-check-raid.pl create mode 100755 nagios-checks/nagios-check-rdiff-backup create mode 100755 nagios-checks/nagios-check-running-kernel create mode 100755 nagios-checks/nagios-check-soas create mode 100644 nagios-checks/nagios-checks-README (limited to 'nagios-checks') 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=] [--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 in seconds for each of the two apt-get runs.\n"; + print " --verbose Be a little verbose.\n"; + print " --chroot= Run check in path.\n"; + print " --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 \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 +# +# 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 +# +# 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 = ; + 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 +# 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. + +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=]\n"); +}; +if ($params->{'help'}) { + print "$PROGRAM_NAME: Usage: $PROGRAM_NAME [--help|--version] [--verbose] [--quiet] [--config=]\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 \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 () { + 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=; +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=" , String, "Device ID") { |x| @device = x } + opts.on("-n", "--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 +# +# 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 -p \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 () { + 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 +# +# +# 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 \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 ] [--timeout ] [--port ] [--critical ] [--warning ] --host \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 +# +# 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=] [--unit=]\n"); +}; +if ($params->{'help'}) { + print "$PROGRAM_NAME: Usage: $PROGRAM_NAME [--help|--version] [--verbose] [--no-sudo] [--controller=] [--unit=]\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 \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=; +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 () { + $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 -F \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] ") +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] [ ...]" + 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 ") { |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 -- cgit v1.2.3