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

Source Code for Module Products.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 origFromAddr = fromAddr 94 log.debug("Found a 'from' address of %s" % fromAddr) 95 if not fromAddr or fromAddr.find('@') == -1: 96 log.warning("Unable to process the 'from' address %s -- ignoring mail" \ 97 % fromAddr) 98 return 99 100 fromAddr = message.get('From').split('@')[1].rstrip('>') 101 fromAddr = fromAddr.split(' ')[0] 102 log.debug("The from address after processing is '%s'" % fromAddr) 103 try: 104 fromIp = socket.gethostbyname(fromAddr) 105 except socket.gaierror: 106 fromIp = None 107 log.info('Hostname lookup failed for host: %s' % fromAddr) 108 109 subject = message.get('Subject') 110 111 # This is tricky... date comes in with an offset value that 112 # represents the number of seconds of difference between the 113 # parsed timezone and UTC. The events database wants all time 114 # as seconds since the epoch and treats it as UTC. As a 115 # result we have to use the datetime class to do the 116 # conversion because the functions in the time module do all 117 # kinds of covnersions "to be helpful" 118 t = rfc822.parsedate_tz(message.get('Date')) 119 120 offset_secs = t[-1] 121 122 # Convert the offset in seconds to minutes. calendar wants minutes 123 offset_mins = offset_secs / 60 124 tz = FixedOffset(offset_mins, "Unknown") 125 126 # Construct dt using the date and time as well as the timezone 127 dt = datetime(t[0], t[1], t[2], t[3], t[4], t[5], 0, tz) 128 secs = calendar.timegm(dt.utctimetuple()) 129 log.info('Timestamp of the event (should be in UTC): %f' % secs) 130 131 event = MailEvent(device=fromAddr, rcvtime=secs, 132 fromEmailAddress=origFromAddr) 133 if fromIp: 134 event.ipAddress = fromIp 135 136 payloads = message.get_payload() 137 payload = 'This is the default message' 138 while type(payloads) == types.ListType: 139 payloads = payloads[0].get_payload() 140 if type(payloads) == types.StringType: 141 payload = payloads 142 143 body = payload 144 event.summary = subject 145 event.message = body 146 self.enrich(event, subject) 147 148 event = self.buildEventClassKey(event) 149 log.info('Sending event...') 150 self.zem.sendEvent(event.__dict__) 151 log.info('The event has been sent.')
152 153
154 - def enrich(self, event, subject):
155 """ 156 Sanitize the event facility and severity fields. 157 158 @param event: event 159 @type event: simple class 160 @param subject: e-mail subject (unused) 161 @type subject: string 162 """ 163 unused(subject) 164 event.facility = "unknown" 165 event.severity = self.eventSeverity
166 167
168 - def buildEventClassKey(self, evt):
169 """ 170 Set the Zenoss eventClassKey 171 172 @param evt: event 173 @type evt: simple class 174 @return: modified event 175 @rtype: simple class 176 """ 177 if getattr(evt, 'eventClassKey', '') or getattr(evt, 'eventClass', ''): 178 return evt 179 elif getattr(evt, 'ntevid', ''): 180 evt.eventClassKey = "%s_%s" % (evt.component,evt.ntevid) 181 elif getattr(evt, 'component', ''): 182 evt.eventClassKey = evt.component 183 else: 184 evt.eventClassKey = 'email' 185 186 if getattr(evt, 'eventClassKey', ''): 187 log.debug("eventClassKey=%s", evt.eventClassKey) 188 else: 189 log.debug("No eventClassKey assigned") 190 return evt
191 192 193
194 -class POPProcessor(MessageProcessor):
195 """ 196 Extension point for messages received via POP. If you need to 197 override the behavior of "process" you should do so by 198 implementing it here. 199 """ 200
201 - def __init__(self, zem, defaultSeverity = 2):
202 """ 203 Initializer 204 205 @param zem: class that provides sendEvent() method 206 @type zem: Zenoss event manager object 207 @param defaultSeverity: severity level to use if we can't figure one out 208 """ 209 MessageProcessor.__init__(self, zem, defaultSeverity)
210 211 212
213 -class MailProcessor(MessageProcessor):
214 """ 215 Extension point for messages received via SMTP. If you need to 216 override the behavior of "process" you should do so by 217 implementing it here. 218 """ 219
220 - def __init__(self, zem, defaultSeverity = 2):
221 """ 222 Initializer 223 224 @param zem: class that provides sendEvent() method 225 @type zem: Zenoss event manager object 226 @param defaultSeverity: severity level to use if we can't figure one out 227 """ 228 MessageProcessor.__init__(self, zem, defaultSeverity)
229