#!/usr/bin/python # A global event handler for Nagios # Cleaned up for NZNOG 2008 presentation # Sam Sargeant # # TODO: This has no external config file. All the logic is contained # inside the main() function. If you don't understand Python objects # this will be very opaque. # # This code is released under a Creative Commons licence # http://creativecommons.org/licenses/by/3.0/nz/ # # You are free: # to Share Ñ to copy, distribute and transmit the work # to Remix Ñ to adapt the work # # Under the following conditions: # # Attribution. You must attribute the work in the manner specified by the # author or licensor (but not in any way that suggests that they endorse you or # your use of the work). # # For any reuse or distribution, you must make clear to others the license # terms of this work. The best way to do this is with a link to the URL above. # Any of the above conditions can be waived if you get permission from the # copyright holder. Nothing in this license impairs or restricts the author's # moral rights. import sys, logging, os, urllib from optparse import OptionParser version = '1.1' log = logging.getLogger('') log.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') try: logfile = logging.FileHandler('/usr/local/nagios/var/event_handler.log') except IOError, e: log.error("Cannot create logging.FileHandler: " + e.strerror) else: logfile.setFormatter(formatter) log.addHandler(logfile) def main(): ## Here is where you add your handlers. iis_handler = SaveIISStatus() iis_handler.target_host = 'iis.myorg.com' handlers = [ iis_handler, DemoHandler(), PlutoRestartHandler() ] parser = OptionParser(version=version) parser.add_option('--host', dest='host', help='host this event has occured on') parser.add_option('--host-address', dest='host_address', metavar='IP_ADDR', help='IP address of the host') parser.add_option('--host-state', dest='host_state', metavar='STATE', help='the current state of the host') parser.add_option('--host-attempt', dest='host_attempt', metavar='NUM', type='int', help='number of host checks that have occured in this state') parser.add_option('--service', dest='service', help='service this event has occured on') parser.add_option('--service-state', dest='service_state', metavar='STATE', help='state of the service') parser.add_option('--service-attempt', dest='service_attempt', type='int', metavar='NUM', help='number of service checks that have occured in this state') parser.add_option('--output', dest='output', help='the text output from the check') parser.add_option('--type', dest='type', help='the event type from Nagios: [hard|soft]') parser.add_option('-v', '--verbose', dest='verbose', action='store_true', help='verbose mode') parser.add_option('-d', '--debug', dest='debug', action='store_true', help='debug mode') parser.add_option('-n', '--no-action', dest='no_action', action='store_true', help='dry-run only') options, args = parser.parse_args() if options.debug: log.setLevel(logging.DEBUG) log.debug("Debug mode enabled") if options.debug: log.debug("Loaded handlers: %s" % [h.__class__.__name__ for h in handlers]) if options.verbose: logstdout = logging.StreamHandler() logstdout.setFormatter(formatter) log.addHandler(logstdout) event = Event() event.host = options.host event.host_address = options.host_address event.host_state = options.host_state event.service = options.service event.service_state = options.service_state event.service_attempt = options.service_attempt event.output = options.output event.type = options.type if options.debug: log.debug("Loaded event: %s" % event) log.debug("isHost: %s" % event.isHost()) log.debug("isService: %s" % event.isService()) # Load event handlers for handler in handlers: log.debug("Checking if handler %s wants %s" % (handler, event)) if handler.wants(event): log.debug("%s wants %s" % (handler, event)) if options.verbose: log.info("Running %s for %s" % (handler, event)) if not options.no_action: try: handler.run(event) except Exception, e: log.error('%s threw exception: %s' % (handler, e)) class Event: def isHost(self): if not self.service: return True return False def isService(self): if self.service: return True return False def __repr__(self): if self.service: return 'service event %s on %s is %s (%s)' % ( self.service, self.host, self.service_state, self.type) else: return 'host event %s is %s (%s)' % ( self.host, self.host_state, self.type) class Handler: def __str__(self): return self.__class__.__name__ def wants(self, event): raise NotImplemented def run(self, event): raise NotImplemented class DemoHandler(Handler): def wants(self, event): return True def run(self, event): print event class SaveIISStatus(Handler): target_host = None def wants(self, event): if event.host == self.target_host: return True def run(self, event): # Save http://host/iisstatus.dll to /var/log/iisstatus/host_yyyymmddhhmm.html import mx.DateTime, urllib2 log.info('Saving iisstatus.dll page for %s' % event.host) timestamp = mx.DateTime.now().strftime('%Y%m%d%H%M') filename = '/var/log/iisstatus/%s_%s.html' % (event.host, timestamp) log.debug('Target filename: %s' % filename) url = 'http://%s/iisstatus.dll' % event.host_address log.debug('Source URL: %s' % url) filein = urllib2.urlopen(url) fileout = open(filename, 'w') fileout.write(filein.read()) fileout.close() filein.close() class MagicRestartHandler(Handler): def wants(self, event): if event.host.endswith('.mysystem.myorg.com') and event.service == 'HTTP' and event.service_attempt == 2: return True def run(self, event): url = 'http://%s:666/?secret-restart-url-modified' % event.host log.info('Restarting MySystem on %s' % event.host) log.debug('Using URL %s' % url) urllib.urlopen(url) if __name__ == '__main__': main()