#!/usr/bin/env python # # Author: Troels Arvin # Versioning: # $Revision: 10797 $ # $Date: 2009-09-25 21:53:24 +0200 (Fri, 25 Sep 2009) $ # # Copyright (c) 2009, Danish National Board of Health. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the the Danish National Board of Health nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY the Danish National Board of Health ''AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL the Danish National Board of Health BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # (Most of the script is wrapped in a big try-block, so that # errors in the script are treated in a way which is interpreted # as an UNKNOWN state in Nagios.) try: import sys import os import urllib import email.Utils import getopt import time import datetime # =========================================================== # Set up some initial values, and prepare a help-message # =========================================================== this_script = os.path.basename(__file__) default_timeunit = 'h' # default time unit: hours timeunit = None def usage(): print """Usage: %s [-h|--help] -u|--url -c|--critical -w|--warning -t|--timeunit -c|--critical: Return CRITICAL if age is larger than time units -w|--warning: Return WARNING if age is larger than time units -t|--timeunit: Which time unit to use. Use s for seconds m for minutes h for hours d for days (24 hours) w for weeks If no unit is indicated, a unit of hours is used. -u|--url : URL to check Checks the indicated URL. If modification age (detected by the Last-Modified HTTP-header) is greater larger than indicated age, WARNING or CRITICAL is returned. At least one of -c or -w need to be specified. Example: ./check_http_age --url=http://example.com/somepath -c 5 -t d""" % this_script sys.exit(3) # =========================================================== # Parameter handling and sanity checks # =========================================================== try: options, args = getopt.getopt(sys.argv[1:], "h:c:w:u:t:", [ 'help', 'critical=', 'warning=', 'url=', 'timeunit=' ] ) except getopt.GetoptError: usage() sys.exit(3) maxage_c = None maxage_w = None for name, value in options: if name in ("-h", "--help"): usage() if name in ('-u', '--url'): url = value if name in ('-t', '--timeunit'): timeunit = value if name in ("-c", "--critical"): try: maxage_c = int(value) except Exception: print "Unable to convert CRITICAL max-age to integer\n" usage() if name in ("-w", "--warning"): try: maxage_w = int(value) except Exception: print "Unable to convert WARNING max-age to integer\n" usage() if url is None: print 'URL not indicated' usage() if maxage_w is None and maxage_c is None: print 'neither max CRITICAL nor WARNING max-age was indicated' usage() if maxage_w is not None and maxage_c is not None: if maxage_w >= maxage_c: print 'warning-value greater or equal to critical-value' usage() if maxage_c is not None and maxage_c < 0: print "max CRITICAL-age (%d) less than 0" % maxage_c usage() if maxage_w is not None and maxage_w < 0: print "max WARNING-age (%d) less than 0" % maxage_w usage() # =========================================================== # By now, all is sane; prepare some helper values # =========================================================== if timeunit is None: timeunit = 'h' multiplier = None if timeunit == 's': multiplier = 1 elif timeunit == 'm': multiplier = 60 elif timeunit == 'h': multiplier = 60*60 elif timeunit == 'd': multiplier = 60*60*24 elif timeunit == 'w': multiplier = 60*60*24*7 if multiplier is None: print "Unknown timeunit '%s'" % timeunit if maxage_w is not None: max_diff_w = maxage_w * multiplier if maxage_c is not None: max_diff_c = maxage_c * multiplier # =========================================================== # Real work, part I: Fetch HTTP header, and parse datetime # =========================================================== headers = urllib.urlopen(url).info() try: lastmod = headers['Last-Modified'] except: print "Could not find a Last-Modified value for the URL" sys.exit(3) try: lastmod_t = email.Utils.mktime_tz(email.Utils.parsedate_tz(lastmod)) except: print "Last-Modified header ('%s') could not be parsed" % lastmod sys.exit(3) # ========================================================== # Real work, part II: Compare with limits # ========================================================== now_t = time.time() diff_t = now_t - lastmod_t # If the need for debugging should arise: #print "lastmod: %s" % lastmod #print "lastmod_t: %d" % lastmod_t #print "now_t: %d" % now_t #print "diff_t: %d" % diff_t if maxage_c is not None: maxdiff = maxage_c * multiplier if diff_t > maxdiff: print "CRITICAL: Modification time '%s' is older than %d %s" % (lastmod,maxage_c,timeunit) sys.exit(2) # 2 means CRITICAL if maxage_w is not None: maxdiff = maxage_w * multiplier if diff_t > maxdiff: print "WARNING: Modification time '%s' is older than %d %s" % (lastmod,maxage_w,timeunit) sys.exit(1) # 1 means WARNING # ========================================================== # Error and exit handling # ========================================================== except SystemExit, e: # Special case which is needed in order to convert the return code # from other exception handlers. sys.exit(int(str(e))) except: # At this point, we don't know what's going on, so let's # not output the details of the error into something which # would appear in the Nagios web interface. print "UNKNOWN - An unhandled error occurred. " sys.stderr.write('Unhandled error: %s' % sys.exc_info()[1]) sys.exit(3) # ========================================================== # All well; construct return message # ========================================================== diff_t_hours = diff_t/(60*60) # floating point value a this point diff_t_minutes = (diff_t_hours-int(diff_t_hours))*60 print "OK - HTTP modification age is %d hours and %d minutes" % (diff_t_hours,diff_t_minutes) sys.exit(0)