Package ZenEvents :: Module MailProcessor
[hide private]
[frames] | no frames]

Source Code for Module ZenEvents.MailProcessor

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2007, Zenoss Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify it 
  7  # under the terms of the GNU General Public License version 2 as published by 
  8  # the Free Software Foundation. 
  9  # 
 10  # For complete information please visit: http://www.zenoss.com/oss/ 
 11  # 
 12  ########################################################################### 
 13   
 14  __doc__ = """MailProcessor 
 15  Base class module that other servers will subclass. 
 16  """ 
 17   
 18  import email, socket, rfc822, types 
 19  import calendar 
 20  from datetime import tzinfo, timedelta, datetime 
 21   
 22  from Event import Event 
 23   
 24  from Products.ZenUtils.Utils import unused 
 25   
 26  import logging 
 27  log = logging.getLogger("zen.mail") 
 28   
 29   
30 -class MailEvent(Event):
31 """ 32 Defaults for events created by the processor 33 """ 34 agent="zenmail" 35 eventGroup="mail"
36 37 38 # The following is copied from the Python standard library 39 # examples page: http://docs.python.org/library/datetime.html 40 ZERO = timedelta(0) 41 42 # A class building tzinfo objects for fixed-offset time zones. 43 # Note that FixedOffset(0, "UTC") is a different way to build a 44 # UTC tzinfo object.
45 -class FixedOffset(tzinfo):
46 """Fixed offset in minutes east from UTC.""" 47
48 - def __init__(self, offset, name):
49 self.__offset = timedelta(minutes = offset) 50 self.__name = name
51
52 - def utcoffset(self, unused):
53 return self.__offset
54
55 - def tzname(self, unused):
56 return self.__name
57
58 - def dst(self, dt):
59 return ZERO
60 61 62
63 -class MessageProcessor(object):
64 """ 65 Base class for parsing email messages that are retrieved via POP or 66 received via SMTP. 67 """ 68
69 - def __init__(self, zem, defaultSeverity = 2):
70 """ 71 Initializer 72 73 @param zem: class that provides sendEvent() method 74 @type zem: Zenoss event manager object 75 @param defaultSeverity: severity level to use if we can't figure one out 76 @type defaultSeverity: integer 77 """ 78 self.zem = zem 79 self.eventSeverity = defaultSeverity
80 81
82 - def process(self, messageStr):
83 """ 84 Convert an e-mail message into a Zenoss event. 85 86 @param messageStr: e-mail message 87 @type messageStr: string 88 """ 89 message = email.message_from_string(messageStr) 90 self.message = message 91 92 fromAddr = message.get('From') 93 log.debug("Found a 'from' address of %s" % fromAddr) 94 if not fromAddr or fromAddr.find('@') == -1: 95 log.warning("Unable to process the 'from' address %s -- ignoring mail" \ 96 % fromAddr) 97 return 98 99 fromAddr = message.get('From').split('@')[1].rstrip('>') 100 fromAddr = fromAddr.split(' ')[0] 101 log.debug("The from address after processing is '%s'" % fromAddr) 102 try: 103 fromIp = socket.gethostbyname(fromAddr) 104 except socket.gaierror: 105 fromIp = None 106 log.info('Hostname lookup failed for host: %s' % fromAddr) 107 108 subject = message.get('Subject') 109 110 # This is tricky... date comes in with an offset value that 111 # represents the number of seconds of difference between the 112 # parsed timezone and UTC. The events database wants all time 113 # as seconds since the epoch and treats it as UTC. As a 114 # result we have to use the datetime class to do the 115 # conversion because the functions in the time module do all 116 # kinds of covnersions "to be helpful" 117 t = rfc822.parsedate_tz(message.get('Date')) 118 119 offset_secs = t[-1] 120 121 # Convert the offset in seconds to minutes. calendar wants minutes 122 offset_mins = offset_secs / 60 123 tz = FixedOffset(offset_mins, "Unknown") 124 125 # Construct dt using the date and time as well as the timezone 126 dt = datetime(t[0], t[1], t[2], t[3], t[4], t[5], 0, tz) 127 secs = calendar.timegm(dt.utctimetuple()) 128 log.info('Timestamp of the event (should be in UTC): %f' % secs) 129 130 event = MailEvent(device=fromAddr, rcvtime=secs) 131 if fromIp: 132 event.ipAddress = fromIp 133 134 payloads = message.get_payload() 135 payload = 'This is the default message' 136 while type(payloads) == types.ListType: 137 payloads = payloads[0].get_payload() 138 if type(payloads) == types.StringType: 139 payload = payloads 140 141 body = payload 142 event.summary = subject 143 event.message = body 144 self.enrich(event, subject) 145 146 event = self.buildEventClassKey(event) 147 log.info('Sending event...') 148 self.zem.sendEvent(event.__dict__) 149 log.info('The event has been sent.')
150 151
152 - def enrich(self, event, subject):
153 """ 154 Sanitize the event facility and severity fields. 155 156 @param event: event 157 @type event: simple class 158 @param subject: e-mail subject (unused) 159 @type subject: string 160 """ 161 unused(subject) 162 event.facility = "unknown" 163 event.severity = self.eventSeverity
164 165
166 - def buildEventClassKey(self, evt):
167 """ 168 Set the Zenoss eventClassKey 169 170 @param evt: event 171 @type evt: simple class 172 @return: modified event 173 @rtype: simple class 174 """ 175 if hasattr(evt, 'eventClassKey') or hasattr(evt, 'eventClass'): 176 return evt 177 elif hasattr(evt, 'ntevid'): 178 evt.eventClassKey = "%s_%s" % (evt.component,evt.ntevid) 179 elif hasattr(evt, 'component'): 180 evt.eventClassKey = evt.component 181 if hasattr(evt, 'eventClassKey'): 182 log.debug("eventClassKey=%s", evt.eventClassKey) 183 else: 184 log.debug("No eventClassKey assigned") 185 return evt
186 187 188
189 -class POPProcessor(MessageProcessor):
190 """ 191 Extension point for messages received via POP. If you need to 192 override the behavior of "process" you should do so by 193 implementing it here. 194 """ 195
196 - def __init__(self, zem, defaultSeverity = 2):
197 """ 198 Initializer 199 200 @param zem: class that provides sendEvent() method 201 @type zem: Zenoss event manager object 202 @param defaultSeverity: severity level to use if we can't figure one out 203 """ 204 MessageProcessor.__init__(self, zem, defaultSeverity)
205 206 207
208 -class MailProcessor(MessageProcessor):
209 """ 210 Extension point for messages received via SMTP. If you need to 211 override the behavior of "process" you should do so by 212 implementing it here. 213 """ 214
215 - def __init__(self, zem, defaultSeverity = 2):
216 """ 217 Initializer 218 219 @param zem: class that provides sendEvent() method 220 @type zem: Zenoss event manager object 221 @param defaultSeverity: severity level to use if we can't figure one out 222 """ 223 MessageProcessor.__init__(self, zem, defaultSeverity)
224