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