#!/usr/bin/env python
#
# Author: Troels Arvin <tra@sst.dk>
# 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 <URL> -c|--critical <max> -w|--warning <max> -t|--timeunit <unit>
    
    -c|--critical: Return CRITICAL if age is larger than <max> time units
    -w|--warning:  Return WARNING  if age is larger than <max> 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)