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

Source Code for Module Products.ZenEvents.EventClassInst

  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  import copy 
 15  import re 
 16  import sre_constants 
 17  import logging 
 18  import transaction 
 19  log = logging.getLogger("zen.Events") 
 20   
 21  from Globals import DTMLFile 
 22  from Globals import InitializeClass 
 23  from AccessControl import ClassSecurityInfo 
 24  from AccessControl import Permissions 
 25  from Acquisition import aq_chain 
 26  from zope.interface import implements 
 27   
 28  from Products.ZenModel.interfaces import IIndexed 
 29  from Products.ZenModel.ZenossSecurity import * 
 30  from Products.ZenRelations.RelSchema import * 
 31  from Products.ZenModel.ZenModelRM import ZenModelRM 
 32  from Products.ZenModel.EventView import EventView 
 33  from Products.ZenModel.ZenPackable import ZenPackable 
 34  from Products.ZenWidgets import messaging 
 35  from Products.ZenUtils.Utils import convToUnits, zdecode 
 36   
 37   
38 -def manage_addEventClassInst(context, id, REQUEST = None):
39 """make a device class""" 40 dc = EventClassInst(id) 41 context._setObject(id, dc) 42 if REQUEST is not None: 43 REQUEST['RESPONSE'].redirect(context.absolute_url() + '/manage_main')
44 45 46 addEventClassInst = DTMLFile('dtml/addEventClassInst',globals()) 47 48
49 -class EventClassPropertyMixin(object):
50 51 transform = '' 52 53 _properties = ( 54 {'id':'transform', 'type':'text', 'mode':'w'}, 55 ) 56
57 - def applyValues(self, evt):
58 """Modify event with values taken from dict Inst. 59 Any non-None property values are applied to the event. 60 """ 61 evt._clearClasses = copy.copy(getattr(self, "zEventClearClasses", [])) 62 evt._action = getattr(self, "zEventAction", "status") 63 sev = getattr(self, "zEventSeverity", -1) 64 if sev >= 0: 65 if evt.severity > 0: 66 evt.severity = sev 67 log.debug("Per transform/mapping, using severity %s, action '%s' and clear classes %s", 68 evt.severity, evt._action, evt._clearClasses) 69 updates = {} 70 for name in 'resolution', 'explanation': 71 value = getattr(self, name, None) 72 if value is not None and value != '': 73 updates[name] = value 74 if updates: 75 log.debug("Adding fields from transform/mapping: %s", updates) 76 evt.updateFromDict(updates) 77 return evt
78
79 - def formatTransform(self, transformLines):
80 """ 81 Convenience function to number the transform info 82 """ 83 numberedTransform = [] 84 for lineNo in range(0, len(transformLines)): 85 line = "%3s %s" % (lineNo, transformLines[lineNo]) 86 numberedTransform.append(line) 87 return '\n'.join(numberedTransform)
88
89 - def sendTransformException(self, eventclass, evt):
90 """ 91 Try to convert the rather horrible looking traceback that 92 is hard to understand into something actionable by the user. 93 """ 94 transformName = '/%s'% '/'.join(eventclass.getPhysicalPath()[4:]) 95 summary = "Error processing transform/mapping on Event Class %s" % \ 96 transformName 97 98 import sys 99 from traceback import format_exc, extract_tb 100 badLineNo = extract_tb(sys.exc_info()[2])[-1][1] - 1 101 102 transformLines = eventclass.transform.splitlines() 103 transformFormatted = self.formatTransform(transformLines) 104 exceptionText = format_exc(0).splitlines()[1] 105 message = """%s 106 Problem on line %s: %s 107 %s 108 109 Transform: 110 %s 111 """ % (summary, badLineNo, exceptionText, transformLines[badLineNo], 112 transformFormatted) 113 log.warn(message) 114 115 # Now send an event 116 zem = self.getDmd().ZenEventManager 117 badEvt = dict( 118 dedupid='|'.join([transformName,zem.host]), 119 # Don't send the *same* event class or we trash and 120 # and crash endlessly 121 eventClass='/', 122 device=zem.host, 123 component=transformName, 124 summary=summary, 125 severity=4, 126 message = "Problem with line %s: %s" % (badLineNo, 127 transformLines[badLineNo]), 128 transform=transformFormatted, 129 exception=exceptionText, 130 ) 131 zem.sendEvent(badEvt)
132
133 - def applyTransform(self, evt, device):
134 """ 135 Apply transforms on an event from the top level of the Event Class Tree 136 down to the actual Event Rules (EventClassInst) 137 """ 138 transpath = self._eventClassPath() 139 variables_and_funcs = { 140 'evt':evt, 'device':device, 'dev':device, 141 'convToUnits':convToUnits, 'zdecode':zdecode, 142 'txnCommit':transaction.commit, 'dmd':self.dmd, 143 'log':log, 144 } 145 for eventclass in transpath: 146 if not eventclass.transform: continue 147 try: 148 log.debug('Applying transform/mapping at Event Class %s', 149 eventclass.getPrimaryDmdId()) 150 exec(eventclass.transform, variables_and_funcs) 151 log.debug('Results after transform: %s', 152 variables_and_funcs['evt']) 153 except Exception, ex: 154 self.sendTransformException(eventclass, evt) 155 156 return variables_and_funcs['evt']
157 158
159 - def inheritedTransforms(self):
160 """ 161 Make a string that brings together all the transforms inherited from the 162 base EventClass to self. 163 """ 164 transpath = self._eventClassPath() 165 transtext = [] 166 for obj in transpath: 167 if not obj.transform: continue 168 if obj.transform == self.transform: break 169 transtext.append("""<a href='%s/editEventClassTransform'>%s<a> 170 """ % (obj.getPrimaryUrlPath(), obj.getPrimaryDmdId())) 171 transtext.append("<pre>%s</pre>" % obj.transform) 172 return "\n".join(transtext)
173 174
175 - def testTransformStyle(self):
176 """Test our transform by compiling it. 177 """ 178 try: 179 if self.transform: 180 compile(self.transform, "<string>", "exec") 181 except: 182 return "color:#FF0000;"
183 184
185 - def _eventClassPath(self):
186 """ 187 Return the path to our current EventClassInst from the top level 188 EventClass down. We use this to process and display the heirarchy of 189 event transforms. 190 """ 191 transpath = [] 192 for obj in aq_chain(self): 193 # skip over relationships in the aq_chain 194 if not isinstance(obj, EventClassPropertyMixin): continue 195 if obj.id == 'dmd': break 196 transpath.append(obj) 197 transpath.reverse() 198 return transpath
199 200 # Why is this a subclass of EventView? 201
202 -class EventClassInst(EventClassPropertyMixin, ZenModelRM, EventView, 203 ZenPackable):
204 """ 205 EventClassInst. 206 """ 207 implements(IIndexed) 208 event_key = meta_type = "EventClassInst" 209 210 default_catalog = "eventClassSearch" 211 212 actions = ("status", "history", "heartbeat", "drop") 213 214 _properties = EventClassPropertyMixin._properties + ( 215 {'id':'eventClassKey', 'type':'string', 'mode':'w'}, 216 {'id':'sequence', 'type':'int', 'mode':'w'}, 217 {'id':'rule', 'type':'string', 'mode':'w'}, 218 {'id':'regex', 'type':'string', 'mode':'w'}, 219 {'id':'example', 'type':'string', 'mode':'w'}, 220 {'id':'explanation', 'type':'text', 'mode':'w'}, 221 {'id':'resolution', 'type':'text', 'mode':'w'}, 222 ) 223 224 225 _relations = ZenPackable._relations + ( 226 ("eventClass", ToOne(ToManyCont,"Products.ZenEvents.EventClass","instances")), 227 ) 228 229 230 # Screen action bindings (and tab definitions) 231 factory_type_information = ( 232 { 233 'id' : 'EventClassInst', 234 'meta_type' : 'EventClassInst', 235 'description' : """Base class for all devices""", 236 'icon' : 'EventClassInst.gif', 237 'product' : 'ZenEvents', 238 'factory' : 'manage_addEventClassInst', 239 'immediate_view' : 'eventClassInstStatus', 240 'actions' : 241 ( 242 { 'id' : 'status' 243 , 'name' : 'Status' 244 , 'action' : 'eventClassInstStatus' 245 , 'permissions' : (Permissions.view, ) 246 }, 247 { 'id' : 'edit' 248 , 'name' : 'Edit' 249 , 'action' : 'eventClassInstEdit' 250 , 'permissions' : ("Manage DMD", ) 251 }, 252 { 'id' : 'sequence' 253 , 'name' : 'Sequence' 254 , 'action' : 'eventClassInstSequence' 255 , 'permissions' : (Permissions.view,) 256 }, 257 { 'id' : 'config' 258 , 'name' : 'Configuration Properties' 259 , 'action' : 'zPropertyEditNew' 260 , 'permissions' : ("Manage DMD",) 261 }, 262 { 'id' : 'events' 263 , 'name' : 'Events' 264 , 'action' : 'viewEvents' 265 , 'permissions' : (Permissions.view, ) 266 }, 267 # { 'id' : 'historyEvents' 268 # , 'name' : 'History' 269 # , 'action' : 'viewHistoryEvents' 270 # , 'permissions' : (Permissions.view, ) 271 # }, 272 { 'id' : 'viewHistory' 273 , 'name' : 'Modifications' 274 , 'action' : 'viewNewHistory' 275 , 'permissions' : (ZEN_VIEW_MODIFICATIONS,) 276 }, 277 ) 278 }, 279 ) 280 281 security = ClassSecurityInfo() 282
283 - def __init__(self, id):
284 ZenModelRM.__init__(self, id) 285 self.eventClassKey = id 286 self.sequence = None 287 self.rule = "" 288 self.regex = "" 289 self.example = "" 290 self.explanation = "" 291 self.resolution = ""
292 293
294 - def getStatus(self, **kwargs):
295 """Return the status number for this device of class statClass. 296 """ 297 return self.getEventManager().getStatusME(self, 298 statusclass=self.getEventClass(), 299 **kwargs)
300 301
302 - def getEventClass(self):
303 """Return the full EventClass of this EventClassInst.""" 304 return self.getOrganizerName()
305
306 - def getEventClassHref(self):
307 """Return href of our class. 308 """ 309 return self.eventClass().getPrimaryUrlPath()
310 311
312 - def getDmdKey(self):
313 """Return the dmd key of this mapping ie: /App/Start/zentinel 314 """ 315 return self.getOrganizerName() + "/" + self.id
316 317
318 - def applyExtraction(self, evt):
319 """ 320 Apply the event dict regex to extract additional values from the event. 321 """ 322 if self.regex: 323 m = re.search(self.regex, evt.message) 324 if m: evt.updateFromDict(m.groupdict()) 325 return evt
326 327
328 - def applyValues(self, evt):
329 """Modify event with values taken from dict Inst. 330 Any non-None property values are applied to the event. 331 """ 332 evt.eventClass = self.getEventClass() 333 evt.eventClassMapping = '%s/%s' % (self.getEventClass(), self.id) 334 return EventClassPropertyMixin.applyValues(self, evt)
335
336 - def ruleOrRegex(self, limit=None):
337 """Return the rule if it exists else return the regex. 338 limit limits the number of characters returned. 339 """ 340 value = self.rule and self.rule or self.regex 341 if not value and self.example: 342 value = self.example 343 if limit: value = value[:limit] 344 return value
345 346
347 - def match(self, evt, device):
348 """ 349 Match an event message against our regex. 350 351 @parameter evt: event to match in our mapping 352 @type evt: dictionary 353 @parameter device: device 354 @type device: DMD object 355 @return: boolean 356 @rtype: boolean 357 """ 358 value = False 359 log.debug("match on:%s", self.getPrimaryDmdId()) 360 if self.rule: 361 try: 362 log.debug("eval rule:%s", self.rule) 363 value = eval(self.rule, {'evt':evt, 'dev':device, 'device': device}) 364 except Exception, e: 365 logging.warn("EventClassInst: %s rule failure: %s", 366 self.getDmdKey(), e) 367 else: 368 try: 369 log.debug("regex='%s' message='%s'", self.regex, evt.message) 370 value = re.search(self.regex, evt.message, re.I) 371 except sre_constants.error: pass 372 return value
373 374
375 - def testRegexStyle(self):
376 """Test our regex using the example event string. 377 """ 378 if self.example: 379 try: 380 value = re.search(self.regex, self.example, re.I) 381 if not value: return "color:#FF0000;" 382 except sre_constants.error: 383 return "color:#FF0000;"
384 385
386 - def testRuleStyle(self):
387 """Test our rule by compiling it. 388 """ 389 try: 390 if self.rule: 391 compile(self.rule, "<string>", "eval") 392 except: 393 return "color:#FF0000;"
394 395
396 - def sameKey(self):
397 """Return a list of all mappings with the same eventClassKey. 398 """ 399 return [ i for i in self.eventClass().find(self.eventClassKey) \ 400 if i.eventClassKey == self.eventClassKey ]
401 402 403 security.declareProtected('Manage DMD', 'manage_resequence')
404 - def manage_resequence(self, seqmap, REQUEST=None):
405 """Reorder the sequence of eventClassMappings with the same key. 406 """ 407 # first pass set new sequence 408 for i, map in enumerate(self.sameKey()): 409 map.sequence = seqmap[i] 410 # second pass take out any holes 411 for i, map in enumerate(self.sameKey()): 412 map.sequence = i 413 if REQUEST: 414 return self.callZenScreen(REQUEST)
415 416 417 security.declareProtected('Manage DMD', 'manage_editEventClassInst')
418 - def manage_editEventClassInst(self, name="", eventClassKey='', 419 regex='', rule='', example='', 420 transform='', 421 explanation='', resolution='', REQUEST=None):
422 """Edit a EventClassInst from a web page. 423 """ 424 redirect = self.rename(name) 425 if eventClassKey and self.eventClassKey != eventClassKey: 426 self.unindex_object() 427 self.sequence = self.eventClass().nextSequenceNumber(eventClassKey) 428 self.eventClassKey = eventClassKey 429 self.index_object() 430 self.regex = regex 431 self.rule = rule 432 self.example = example 433 self.transform = transform 434 self.explanation = explanation 435 self.resolution = resolution 436 if REQUEST: 437 from Products.ZenUtils.Time import SaveMessage 438 messaging.IMessageSender(self).sendToBrowser( 439 'Saved', SaveMessage()) 440 return self.callZenScreen(REQUEST, redirect)
441 442 443 InitializeClass(EventClassInst) 444