#!/usr/bin/python

### -*- coding: utf-8
# This script monitors an rss feed and checks it for freshness.

import os,sys,re, urllib
import pkg_resources

from optparse import OptionParser
from time import time,mktime,strftime
from email.Utils import parsedate

from cStringIO import StringIO
try:
    from xml.etree import cElementTree as ET
except ImportError:
    try:
        import cElementTree as ET
    except ImportError:
        sys.exit(4)


nagios_states={'OK':0,'WARNING':1,'CRITICAL':2,'UNKNOWN':3,'DEPENDENT':4}
invert_nagios_states= dict([(v, k) for k, v in nagios_states.iteritems()])

my_state='UNKNOWN'
response_text="NO OUTPUT"

debug=False

def arg_parse():
    usage="%prog [options] arg"
    parser = OptionParser(usage)
    parser.add_option("-H", "--hostname", dest="hostname",help="RSS URL to check",default='http://www.theregister.co.uk/headlines.rss')
    parser.add_option("-v", "--verbose", dest="verbose",action="store_true",help="print extra debugging information (and lists all services)",default=False)
    parser.add_option("-t", "--timeout", dest="timeout",type="int",help="Max page loadtime (Default: 10)",default=10)
    parser.add_option("-a", "--age", dest="max_age",type="int",help="Max age (in minutes) for articles",default=600)
    ### version

    (options, args) = parser.parse_args(args=sys.argv[1:])
    if len(args)!=0:
         parser.error("Error in command line options")
    return options

def make_counter(label, value, unit= '', _max = "", _min = "", warn = "", crit = ""):
    "Makes the perf counter"
    return {'label' : label, 'value' : value, 'max' : str(_max),
            'min': str(_min), 'warn' : str(warn), 'crit' : str(crit), 'unit': str(unit) }

def make_stats(counters):
    it = []
    for key, item in counters.iteritems():
        item['value'] = "%d" % (item['value'])
        it.append("%(label)s=%(value)s%(unit)s;%(crit)s;%(min)s;%(max)s" % item)
        #it.append("%(label)s=%(value)s%(unit)s;%(warn)s;%(crit)s;%(min)s;%(max)s" % item)
    return " ".join(it)

if __name__=="__main__":
    try:
         import psyco
         psyco.full()
    except ImportError:
         pass

    """
    format: 'label'=value[UOM];[warn];[crit];[min];[max]
    UOM (unit of measurement) is one of:
      no unit specified - assume a number (int or float) of things (eg, users, processes, load averages)
      s - seconds (also us, ms)
      % - percentage
      B - bytes (also KB, MB, TB)
      c - a continous counter (such as bytes transmitted on an interface)
    """
    counters = {}
    date = ""
    try:
        options=arg_parse()
        if options.verbose: debug=True
        max_age = options.max_age 
        max_timeout = options.timeout
        url = options.hostname
        counters['age'] = make_counter(label='articleage',
                                        value= 0,
                                        unit = "s",
                                        _max = max_age)
        counters['items'] = make_counter(label="items",
                                                value = 0,
                                                _min = 0,
                                                _max = 100)


    except NagiosError, msg:
       print my_state,':',msg
       sys.exit(int(nagios_states[my_state]))
    except Exception, e :
       response_text="Errors in parameters submitted to command: %s" % str(e)
       my_state='UNKNOWN'
       if debug: raise
    else:
         if debug:
              print repr(options)
         startTime = time()
         try:
            data = urllib.urlopen(url).read()
         except Exception:
            my_state = ""
            response_text = ""
            # Could be a socket error or an HTTP error--either way, we
            # don't care--it's a failure to us.
            my_state = 'CRITICAL' 
            if debug: raise
         else:
            my_state = 'OK'
            try:
                rss = ET.parse(StringIO(data))
                num_items = len(rss.findall('//item'))
                counters['items']['value'] = num_items
                if num_items > 0:
                    itemDate = rss.find('//item').findtext('pubDate')
                    age = (startTime - mktime(parsedate(itemDate))) / (60)
                    age = abs(age)

                    if age > (max_age / 2.0):
                        my_state = 'WARNING'
                        response_text = "Age is to high: %d" % age
                    if age > max_age:
                        my_state = 'CRITICAL'
                        response_text = "Age is to high: %d" % age
                    counters['age']['value'] = age
                    d = strftime("%d-%m-%y %H:%M" , parsedate(itemDate) )
                    response_text = "RSS - Newest %d min %s - Nr items %d" %(age,d, num_items)
                else:
                    my_state = 'CRITICAL'
                    response_text = "No items found!"
            except Exception, e:
                my_state = 'CRITICAL'
                response_text = str(e)
                if debug: raise

            elapsed = (time() - startTime) 

            counters['request_time'] = make_counter(label='time',
                                            value = elapsed,
                                            unit = 's', _max = max_timeout)

            counters['size'] = make_counter(label='size',
                                            value = len(data),
                                            unit = 'B', _max = max_timeout)

    #response_text += make_stats(counters)
    out = my_state +  ' - ' + response_text +  "|"+ make_stats(counters)
    #sys.stdout.write(out)
    print out
    sys.exit(int(nagios_states[my_state]))

