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 or (at your 
  8  # option) any later version as published by 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').replace("\r","").replace("\n", "") 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.debug('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 isinstance(payloads, list): 139 payloads = payloads[0].get_payload() 140 if isinstance(payloads, basestring): 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 self.zem.sendEvent(event.__dict__)
150
151 - def enrich(self, event, subject):
152 """ 153 Sanitize the event facility and severity fields. 154 155 @param event: event 156 @type event: simple class 157 @param subject: e-mail subject (unused) 158 @type subject: string 159 """ 160 unused(subject) 161 event.facility = "unknown" 162 event.severity = self.eventSeverity
163 164
165 - def buildEventClassKey(self, evt):
166 """ 167 Set the Zenoss eventClassKey 168 169 @param evt: event 170 @type evt: simple class 171 @return: modified event 172 @rtype: simple class 173 """ 174 if getattr(evt, 'eventClassKey', '') or getattr(evt, 'eventClass', ''): 175 return evt 176 elif getattr(evt, 'ntevid', ''): 177 evt.eventClassKey = "%s_%s" % (evt.component,evt.ntevid) 178 elif getattr(evt, 'component', ''): 179 evt.eventClassKey = evt.component 180 else: 181 evt.eventClassKey = 'email' 182 183 if getattr(evt, 'eventClassKey', ''): 184 log.debug("eventClassKey=%s", evt.eventClassKey) 185 else: 186 log.debug("No eventClassKey assigned") 187 return evt
188 189 190
191 -class POPProcessor(MessageProcessor):
192 """ 193 Extension point for messages received via POP. If you need to 194 override the behavior of "process" you should do so by 195 implementing it here. 196 """ 197
198 - def __init__(self, zem, defaultSeverity = 2):
199 """ 200 Initializer 201 202 @param zem: class that provides sendEvent() method 203 @type zem: Zenoss event manager object 204 @param defaultSeverity: severity level to use if we can't figure one out 205 """ 206 MessageProcessor.__init__(self, zem, defaultSeverity)
207 208 209
210 -class MailProcessor(MessageProcessor):
211 """ 212 Extension point for messages received via SMTP. If you need to 213 override the behavior of "process" you should do so by 214 implementing it here. 215 """ 216
217 - def __init__(self, zem, defaultSeverity = 2):
218 """ 219 Initializer 220 221 @param zem: class that provides sendEvent() method 222 @type zem: Zenoss event manager object 223 @param defaultSeverity: severity level to use if we can't figure one out 224 """ 225 MessageProcessor.__init__(self, zem, defaultSeverity)
226