From: Michael Howe Date: Fri, 19 Mar 2010 21:46:37 +0000 (+0000) Subject: Created tags and trunk dirs for nagios-plugins-local; added code to trunk X-Git-Tag: 0.1~1 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=4978b92a9215d2c12def458f7e05a1e3e225f97f;p=packages%2Fn%2Fnagios-plugins-local.git Created tags and trunk dirs for nagios-plugins-local; added code to trunk --- 4978b92a9215d2c12def458f7e05a1e3e225f97f diff --git a/Makefile b/Makefile new file mode 100644 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 index 0000000..94f7b51 --- /dev/null +++ b/debian/README @@ -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 Sat, 06 Mar 2010 10:43:16 +0000 diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..212186a --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +nagios-plugins-local (0.1) unstable; urgency=low + + * Initial Release. + + -- Michael Howe Sat, 06 Mar 2010 10:43:16 +0000 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +7 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..972242d --- /dev/null +++ b/debian/control @@ -0,0 +1,13 @@ +Source: nagios-plugins-local +Section: net +Priority: extra +Maintainer: Michael Howe +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 index 0000000..bdd92bc --- /dev/null +++ b/debian/copyright @@ -0,0 +1,36 @@ +This work was packaged for Debian by: + + Michael Howe on Sat, 06 Mar 2010 10:43:16 +0000 + +Upstream Author(s): + + Hari Sekhon + Mike Ryan + +Copyright: + + check_md_raid: + check_cert: + +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 . + +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 +and is licensed under the GPL version 3, see above. diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..3d3d89c --- /dev/null +++ b/debian/rules @@ -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 index 0000000..163aaf8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/plugins/check_cert b/plugins/check_cert new file mode 100755 index 0000000..d555581 --- /dev/null +++ b/plugins/check_cert @@ -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 < --critical= --host= --protocol= [] + --critical= number of days before certificate expiration + to return a critical status + + --help display this message + + --url= URL to check. supported schemes: file, + https, imaps, ldaps, smtp, smtps. + + --name= expected name on certificate + + --warning= 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 index 0000000..5788da4 --- /dev/null +++ b/plugins/check_md_raid @@ -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()