]> git.michaelhowe.org Git - packages/n/nagios-plugins-local.git/commitdiff
Created tags and trunk dirs for nagios-plugins-local; added code to trunk
authorMichael Howe <michael@michaelhowe.org>
Fri, 19 Mar 2010 21:46:37 +0000 (21:46 +0000)
committerMichael Howe <michael@michaelhowe.org>
Fri, 19 Mar 2010 21:46:37 +0000 (21:46 +0000)
Makefile [new file with mode: 0644]
debian/README [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/source/format [new file with mode: 0644]
plugins/check_cert [new file with mode: 0755]
plugins/check_md_raid [new file with mode: 0755]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..eb62983
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+
+PLUGINDIR=plugins
+INSTALL=/usr/bin/install
+DSTPLUGINDIR=$(DESTDIR)/usr/lib/nagios/plugins
+
+all:
+
+install:
+       $(INSTALL) -d $(DSTPLUGINDIR)
+       $(INSTALL) -m 0755 $(PLUGINDIR)/check_cert $(DSTPLUGINDIR)
+       $(INSTALL) -m 0755 $(PLUGINDIR)/check_md_raid $(DSTPLUGINDIR)
diff --git a/debian/README b/debian/README
new file mode 100644 (file)
index 0000000..94f7b51
--- /dev/null
@@ -0,0 +1,7 @@
+The Debian Package nagios-plugins-local
+----------------------------
+
+This package is a collection of scripts that are not in the standard Debian
+repository, but which are nonetheless useful.
+
+ -- Michael Howe <michael@michaelhowe.org>  Sat, 06 Mar 2010 10:43:16 +0000
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..212186a
--- /dev/null
@@ -0,0 +1,5 @@
+nagios-plugins-local (0.1) unstable; urgency=low
+
+  * Initial Release.
+
+ -- Michael Howe <michael@michaelhowe.org>  Sat, 06 Mar 2010 10:43:16 +0000
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..7f8f011
--- /dev/null
@@ -0,0 +1 @@
+7
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..972242d
--- /dev/null
@@ -0,0 +1,13 @@
+Source: nagios-plugins-local
+Section: net
+Priority: extra
+Maintainer: Michael Howe <michael@michaelhowe.org>
+Build-Depends: debhelper (>= 7)
+Standards-Version: 3.8.4
+Homepage: 
+
+Package: nagios-plugins-local
+Architecture: all
+Depends: ${misc:Depends}, perl, python
+Description: Local nagios plugins
+ Nagios plugins customized for use on michaelhowe.org hosts.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..bdd92bc
--- /dev/null
@@ -0,0 +1,36 @@
+This work was packaged for Debian by:
+
+    Michael Howe <michael@michaelhowe.org> on Sat, 06 Mar 2010 10:43:16 +0000
+
+Upstream Author(s):
+
+    Hari Sekhon
+    Mike Ryan
+
+Copyright:
+
+    check_md_raid: <Copyright (C) 2007 Hari Sekhon>
+    check_cert: <Copyright (C) 2006 Mike Ryan>
+
+License:
+
+    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 3 of the License, or
+    (at your option) any later version.
+
+    This package 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, see <http://www.gnu.org/licenses/>.
+
+On Debian systems, the complete text of the GNU General
+Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
+
+The Debian packaging is:
+
+    Copyright (C) 2010 Michael Howe <michael@michaelhowe.org>
+and is licensed under the GPL version 3, see above.
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..3d3d89c
--- /dev/null
@@ -0,0 +1,13 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+export DH_VERBOSE=1
+
+%:
+       dh  $@
diff --git a/debian/source/format b/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/plugins/check_cert b/plugins/check_cert
new file mode 100755 (executable)
index 0000000..d555581
--- /dev/null
@@ -0,0 +1,228 @@
+#!/usr/bin/perl
+###########################################################################
+#####                                                                     #
+#####     check_cert.pl -- check  HTTPS,  IMAPS,  LDAPS or SMTP (with     #
+#####     STARTTLS) certificate expiration and, optionally, naming.       #
+#####                                                                     #
+############| mike ryan                       -- 02/03/06, 14:15 |#########
+
+#use 5.6.1;
+use strict;
+use warnings;
+no warnings qw(redefine);
+
+use Date::Parse qw(str2time);
+use English;
+use Getopt::Long;
+use URI;
+
+#use lib '/usr/local/nagios/libexec';
+use lib '/usr/lib/nagios/plugins';
+use utils qw(%ERRORS);
+
+sub usage {
+    my %params = @_;
+
+    if (defined($params{'message'})) {
+        my $message = $params{'message'};
+        $message =~ s/\n*$/\n/s;
+        print STDERR $message;
+    }
+
+    print STDERR <<EOF;
+Usage: $PROGRAM_NAME --warn=<days> --critical=<days> --host=<hostname> --protocol=<protocol> [<options>]
+    --critical=<days>       number of days before certificate expiration
+                            to return a critical status
+
+    --help                  display this message
+
+    --url=<url>             URL to check.  supported schemes: file,
+                            https, imaps, ldaps, smtp, smtps.
+
+    --name=<name>           expected name on certificate
+
+    --warning=<days>        number of days before certificate expiration
+                            to return a warning status
+EOF
+
+    if (!defined($params{'error'}) || $params{'error'}) {
+        print "UNKNOWN: bad usage\n";
+        exit($ERRORS{'UNKNOWN'});
+    }
+}
+
+###########################################################################
+#####                                                                     #
+#####     init.                                                           #
+#####                                                                     #
+###########################################################################
+
+my %opt;
+GetOptions(\%opt,
+    'critical=i',
+    'help',
+    'name=s',
+    'url=s',
+    'warning=i',
+) || usage();
+
+if (defined($opt{'help'})) {
+    usage();
+}
+
+# check for required options
+foreach my $option (qw{critical warning url}) {
+    if (!defined($opt{$option})) {
+        usage(message => "--$option required");
+    }
+}
+
+# check URL scheme type
+my $uri = URI->new($opt{'url'});
+my $scheme = lc($uri->scheme);
+if (!defined($scheme) || ($scheme eq '')) {
+    usage(message => "invalid URL");
+}
+
+###########################################################################
+#####                                                                     #
+#####     retrieve certificate                                            #
+#####                                                                     #
+###########################################################################
+
+my $certdata;
+
+my $host = $uri->opaque();
+$host =~ s/^\/+//;
+my $port = undef;
+if ($host =~ s/:(\d+)//) {
+    $port = $1;
+}
+$host ||= 'localhost';
+
+if ($scheme eq 'file') {
+    $certdata = read_file($uri->path());
+
+} elsif ($scheme eq 'https') {
+    $port ||= 443;
+
+    $certdata = s_client("", "-connect $host:$port");
+
+} elsif ($scheme eq 'imaps') {
+    $port ||= 993;
+
+    $certdata = s_client(". logout", "-connect $host:$port");
+
+} elsif ($scheme eq 'ldaps') {
+    $port ||= 636;
+
+    $certdata = s_client("", "-connect $host:$port");
+
+} elsif ($scheme eq 'smtp') {
+    $port ||= 25;
+
+    $certdata = s_client("quit", "-starttls smtp -connect $host:$port");
+
+} elsif ($scheme eq 'smtps') {
+    $port ||= 465;
+
+    $certdata = s_client("quit", "-connect $host:$port");
+
+} else {
+    usage(message => "unsupported scheme ($scheme)");
+}
+
+if (!defined($certdata)) {
+    print "UNKNOWN: failed to retrieve certificate data\n";
+    exit($ERRORS{'UNKNOWN'});
+}
+
+# make sure certificate validity isn't in the future.
+my $check_start_time = time;
+if (!defined($certdata->{'not_before'})) {
+    print "UNKNOWN: failed to parse Not Before validity\n";
+    exit($ERRORS{'UNKNOWN'});
+}
+if ($check_start_time < $certdata->{'not_before'}) {
+    printf("CRITICAL: certificate not valid until %s\n", scalar(localtime($certdata->{'not_before'})));
+    exit($ERRORS{'CRITICAL'});
+}
+
+# make sure certificate validity isn't in the past.
+if (!defined($certdata->{'not_after'})) {
+    print "UNKNOWN: failed to parse Not After validitiy\n";
+    exit($ERRORS{'UNKNOWN'});
+}
+if ($check_start_time > $certdata->{'not_after'}) {
+    printf("CRITICAL: certificate expired %s\n", scalar(localtime($certdata->{'not_after'})));
+    exit($ERRORS{'CRITICAL'});
+}
+
+# check for impending expiration.
+my $expires_in = int(($certdata->{'not_after'} - $check_start_time) / (24*60*60));
+if ($expires_in <= $opt{'critical'}) {
+    printf("CRITICAL: certificate expires in $expires_in days (%s)\n", scalar(localtime($certdata->{'not_after'})));
+    exit($ERRORS{'CRITICAL'});
+}
+if ($expires_in <= $opt{'warning'}) {
+    printf("WARNING: certificate expires in $expires_in days (%s)\n", scalar(localtime($certdata->{'not_after'})));
+    exit($ERRORS{'WARNING'});
+}
+
+# optionally check for name mismatch.
+if (defined($opt{'name'})) {
+    if (!defined($certdata->{'cn'})) {
+        print "UNKNOWN: failed to parse certificate name\n";
+        exit($ERRORS{'UNKNOWN'});
+    }
+    if (lc($opt{'name'}) ne lc($certdata->{'cn'})) {
+        printf("CRITICAL: certificate name mismatch (expected %s, got %s)\n", $opt{'name'}, $certdata->{'cn'});
+        exit($ERRORS{'CRITICAL'});
+    }
+}
+
+# note good certificate.
+printf("OK: certificate expires in %d days (%s)\n", $expires_in, scalar(localtime($certdata->{'not_after'})));
+exit($ERRORS{'OK'});
+
+###########################################################################
+#####                                                                     #
+#####     certificate retrieval functions.                                #
+#####                                                                     #
+###########################################################################
+
+sub s_client {
+    my ($command, $arguments) = @_;
+
+    return(parse_certificate(scalar(`/bin/echo $command | /usr/bin/openssl s_client $arguments 2>/dev/null | /usr/bin/openssl x509 -text 2>/dev/null`)));
+}
+
+sub read_file {
+    my ($filename) = @_;
+
+    return(parse_certificate(scalar(`/usr/bin/openssl x509 -in $filename -text 2>/dev/null`)));
+}
+
+sub parse_certificate {
+    my ($text) = @_;
+
+    my %result;
+
+    foreach my $line (split(/[\r\n]+/, $text)) {
+        if ($line =~ /^\s+Not Before: (.*)$/ ){
+            $result{'not_before'} = str2time($1);
+        } elsif ($line =~ /^\s+Not After : (.*)$/ ){
+            $result{'not_after'} = str2time($1);
+        } elsif ($line =~ /^\s+Subject:.*, CN=(.*)$/ ){
+            $result{'cn'} = $1;
+        }
+    }
+
+    if (scalar(keys(%result)) == 0) {
+        print("CRITICAL: failed to retrieve certificate\n");
+        exit($ERRORS{'CRITICAL'});
+    }
+
+    return(\%result);
+}
+
diff --git a/plugins/check_md_raid b/plugins/check_md_raid
new file mode 100755 (executable)
index 0000000..5788da4
--- /dev/null
@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+#
+#   Copyright Hari Sekhon 2007
+#
+#   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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+# 
+
+""" This plugin for Nagios uses the standard mdadm program to get the status
+ of all the linux md arrays on the local machine using the mdadm utility"""
+
+__version__ = "0.7.2"
+
+import os
+import re
+import sys
+from optparse import OptionParser
+
+# Standard Nagios return codes
+OK       = 0
+WARNING  = 1
+CRITICAL = 2
+UNKNOWN  = 3
+
+# Full path to the mdadm utility check on the Raid state
+BIN    = "/sbin/mdadm"
+
+def end(status, message):
+    """exits the plugin with first arg as the return code and the second
+    arg as the message to output"""
+        
+    if status == OK:
+        print "RAID OK: %s" % message
+        sys.exit(OK)
+    elif status == WARNING:
+        print "RAID WARNING: %s" % message
+        sys.exit(WARNING)
+    elif status == CRITICAL:
+        print "RAID CRITICAL: %s" % message
+        sys.exit(CRITICAL)
+    else:
+        print "UNKNOWN: %s" % message
+        sys.exit(UNKNOWN)
+
+
+if os.geteuid() != 0:
+    end(UNKNOWN, "You must be root to run this plugin")
+
+if not os.path.exists(BIN):
+    end(UNKNOWN, "Raid utility '%s' cannot be found" % BIN)
+
+if not os.access(BIN, os.X_OK):
+    end(UNKNOWN, "Raid utility '%s' is not executable" % BIN)
+
+
+def find_arrays(verbosity):
+    """finds all MD arrays on local machine using mdadm and returns a list of 
+    them, or exits UNKNOWN if no MD arrays are found"""
+    
+    if verbosity >= 3:
+        print "finding all MD arrays via: %s --detail --scan" % BIN
+    devices_output = os.popen("%s --detail --scan" % BIN).readlines()
+    raid_devices   = []
+    for line in devices_output:
+        if "ARRAY" in line:
+            raid_device = line.split()[1]
+            if verbosity >= 2:
+                print "found array %s" % raid_device
+            raid_devices.append(raid_device)
+    
+    if len(raid_devices) == 0:
+        end(UNKNOWN, "no MD raid devices found on this machine")
+    else:
+        raid_devices.sort()
+        return raid_devices
+     
+
+def test_raid(verbosity):
+    """checks all MD arrays on local machine, returns status code"""
+    
+    raid_devices = find_arrays(verbosity)
+
+    status = OK 
+    message = ""
+    arrays_not_ok = 0
+    number_arrays = len(raid_devices)
+    for array in raid_devices:
+        if verbosity >= 2:
+            print 'Now testing raid device "%s"' % array
+       
+        detailed_output = os.popen("%s --detail %s" % (BIN, array) ).readlines()
+        
+        if verbosity >= 3:
+            for line in detailed_output:
+                print line, 
+
+        state = "unknown"
+        for line in detailed_output:
+            if "State :" in line:
+                state = line.split(":")[-1][1:-1]
+        re_clean = re.compile('^clean(, no-errors)?$')
+        if not re_clean.match(state) and state != "active":
+            arrays_not_ok += 1
+            raidlevel = detailed_output[3].split()[-1]
+            shortname = array.split("/")[-1].upper()
+            if state == "dirty":
+            # This happens when the array is under heavy usage but it's \
+            # normal and the array recovers within seconds 
+                continue
+            elif "recovering" in state:
+                extra_info = None
+                for line in detailed_output:
+                    if "Rebuild Status" in line:
+                        extra_info = line
+                message += 'Array "%s" is in state ' % shortname
+                if extra_info:
+                    message += '"%s" (%s) - %s' \
+                                    % (state, raidlevel, extra_info)
+                else:
+                    message += '"%s" (%s)' % (state, raidlevel)
+                message += ", "
+                if status == OK:
+                    status = WARNING
+            elif state == "unknown":
+                message += 'State of Raid Array "%s" is unknown, ' % shortname
+                if state == OK:
+                    status = UNKNOWN
+            else:
+                message += 'Array %s is in state "%s" (%s), ' \
+                                            % (shortname, state, raidlevel)
+                status = CRITICAL
+
+    message = message.rstrip(", ")
+
+    if status == OK:
+        message += "All arrays OK"
+    else:
+        if arrays_not_ok == 1:
+            message = "1 array not ok - " + message
+        else:
+            message = "%s arrays not ok - " % arrays_not_ok + message
+
+    if number_arrays == 1:
+        message += " [1 array checked]"
+    else:
+        message += " [%s arrays checked]" % number_arrays
+
+    return status, message
+
+
+def main():
+    """parses args and calls func to test MD arrays"""
+
+    parser = OptionParser()
+
+    parser.add_option(  "-v",
+                        "--verbose",
+                        action="count",
+                        dest="verbosity",
+                        help="Verbose mode. Good for testing plugin. By default\
+ only one result line is printed as per Nagios standards")
+
+    parser.add_option(  "-V",
+                        "--version",
+                        action="store_true",
+                        dest="version",
+                        help="Print version number and exit")
+
+    (options, args) = parser.parse_args()
+
+    if args:
+        parser.print_help()
+        sys.exit(UNKNOWN)
+
+    verbosity = options.verbosity
+    version   = options.version
+
+    if version:
+        print __version__
+        sys.exit(OK)
+
+    result, message = test_raid(verbosity)
+
+    end(result, message)
+
+
+if __name__ == "__main__":
+    main()