| 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 )
290 },
291 )
292
293 security = ClassSecurityInfo()
294
296 ZenModelRM.__init__(self, id)
297 self.eventClassKey = id
298 self.sequence = None
299 self.rule = ""
300 self.regex = ""
301 self.example = ""
302 self.explanation = ""
303 self.resolution = ""
304
305
307 """Return the status number for this device of class statClass.
308 """
309 return EventView.getStatus(self, self.getEventClass())
310
314
319
320
322 """Return the dmd key of this mapping ie: /App/Start/zentinel
323 """
324 return self.getOrganizerName() + "/" + self.id
325
326
328 """
329 Apply the event dict regex to extract additional values from the event.
330 """
331 if self.regex:
332 m = re.search(self.regex, evt.message)
333 if m: evt.updateFromDict(m.groupdict())
334 return evt
335
336
338 """Modify event with values taken from dict Inst.
339 Any non-None property values are applied to the event.
340 """
341 evt.eventClass = self.getEventClass()
342 evt.eventClassMapping = '%s/%s' % (self.getEventClass(), self.id)
343 return EventClassPropertyMixin.applyValues(self, evt)
344
346 """Return the rule if it exists else return the regex.
347 limit limits the number of characters returned.
348 """
349 value = self.rule and self.rule or self.regex
350 if not value and self.example:
351 value = self.example
352 if limit: value = value[:limit]
353 return value
354
355
357 """
358 Match an event message against our regex.
359
360 @parameter evt: event to match in our mapping
361 @type evt: dictionary
362 @parameter device: device
363 @type device: DMD object
364 @return: boolean
365 @rtype: boolean
366 """
367 value = False
368 log.debug("match on:%s", self.getPrimaryDmdId())
369 if self.rule:
370 try:
371 log.debug("eval rule:%s", self.rule)
372 value = eval(self.rule, {'evt':evt, 'dev':device, 'device': device})
373 except Exception, e:
374 logging.warn("EventClassInst: %s rule failure: %s",
375 self.getDmdKey(), e)
376 else:
377 try:
378 log.debug("regex='%s' message='%s'", self.regex, evt.message)
379 value = re.search(self.regex, evt.message, re.I)
380 except sre_constants.error: pass
381 return value
382
383
385 """Test our regex using the example event string.
386 """
387 if self.example:
388 try:
389 value = re.search(self.regex, self.example, re.I)
390 if not value: return "color:#FF0000;"
391 except sre_constants.error:
392 return "color:#FF0000;"
393
394
396 """Test our rule by compiling it.
397 """
398 try:
399 if self.rule:
400 compile(self.rule, "<string>", "eval")
401 except:
402 return "color:#FF0000;"
403
404
406 """Return a list of all mappings with the same eventClassKey.
407 """
408 return [ i for i in self.eventClass().find(self.eventClassKey) \
409 if i.eventClassKey == self.eventClassKey ]
410
411
412 security.declareProtected('Manage DMD', 'manage_resequence')
414 """Reorder the sequence of eventClassMappings with the same key.
415 """
416 # first pass set new sequence
417 for i, map in enumerate(self.sameKey()):
418 map.sequence = int(seqmap[i])
419 # second pass take out any holes
420 for i, map in enumerate(self.sameKey()):
421 map.sequence = i
422 if REQUEST:
423 return self.callZenScreen(REQUEST)
424
425
426 security.declareProtected('Manage DMD', 'manage_editEventClassInst')
427 - def manage_editEventClassInst(self, name="", eventClassKey='',
428 regex='', rule='', example='',
429 transform='',
430 explanation='', resolution='', REQUEST=None):
431 """Edit a EventClassInst from a web page.
432 """
433 redirect = self.rename(name)
434 if eventClassKey and self.eventClassKey != eventClassKey:
435 self.unindex_object()
436 self.sequence = self.eventClass().nextSequenceNumber(eventClassKey)
437 self.eventClassKey = eventClassKey
438 self.index_object()
439 self.regex = regex
440 self.rule = rule
441 self.example = example
442 self.transform = transform
443 self.explanation = explanation
444 self.resolution = resolution
445 if REQUEST:
446 from Products.ZenUtils.Time import SaveMessage
447 messaging.IMessageSender(self).sendToBrowser(
448 'Saved', SaveMessage())
449 return self.callZenScreen(REQUEST, redirect)
450
451
452 InitializeClass(EventClassInst)
453
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1.1812 on Tue Oct 11 12:51:41 2011 | http://epydoc.sourceforge.net |