Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env /usr/local/zenoss/python/bin/python
- #
- # Author: Scott Haskell
- # Date: 08/30/2008
- # Modified: 10/30/2009
- # License: This is free software. You can re-distribuite it and/or modify
- # it under the terms of the GNU General Public License version 2 (GPLv2), as
- # published by the Free Software Foundation.
- #
- # Description: Script that reads body of Zenoss event email, passed by Procmail to STDIN.
- # Script attempts to find what state the event is in (0 - new, 1 - acknowledged, 2 - suppressed)
- # and acts accordingly.
- #
- # For detailed installation and configuration, please visit:
- # http://www.zenoss.com/Members/shaskell/email-ack/email-acknowledgement-postfix-procmail-and-python
- #
- import Globals
- from Products.ZenUtils.ZenScriptBase import ZenScriptBase
- import sys
- import os
- import string
- import re
- import commands
- import string
- import signal
- import email
- # Update for outgoing email
- MAIL = "/usr/sbin/sendmail -t "
- server_from_address = "[email protected]"
- cc_address = ""
- # Debug flag
- DEBUG = 0
- # Alarm Handler timeout (in seconds)
- TIMEOUT = 15
- # Alarm handler
- def handler(signum, frame):
- print 'Signal handler called with', signum
- raise IOError, "Operation timed out"
- sys.exit(255)
- # Zenackevent Class - borrowed from
- # http://dev.zenoss.com/trac/browser/trunk/Products/ZenEvents/zenackevents.py
- class zenackevents(ZenScriptBase):
- def ack(self, state=1, evids=(), userid=""):
- self.dmd.ZenEventManager.manage_setEventStates(state,
- evids, userid)
- # Parse email headers and save payload
- # Argument(s): None
- # Return:
- # 1) Email Payload
- # 2) From Address
- def parse_email():
- payload = None
- m = email.message_from_file(sys.stdin)
- # Debug Email
- if(DEBUG):
- keys = m.keys()
- for key in keys:
- print("%s: %s") % (key, m[key])
- # Get From Address
- try:
- from_address = m['From']
- except:
- print "Can't parse From Address in Email"
- # Check for multipart message
- if(m.is_multipart()):
- # Save message instances and loop
- sub_parts = m.get_payload()
- # Get 'text/plain' instance
- for sub_part in sub_parts:
- if(sub_part.get_content_type() == "text/plain"):
- # save payload
- payload = sub_part.get_payload(decode=True)
- else:
- # save payload
- payload = m.get_payload(decode=True)
- if(DEBUG):
- print "DEBUG --"
- print payload
- print "-- DEBUG"
- if(not payload):
- print "Could not successfully get email payload - Exiting"
- sys.exit(1)
- return(payload, from_address)
- # Subroutine to extract email addres, device and event id from body
- # of email.
- # Argument(s):
- # 1) string - email (header and body as single string)
- # Return:
- # Dictionary that contains:
- # 1) email address of acknowledger
- # 2) eventid:device
- def parse(payload):
- events = {}
- evid = None
- dev = None
- # Save Device
- d = re.search(r'Device: (.*)', payload)
- try:
- dev = d.group(1)
- except:
- print "Could not parse Device Name -- Setting to Unknown"
- # Save Event ID
- # From what I can tell it's hex and digits repeating (at least 20 times)
- # I did an re.findall with this regex and it matched all instances of the
- # event ID in the email.
- e = re.findall(r'([a-f0-9-]{20,})', payload)
- if(e):
- evid = parse_evids(e)
- if(not evid):
- print "Could not parse Event ID - Exiting"
- sys.exit(1)
- if(dev):
- events[evid] = dev
- else:
- events[evid] = "Unknown"
- return(events)
- # It should match all evids, but if some random string gets detected in the
- # regex, take the highest occurance of what it believes to be the evid.
- # Arguments:
- # 1) dictionary - Event ID's
- # Returns:
- # 1) string - parsed event ID for ack
- def parse_evids(evids):
- all_evids = {}
- # initialize and increment evid occurances
- for v in evids:
- if(not all_evids.has_key(v)):
- all_evids[v] = 1
- else:
- all_evids[v] += 1
- k = all_evids.keys()
- # sort all evid keys by number of occurances
- if(len(all_evids) > 1): k.sort(key = all_evids.__getitem__)
- evid = k.pop()
- return(evid)
- # Subroutine to email that event was ack'd
- # Arguments:
- # 1) string - email address
- # 2) string - status message
- def email_ack(to_address, status, dev, evid, user, event_summary):
- p = os.popen(MAIL, 'w')
- p.write("From: %s\n" % (server_from_address))
- p.write("To: %s\n" % (to_address))
- if(cc_address): p.write("Cc: %s\n" % (cc_address))
- p.write("Content-Type: text/plain\n")
- p.write("Subject: ACK: %s on %s\n\n" % (event_summary, dev))
- p.write("%s\n" % status)
- exitcode = p.close()
- if exitcode:
- print "Exit code: %s" % exitcode
- # Subroutine to acknowledge event
- # Argument(s):
- # 1) zae object
- # 2) dictionary - events dictionary
- def ack_event(zae, events, from_address):
- user = None
- status = None
- # save date for logging
- cmd = "/bin/date"
- date = commands.getoutput(cmd)
- # extract user from email address
- try:
- u = re.search(r'(\w+)@.*', from_address)
- user = u.group(1)
- except:
- user = "admin"
- # loop through events dictionary and ack event(s)
- for k, v in events.iteritems():
- state = None
- evids = []
- evid = k
- dev = v
- try:
- # save event state; 0 == new, 1 == ack, 2 == suppressed
- event_summary = zae.dmd.ZenEventManager.getEventDetail(evid).summary
- state = int(zae.dmd.ZenEventManager.getEventDetail(evid).eventState)
- if(state == 0):
- try:
- # append to list, because manage_setEventStates expects list
- evids.append(evid)
- zae.ack(evids=evids, userid=user)
- status = "%s - Acknowledged evid: %s on %s by %s" % (date, evid, dev, user)
- except:
- status = "%s - ERROR: Could not ack evid: %s on %s" % (date, evid, dev)
- if(state == 1):
- status = "%s - evid: %s on %s has already been acknowledged" % (date, evid, dev)
- if(state == 2):
- status = "%s - evid: %s on %s has been suppressed" % (date, evid, dev)
- except:
- if(not state):
- status = "could not get event state on event id %s - Exiting" % (evid)
- sys.exit(1)
- else:
- status = "%s - Eventid %s on %s has already cleared or has been moved to history" % (date, evid, dev)
- # log status message
- print status
- if __name__ == '__main__':
- events = {}
- zae = zenackevents(connect=True)
- # Set alarm handler and alarm
- signal.signal(signal.SIGALRM, handler)
- signal.alarm(TIMEOUT)
- (payload, from_address) = parse_email()
- events = parse(payload)
- ack_event(zae, events, from_address)
- # disable alarm
- signal.alarm(0)
- sys.exit(0)
Advertisement
Add Comment
Please, Sign In to add comment