1
2
3
4
5
6
7
8
9
10
11
12
13
14 __doc__ = """EventManagerBase
15 Data connector to backend of the event management system.
16 """
17
18 import time
19 import types
20 import random
21 random.seed()
22 import logging
23 log = logging.getLogger("zen.Events")
24
25 from AccessControl import ClassSecurityInfo
26 from AccessControl import getSecurityManager
27 from Globals import DTMLFile
28 from Acquisition import aq_base
29 import DateTime
30 from Products.ZenModel.ZenossSecurity import *
31
32 from Products.ZenUtils.ObjectCache import ObjectCache
33 from Products.ZenUtils.json import unjson
34
35 from ZEvent import ZEvent
36 from EventDetail import EventDetail
37 from BetterEventDetail import BetterEventDetail
38 from EventCommand import EventCommand
39 from Products.ZenEvents.Exceptions import *
40
41 from Products.ZenModel.ZenModelRM import ZenModelRM
42 from Products.ZenModel.ZenossSecurity import *
43 from Products.ZenRelations.RelSchema import *
44 from Products.ZenUtils import Time
45 from Products.ZenUtils.FakeRequest import FakeRequest
46 from Products.ZenEvents.ZenEventClasses import Status_Ping, Status_Wmi_Conn
47 from Products.ZenWidgets import messaging
48 from Products.ZenUI3.browser.eventconsole.columns import COLUMN_CONFIG
49
50 from ZenEventClasses import Unknown
51
52 from DbAccessBase import DbAccessBase
53
54 from Products.ZenUtils.Utils import unused
55
56 __pychecker__="maxargs=16"
57
59 """
60 Prepares data from L{Products.ZenEvents.EventManagerBase.getEventSummary}
61 for rendering in the eventrainbow template macro.
62
63 Each cell of the old-style event rainbow needs a CSS class specified in
64 order to render its color, fill and border style. evtprep determines the
65 proper class and returns it, along with a string representation of the
66 number of live and acknowledged events.
67
68 >>> from Products.ZenEvents.EventManagerBase import evtprep
69 >>> evtprep(['zenevents_5_noack noack', 2, 2])
70 {'cssclass': 'zenevents_5_noack noack empty thin', 'data': '2/2'}
71 >>> evtprep(['zenevents_5_noack noack', 1, 2])
72 {'cssclass': 'zenevents_5_noack noack', 'data': '1/2'}
73
74 @param evts: A tuple of the form (Severity string, Number Acknowledged int,
75 Number Live int)
76 @type evts: tuple
77 @return: A dictionary of the form {'cssclass': Class string, 'data': Event
78 count representation string}
79
80 """
81 evtsdata = "%d/%d" % (evts[1],evts[2])
82 if evts[1]==evts[2] or evts[2]==0:
83 return {'cssclass':evts[0] + " empty thin",
84 'data':evtsdata}
85 else:
86 return {'cssclass':evts[0], 'data':evtsdata}
87
88
90 """
91 Data connector to backend of the event management system.
92 """
93
94
95
96
97 eventStateConversions = (
98 ('New', 0),
99 ('Acknowledged',1),
100 ('Suppressed', 2),
101
102 )
103
104 eventActions = ('status', 'history', 'drop')
105
106 severityConversions = (
107 ('Critical', 5),
108 ('Error', 4),
109 ('Warning', 3),
110 ('Info', 2),
111 ('Debug', 1),
112 ('Clear', 0),
113 )
114 severities = dict([(b, a) for a, b in severityConversions])
115
116 priorityConversions = (
117 ('None', -1),
118 ('Emergency', 0),
119 ('Alert', 1),
120 ('Critical', 2),
121 ('Error', 3),
122 ('Warning', 4),
123 ('Notice', 6),
124 ('Info', 8),
125 ('Debug', 10),
126 )
127 priorities = dict([(b, a) for a, b in priorityConversions])
128
129 statusTable = "status"
130 detailTable = "detail"
131 logTable = "log"
132 lastTimeField = "lastTime"
133 firstTimeField = "firstTime"
134 deviceField = "device"
135 componentField = "component"
136 eventClassField = "eventClass"
137 severityField = "severity"
138 stateField = "eventState"
139 countField = "count"
140 prodStateField = "prodState"
141 DeviceGroupField = "DeviceGroups"
142 SystemField = "Systems"
143
144 DeviceWhere = "\"device = '%s'\" % me.getDmdKey()"
145 DeviceResultFields = ("eventState", "severity", "component", "eventClass",
146 "summary", "firstTime", "lastTime", "count" )
147 ComponentWhere = ("\"(device = '%s' and component = '%s')\""
148 " % (me.device().getDmdKey(), me.name())")
149 ComponentResultFields = ("eventState", "severity", "eventClass", "summary",
150 "firstTime", "lastTime", "count" )
151 IpAddressWhere = "\"ipAddress='%s'\" % (me.getId())"
152 EventClassWhere = "\"eventClass like '%s%%'\" % me.getDmdKey()"
153 EventClassInstWhere = """\"eventClass = '%s' and eventClassKey = '%s'\" % (\
154 me.getEventClass(), me.eventClassKey)"""
155 DeviceClassWhere = "\"DeviceClass like '%s%%'\" % me.getDmdKey()"
156 LocationWhere = "\"Location like '%s%%'\" % me.getDmdKey()"
157 SystemWhere = "\"Systems like '%%|%s%%'\" % me.getDmdKey()"
158 DeviceGroupWhere = "\"DeviceGroups like '%%|%s%%'\" % me.getDmdKey()"
159
160 defaultResultFields = ("eventState", "severity", "device", "component",
161 "eventClass", "summary", "firstTime", "lastTime",
162 "count" )
163
164 defaultFields = ('eventState', 'severity', 'evid')
165
166 defaultEventId = ('device', 'component', 'eventClass',
167 'eventKey', 'severity')
168
169 requiredEventFields = ('device', 'summary', 'severity')
170
171 refreshConversionsForm = DTMLFile('dtml/refreshNcoProduct', globals())
172
173 defaultAvailabilityDays = 7
174 defaultPriority = 3
175 eventAgingHours = 4
176 eventAgingSeverity = 4
177 historyMaxAgeDays = 0
178
179 _properties = (
180 {'id':'backend', 'type':'string','mode':'r', },
181 {'id':'username', 'type':'string', 'mode':'w'},
182 {'id':'password', 'type':'string', 'mode':'w'},
183 {'id':'host', 'type':'string', 'mode':'w'},
184 {'id':'database', 'type':'string', 'mode':'w'},
185 {'id':'port', 'type':'int', 'mode':'w'},
186 {'id':'defaultWhere', 'type':'text', 'mode':'w'},
187 {'id':'defaultOrderby', 'type':'text', 'mode':'w'},
188 {'id':'defaultResultFields', 'type':'lines', 'mode':'w'},
189 {'id':'statusTable', 'type':'string', 'mode':'w'},
190 {'id':'detailTable', 'type':'string', 'mode':'w'},
191 {'id':'logTable', 'type':'string', 'mode':'w'},
192 {'id':'lastTimeField', 'type':'string', 'mode':'w'},
193 {'id':'firstTimeField', 'type':'string', 'mode':'w'},
194 {'id':'deviceField', 'type':'string', 'mode':'w'},
195 {'id':'componentField', 'type':'string', 'mode':'w'},
196 {'id':'severityField', 'type':'string', 'mode':'w'},
197 {'id':'countField', 'type':'string', 'mode':'w'},
198 {'id':'DeviceGroupField', 'type':'string', 'mode':'w'},
199 {'id':'SystemField', 'type':'string', 'mode':'w'},
200 {'id':'DeviceWhere', 'type':'string', 'mode':'w'},
201 {'id':'DeviceResultFields', 'type':'lines', 'mode':'w'},
202 {'id':'ComponentResultFields', 'type':'lines', 'mode':'w'},
203 {'id':'EventClassWhere', 'type':'string', 'mode':'w'},
204 {'id':'EventClassInstWhere', 'type':'string', 'mode':'w'},
205 {'id':'DeviceClassWhere', 'type':'string', 'mode':'w'},
206 {'id':'LocationWhere', 'type':'string', 'mode':'w'},
207 {'id':'SystemWhere', 'type':'string', 'mode':'w'},
208 {'id':'DeviceGroupWhere', 'type':'string', 'mode':'w'},
209 {'id':'requiredEventFields', 'type':'lines', 'mode':'w'},
210 {'id':'defaultEventId', 'type':'lines', 'mode':'w'},
211 {'id':'defaultFields', 'type':'lines', 'mode':'w'},
212 {'id':'timeout', 'type':'int', 'mode':'w'},
213 {'id':'clearthresh', 'type':'int', 'mode':'w'},
214 {'id':'defaultAvailabilityDays', 'type':'int', 'mode':'w'},
215 {'id':'defaultPriority', 'type':'int', 'mode':'w'},
216 {'id':'eventAgingHours', 'type':'int', 'mode':'w'},
217 {'id':'eventAgingSeverity', 'type':'int', 'mode':'w'},
218 {'id':'historyMaxAgeDays', 'type':'int', 'mode':'w'},
219 )
220
221 _relations = (
222 ("commands", ToManyCont(ToOne, "Products.ZenEvents.EventCommand", "eventManager")),
223 )
224
225 factory_type_information = (
226 {
227 'immediate_view' : 'editEventManager',
228 'actions' :
229 (
230 { 'id' : 'edit'
231 , 'name' : 'Edit'
232 , 'action' : 'editEventManager'
233 , 'permissions' : ( "Manage DMD", )
234 },
235 { 'id' : 'edit'
236 , 'name' : 'Fields'
237 , 'action' : 'editEventManagerFields'
238 , 'permissions' : ( "Manage DMD", )
239 },
240 { 'id' : 'history_edit'
241 , 'name' : 'History Fields'
242 , 'action' : 'editEventManagerHistoryFields'
243 , 'permissions' : ( "Manage DMD", )
244 },
245 { 'id' : 'commands'
246 , 'name' : 'Commands'
247 , 'action' : 'listEventCommands'
248 , 'permissions' : ( "Manage DMD", )
249 },
250 { 'id' : 'changes'
251 , 'name' : 'Modifications'
252 , 'action' : 'viewHistory'
253 , 'permissions' : (ZEN_VIEW_MODIFICATIONS,)
254 },
255 )
256 },
257 )
258
259 security = ClassSecurityInfo()
260
261
262 - def __init__(self, id, title='', hostname='localhost', username='root',
263 password='', database='events', port=3306,
264 defaultWhere='',defaultOrderby='',defaultResultFields=[]):
265 """
266 Sets up event database access and initializes the cache.
267
268 @param id: A unique id
269 @type id: string
270 @param title: A title
271 @type title: string
272 @param hostname: The hostname of the events database server
273 @type hostname: string
274 @param username: The name of a user with permissions to access the
275 events database
276 @type username: string
277 @param password: The password of the user
278 @type password: string
279 @param database: The name of the events database
280 @type database: string
281 @param port: The port on which the database server is listening
282 @type port: int
283 @param defaultWhere: The default where clause to use when building
284 queries
285 @type defaultWhere: string
286 @param defaultOrderby: The default order by clause to use when building
287 queries
288 @type defaultOrderby: string
289 @param defaultResultFields: DEPRECATED. Currently unused.
290 @type defaultResultFields: list
291
292 """
293 unused(defaultOrderby, defaultResultFields)
294 self.id = id
295 self.title = title
296 self.username=username
297 self.password=password
298 self.database=database
299 self.host=hostname
300 self.port=port
301 DbAccessBase.__init__(self)
302
303 self.defaultWhere = defaultWhere
304 self.defaultOrderby="%s desc, %s desc" % (
305 self.severityField, self.lastTimeField)
306
307 self._schema = {}
308 self._fieldlist = []
309 self._colors = ()
310 self._ackedcolors = ()
311 ObjectCache.__init__(self)
312 self.initCache()
313
314
315
316
317
318
320 """
321 A wrapper for L{lookupManagedEntityResultFields} accepting an object
322 with an C{event_key} attribute.
323
324 >>> class dummy(object):
325 ... event_key = 'Device'
326 ...
327 >>> d = dummy()
328 >>> f = dmd.ZenEventManager.getEventResultFields(d)
329 >>> f==dmd.ZenEventManager.DeviceResultFields
330 True
331 >>> d.event_key = 'Robot'
332 >>> f = dmd.ZenEventManager.getEventResultFields(d)
333 >>> f==dmd.ZenEventManager.defaultResultFields
334 True
335
336 @param context: An object with an C{event_key} attribute.
337 @type context: L{ManagedEntity}
338 @return: A sequence of strings representing columns in the database.
339 @rtype: tuple
340 """
341 return self.lookupManagedEntityResultFields(getattr(context,
342 'event_key', 'Default'))
343
364
365
367 """
368 Create SQL representing conditions that match passed filters and append
369 it to a given where clause.
370
371 Expressions are built using various criteria, including the type of
372 filter widget representing the column and factors specific to the
373 column itself.
374
375 All C{textfield} columns except C{count} will be matched as regular
376 expressions.
377
378 C{count} may be passed as a comparison expression such as ">=2", "=8",
379 "<10", etc., or an integer, in which case it will be evaluated as
380 ">=n".
381
382 C{firstTime} and C{lastTime} are turned into seconds since the epoch,
383 then evaluated as '>=n' and '<=n', respectively.
384
385 C{multiselectmenu} columns (prodState, severity, eventState, priority)
386 arrive as a list of values to match, and become 'and (field=v1 or
387 field=v2...)' where field is the column and vn is the value.
388
389 @param where: The where clause to which to append further conditions
390 @type where: str
391 @param filters: Values for which to create filters (e.g.,
392 {'device':'^loc.*$', 'severity':[4, 5]})
393 @type filters: dict or JSON str representing dict
394 @param values: if not none the returned where clause will be
395 parameterized and the values will be populated with the values,
396 if none the values will be in the where string
397 @type values: list
398 """
399 queryValues = []
400 newwhere = ''
401 if filters is None: filters = {}
402 elif isinstance(filters, basestring):
403 filters = unjson(filters)
404 for k,v in filters.items():
405 ftype = COLUMN_CONFIG[k].get('filter', 'textfield')
406 if isinstance(ftype, dict):
407 ftype = ftype['xtype']
408 if k=='count':
409 if v.isalnum():
410 queryValues.append(v)
411 v = '>=%s'
412 else:
413
414 pass
415 newwhere += ' and count%s ' % v
416 elif ftype=='textfield':
417 newwhere += ' and (%s REGEXP %%s) ' % (k,)
418 queryValues.append(v)
419 elif k=='firstTime':
420 v = self.dateDB(v.replace('T', ' '))
421 newwhere += ' and %s >= %%s ' % (k,)
422 queryValues.append(v)
423 elif k=='lastTime':
424 v = self.dateDB(v.replace('T', ' '))
425 newwhere += ' and %s <= %%s ' % (k, )
426 queryValues.append(v)
427 elif ftype=='multiselectmenu':
428 if isinstance(v, basestring): v = (v,)
429 sevstr = ' or '.join(['%s=%%s' % (k,) for s in v])
430 queryValues.extend(v)
431 newwhere += ' and (%s) ' % sevstr
432 if values is not None:
433 values.extend(queryValues)
434 else:
435 newwhere = newwhere % tuple(queryValues)
436 return where + newwhere
437
438
439 - def getEventIDsFromRanges(self, context, sort, direction, start=None,
440 limit=None, filters=None, evids=None,
441 ranges=None, asof=None):
442 """
443 Consolidate event ids and ranges of records into a list of event ids.
444
445 Accepts criteria representing a console state and criteria representing
446 selected records, in the form of a list of event ids and a list of
447 ranges of row numbers for which the client had not loaded event ids.
448 Can then perform the query described by the console state and use that
449 to select event ids from the given ranges. These are then added to the
450 evids passed in, if any. The resulting list is uniquified and returned.
451
452 @param context: The context for which events should be queried.
453 """
454
455 if not evids and not ranges:
456 return []
457
458 if evids is None: evids = []
459 start = max(start, 0)
460
461
462 where = self.lookupManagedEntityWhere(context)
463 where = self.filteredWhere(where, filters)
464 if asof:
465 where += " and not (stateChange>%s and eventState=0)" % (
466 self.dateDB(asof))
467
468
469 if not ranges:
470 return evids
471 else:
472
473 events = []
474 for s,e in ranges:
475 events += self.getEventList(resultFields=('evid',),
476 where=where, orderby="%s %s" %
477 (sort, direction), severity=-1,
478 state=2, offset=s, rows=e)
479
480
481 evids = set(e.evid for e in events) | set(evids)
482 return list(evids)
483
484
485 - def getEventBatchME(self, me, selectstatus=None, resultFields=[],
486 where="", orderby="", severity=None, state=2,
487 startdate=None, enddate=None, offset=0, rows=0,
488 getTotalCount=False, filter="", goodevids=[],
489 badevids=[], **kwargs):
490 """
491 Returns a batch of events based on criteria from checked rows on the
492 event console.
493
494 The event console can show thousands of events, and we want to support a
495 "Select All" feature; enter this method. It builds a query based on the
496 select status from the console ("All", "None", "Acknowledged",
497 "Unacknowledged") and any checkboxes that have been modified manually.
498
499 @param me: The managed entity for which to query events.
500 @type me: L{ManagedEntity}
501 @param resultFields: The columns to return from the database.
502 @type resultFields: list
503 @param where: The base where clause to modify.
504 @type where: string
505 @param orderby: The "ORDER BY" string governing sort order.
506 @type orderby: string
507 @param severity: The minimum severity for which to query.
508 @type severity: int
509 @param state: The minimum state for which to query.
510 @type state: int
511 @param startdate: The early date limit
512 @type startdate: string, DateTime
513 @param enddate: The late date limit
514 @type enddate: string, DateTime
515 @param offset: The row at which to begin returning
516 @type offset: int
517 @param rows: DEPRECATED The number of rows to return (ignored).
518 @type rows: int
519 @param getTotalCount: Whether or not to return a count of the total
520 number of rows
521 @type getTotalCount: bool
522 @param filter: A glob by which to filter events
523 @type filter: string
524 @param goodevids: Ids of events that specifically should be included
525 @type goodevids: list
526 @param badevids: Ids of events that specifically should not be included
527 @type badevids: list
528 @return: Ids of matching events
529 @rtype: list
530 @todo: Remove unused parameters from the method definition
531 """
532 unused(getTotalCount, rows)
533 newwhere = self.lookupManagedEntityWhere(me)
534 if where: newwhere = self._wand(newwhere, '%s%s', where, '')
535 where = newwhere
536 badevidsstr, goodevidsstr = '',''
537 if not isinstance(goodevids, (list, tuple)): goodevids = [goodevids]
538 if not isinstance(badevids, (list, tuple)): badevids = [badevids]
539 if badevids: badevidsstr = " and evid not in ('%s')" %(
540 "','".join(badevids))
541 if goodevids: goodevidsstr = " and evid in ('%s')" %(
542 "','".join(goodevids))
543 if selectstatus=='all':
544 where += badevidsstr
545 elif selectstatus=='none':
546 where += goodevidsstr or ' and 0'
547 elif selectstatus=='acked':
548 oper = bool(goodevidsstr) and ' or' or ' and'
549 where += goodevidsstr + oper + " (eventstate=1 %s) " % badevidsstr
550 elif selectstatus=='unacked':
551 oper = bool(goodevidsstr) and ' or' or 'and'
552 where += goodevidsstr + oper + " (eventstate=0 %s) " % badevidsstr
553 try:
554 resultFields = kwargs['resultFields']; del kwargs['resultFields']
555 except KeyError:
556 resultFields = self.lookupManagedEntityResultFields(me.event_key)
557 events = self.getEventList(
558 filter=filter,
559 offset=offset,
560 getTotalCount=False,
561 startdate=startdate,
562 enddate=enddate, severity=severity,
563 state=state, orderby=orderby,
564 resultFields=resultFields,
565 where=where,**kwargs)
566 return [ev.evid for ev in events]
567
568
570 """This is a hook do not delete me!"""
571 return where
572
573
574 - def getEventList(self, resultFields=None, where="", orderby="",
575 severity=None, state=2, startdate=None, enddate=None, offset=0,
576 rows=0, getTotalCount=False, filter="", filters=None, **kwargs):
577 """
578 Fetch a list of events from the database matching certain criteria.
579
580 @param resultFields: The columns to return from the database.
581 @type resultFields: list
582 @param where: The base where clause to modify.
583 @type where: string
584 @param orderby: The "ORDER BY" string governing sort order.
585 @type orderby: string
586 @param severity: The minimum severity for which to query.
587 @type severity: int
588 @param state: The minimum state for which to query.
589 @type state: int
590 @param startdate: The early date limit
591 @type startdate: string, DateTime
592 @param enddate: The late date limit
593 @type enddate: string, DateTime
594 @param offset: The row at which to begin returning
595 @type offset: int
596 @param rows: The number of rows to return.
597 @type rows: int
598 @param getTotalCount: Whether or not to return a count of the total
599 number of rows
600 @type getTotalCount: bool
601 @param filter: A glob by which to filter events
602 @type filter: string
603 @return: Matching events as L{ZEvent}s.
604 @rtype: list
605 @todo: Remove unused parameters from the method definition
606 """
607 unused(kwargs)
608 paramValues = []
609 try:
610 where = self.restrictedUserFilter(where)
611 if not resultFields:
612 resultFields = self.defaultResultFields
613 resultFields = list(resultFields)
614 resultFields.extend(self.defaultFields)
615
616
617 fieldList = [x.lower() for x in self.getFieldList()]
618 for field in resultFields:
619 if field.lower() not in fieldList:
620 raise ('requested column %s is not valid' % field)
621
622 calcfoundrows = ''
623 if getTotalCount:
624 calcfoundrows = 'SQL_CALC_FOUND_ROWS'
625 select = ["select ", calcfoundrows, ','.join(resultFields),
626 "from %s where" % self.statusTable ]
627 if not where:
628 where = self.defaultWhere
629
630
631 where = where.replace('%', '%%')
632 def paramWhereAnd(where, fmt, field, value):
633 log.debug("where is %s" % where)
634 if value != None and where.find(field) == -1:
635 if where: where += " and "
636 where += fmt % (field,)
637 paramValues.append(value)
638 return where
639 where = paramWhereAnd(where, "%s >= %%s", self.severityField, severity)
640 where = paramWhereAnd(where, "%s <= %%s", self.stateField, state)
641 log.debug("filter is %s" % filter )
642 if filter:
643 where += ' and (%s) ' % (' or '.join(['%s LIKE "%%%s%%"' % (
644 x, filter) for x in resultFields]))
645 if startdate:
646 startdate, enddate = self._setupDateRange(startdate, enddate)
647 where = paramWhereAnd(where,"%s >= %%s",self.lastTimeField, startdate )
648 where = paramWhereAnd(where,"%s <= %%s",self.firstTimeField, enddate )
649
650 if filters is not None:
651 where = self.filteredWhere(where, filters, paramValues)
652 select.append(where)
653 if not orderby:
654 orderby = self.defaultOrderby
655 if orderby:
656
657 values = []
658 for x in orderby.split(','):
659 values.extend(x.split(' '))
660 values = [x for x in values if x]
661 log.debug("orderby is %s" % orderby)
662 log.debug("values is %s" % values)
663
664 for col in values:
665 col = col.lower()
666 if col not in ['desc','asc'] and col not in fieldList:
667 raise ("order by value %s not valid" % col)
668
669 select.append("order by")
670 select.append(orderby)
671 if rows:
672
673 int(offset)
674 int(rows)
675 select.append("limit %s, %s" % (offset, rows))
676 select.append(';')
677 select = " ".join(select)
678 if getTotalCount:
679 try: retdata, totalCount = self.checkCache(select)
680 except TypeError:
681 retdata, totalCount = self.checkCache(select), 100
682 else: retdata = self.checkCache(select)
683 if not False:
684 conn = self.connect()
685 try:
686 curs = conn.cursor()
687 curs.execute(select, paramValues)
688 retdata = []
689
690
691 if self.checkRemotePerm(ZEN_VIEW, self.dmd.Events):
692 eventPermission = True
693 else:
694 eventPermission = False
695 for row in curs.fetchall():
696 row = map(self.convert, resultFields, row)
697 evt = ZEvent(self, resultFields, row, eventPermission)
698 retdata.append(evt)
699 if getTotalCount:
700 curs.execute("SELECT FOUND_ROWS()")
701 totalCount = curs.fetchone()[0]
702 finally: self.close(conn)
703 if getTotalCount: self.addToCache(select, (retdata, totalCount))
704 else: self.addToCache(select, retdata)
705 self.cleanCache()
706 if getTotalCount:
707 return retdata, totalCount
708 else: return retdata
709 except:
710 log.exception("Failure querying events")
711 raise
712
713
715 """
716 Return the CSS class, number of acknowledged events, and number of
717 unacknowledged events, per severity, for a C{ManagedEntity}.
718
719 @param me: The object of the inquiry.
720 @type me: L{ManagedEntity}
721 @param severity: The minimum severity for which to retrieve events
722 @type severity: int
723 @param state: The minimum state for which to retrieve events
724 @type state: int
725 @param prodState: The minimum production state for which to retrieve
726 events
727 @type prodState: int
728 @return: List of lists of the form [class, acked count, unacked count].
729 @rtype: list
730 """
731 try:
732 where = self.lookupManagedEntityWhere(me)
733 return self.getEventSummary(where, severity, state, prodState)
734 except:
735 log.exception("event summary for %s failed" % me.getDmdKey())
736 raise
737
738
740 """
741 Return a list of tuples with number of events and the color of the
742 severity that the number represents.
743
744 This method should not be called directly, but overridden by subclasses.
745
746 @param where: The base where clause to modify.
747 @type where: string
748 @param severity: The minimum severity for which to retrieve events
749 @type severity: int
750 @param state: The minimum state for which to retrieve events
751 @type state: int
752 @param prodState: The minimum production state for which to retrieve
753 events
754 @type prodState: int
755 @return: List of lists of the form [class, acked count, unacked count].
756 @rtype: list
757 """
758 raise NotImplementedError
759
760
761 - def getEventDetailFromStatusOrHistory(self, evid=None, dedupid=None,
762 better=False):
763 try:
764 event = self.dmd.ZenEventManager.getEventDetail(
765 evid, dedupid, better)
766 except ZenEventNotFound:
767 event = self.dmd.ZenEventHistory.getEventDetail(evid, dedupid,
768 better)
769 return event
770
771
773 """
774 Return an EventDetail object for a particular event.
775
776 @param evid: Event ID
777 @type evid: string
778 @param dedupid: string used to determine duplicates
779 @type dedupid: string
780 @param better: provide even more detail than normal?
781 @type better: boolean
782 @return: fields from the event
783 @rtype: EventDetail object
784 """
785 idfield = evid and "evid" or "dedupid"
786 if not evid: evid = dedupid
787 cachekey = '%s%s' % (idfield, evid)
788 event = self.checkCache(cachekey)
789 if event: return event
790 fields = self.getFieldList()
791 selectevent = "select "
792 selectevent += ", ".join(fields)
793 selectevent += " from %s where" % self.statusTable
794 selectevent += " %s = '%s'" % (idfield, evid)
795 conn = self.connect()
796 try:
797 curs = conn.cursor()
798 curs.execute(selectevent)
799 evrow = curs.fetchone()
800 if not evrow:
801 raise ZenEventNotFound( "Event id '%s' not found" % evid)
802 evdata = map(self.convert, fields, evrow)
803 if better:
804 event = BetterEventDetail(self, fields, evdata)
805 else:
806 event = EventDetail(self, fields, evdata)
807
808 selectdetail = "select name, value from %s where" % self.detailTable
809 selectdetail += " evid = '%s'" % event.evid
810
811 curs.execute(selectdetail)
812 event._details = curs.fetchall()
813
814 selectlogs = "select userName, ctime, text"
815 selectlogs += " from %s where" % self.logTable
816 selectlogs += " evid = '%s' order by ctime desc" % event.evid
817
818 curs.execute(selectlogs)
819 jrows = curs.fetchall()
820 logs = []
821 for row in jrows:
822 user = self.cleanstring(row[0])
823 date = self.dateString(row[1])
824 text = row[2]
825 logs.append((user, date, text))
826 event._logs = logs
827 finally: self.close(conn)
828
829 self.addToCache(cachekey, event)
830 self.cleanCache()
831 return event
832
833
834 - def getStatusME(self, me, statusclass=None, **kwargs):
848
849
851 """Return status based on a where clause defined for the me event_type.
852 No fancy caching done this might be a little slow if there are a lot
853 of events. Where clause is evaled
854 """
855 where = self.lookupManagedEntityWhere(me)
856 select = "select count(*) from %s where %s" % (self.statusTable, where)
857 statusCount = self.checkCache(select)
858 if not statusCount:
859 conn = self.connect()
860 try:
861 curs = conn.cursor()
862
863 curs.execute(select)
864 statusCount = curs.fetchone()[0]
865 finally: self.close(conn)
866
867 self.addToCache(select,statusCount)
868 return statusCount
869
870
871 - def getOrganizerStatus(self, org, statusclass=None, severity=None,
872 state=0, where=""):
873 """see IEventStatus
874 """
875 orgfield = self.lookupManagedEntityField(org.event_key)
876 select = "select %s from %s where " % (orgfield, self.statusTable)
877 where = self._wand(where, "%s = '%s'", self.eventClassField,statusclass)
878 where = self._wand(where, "%s >= %s", self.severityField, severity)
879 where = self._wand(where, "%s <= %s", self.stateField, state)
880 select += where
881
882 statusCache = self.checkCache(select)
883 if not statusCache:
884 conn = self.connect()
885 try:
886 curs = conn.cursor()
887 curs.execute(select)
888 statusCache=[]
889 orgdict={}
890 for row in curs.fetchall():
891 orgfield = self.cleanstring(row[0])
892 if not orgfield: continue
893 if orgfield.startswith("|"): orgfield = orgfield[1:]
894 for orgname in orgfield.split("|"):
895 orgdict.setdefault(orgname, 0)
896 orgdict[orgname] += 1
897 statusCache = orgdict.items()
898 self.addToCache(select,statusCache)
899 finally: self.close(conn)
900 countevts = 0
901 for key, value in statusCache:
902 if key.startswith(org.getOrganizerName()):
903 countevts += value
904 return countevts
905
906
909 """Return list of tuples (org, count) for all organizers with events.
910 """
911 orgfield = self.lookupManagedEntityField(event_key)
912 select = "select %s, count from %s where " % (orgfield,self.statusTable)
913 where = self._wand(where, "%s >= %s", self.severityField, severity)
914 where = self._wand(where, "%s <= %s", self.stateField, state)
915 where = self._wand(where,"%s like '%s'",self.eventClassField,"/Status%")
916 select += where
917 statusCache = self.checkCache(select)
918 if not statusCache:
919 conn = self.connect()
920 try:
921 curs = conn.cursor()
922 curs.execute(select)
923 statusCache=[]
924 orgdict={}
925 for row in curs.fetchall():
926 orgfield = self.cleanstring(row[0])
927 if not orgfield: continue
928 if orgfield.startswith("|"): orgfield = orgfield[1:]
929 for orgname in orgfield.split("|"):
930 if not orgname: continue
931 count, total = orgdict.setdefault(orgname, (0,0))
932 count+=1
933 total+=row[1]
934 orgdict[orgname] = (count,total)
935 statusCache = [ [n, c[0], int(c[1])] for n, c in orgdict.items() ]
936 statusCache.sort(lambda x,y: cmp(x[1],y[1]))
937 statusCache.reverse()
938 if limit:
939 statusCache = statusCache[:limit]
940 self.addToCache(select,statusCache)
941 finally: self.close(conn)
942 return statusCache
943
944
952
953
960
961
967
968
970 """Return list of tuples (device, count, total) of events for
971 all devices with events.
972 """
973 where = self._wand(where, "%s >= %s", self.severityField, severity)
974 where = self._wand(where, "%s <= %s", self.stateField, state)
975 select = """select distinct device, count(device) as evcount,
976 sum(count) from status where %s group by device
977 having evcount > %s""" % (where, mincount)
978 statusCache = self.checkCache(select)
979 if not statusCache:
980 try:
981 conn = self.connect()
982 try:
983 curs = conn.cursor()
984 curs.execute(select)
985 statusCache = [ [d,int(c),int(s)] for d,c,s in curs.fetchall() ]
986
987 statusCache.sort(lambda x,y: cmp(x[1],y[1]))
988 statusCache.reverse()
989 if limit:
990 statusCache = statusCache[:limit]
991 finally: self.close(conn)
992 except:
993 log.exception(select)
994 raise
995 return statusCache
996
997
998 - def getDeviceStatus(self, device, statclass=None, countField=None,
999 severity=3, state=None, where=""):
1000 """see IEventStatus
1001 """
1002 if countField == None: countField = self.countField
1003 select = "select %s, %s from %s where " % (
1004 self.deviceField, self.countField, self.statusTable)
1005 where = self._wand(where, "%s = '%s'", self.eventClassField, statclass)
1006 where = self._wand(where, "%s >= %s", self.severityField, severity)
1007 where = self._wand(where, "%s <= %s", self.stateField, state)
1008 select += where
1009
1010 statusCache = self.checkCache(select)
1011 if not statusCache:
1012 try:
1013 conn = self.connect()
1014 try:
1015 curs = conn.cursor()
1016 curs.execute(select)
1017 statusCache = {}
1018 for dev, count in curs.fetchall():
1019 dev = self.cleanstring(dev)
1020 statusCache[dev] = count
1021 self.addToCache(select,statusCache)
1022 finally: self.close(conn)
1023 except:
1024 log.exception("status failed for device %s", device)
1025 return -1
1026 return statusCache.get(device, 0)
1027
1028
1031
1032
1035
1036
1038 import Availability
1039 for name in "device", "component", "eventClass", "systems", "severity":
1040 if hasattr(state, name):
1041 kw.setdefault(name, getattr(state, name))
1042 for name in "startDate", "endDate":
1043 if hasattr(state, name):
1044 kw.setdefault(name, Time.ParseUSDate(getattr(state, name)))
1045 kw.setdefault('startDate',
1046 time.time() - 60*60*24*self.defaultAvailabilityDays)
1047 return Availability.query(self.dmd, **kw)
1048
1049
1050 - def getHeartbeat(self, failures=True, simple=False, limit=0, db=None):
1051 """Return all heartbeat issues list of tuples (device, component, secs)
1052 """
1053 sel = """select device, component, lastTime from heartbeat """
1054 if failures:
1055 sel += "where DATE_ADD(lastTime, INTERVAL timeout SECOND) <= NOW();"
1056
1057 statusCache = self.checkCache(sel)
1058 cleanup = lambda : None
1059 if not statusCache:
1060 statusCache = []
1061 conn = self.connect()
1062 try:
1063 curs = conn.cursor()
1064 curs.execute(sel)
1065 res = list(curs.fetchall())
1066 res.sort(lambda x,y: cmp(x[2],y[2]))
1067 devclass = self.getDmdRoot("Devices")
1068 for devname, comp, dtime in res:
1069 dtime = "%d" % int(time.time()-dtime.timeTime())
1070 dev = devclass.findDevice(devname)
1071 if dev and not simple:
1072 alink = "<a href='%s'>%s</a>" % (
1073 dev.getPrimaryUrlPath(), dev.titleOrId())
1074 else: alink = devname
1075 statusCache.append([alink, comp, dtime, devname])
1076 if limit:
1077 statusCache = statusCache[:limit]
1078 cleanup()
1079 finally: self.close(conn)
1080 return statusCache
1081
1082
1084 beats = self.getHeartbeat(failures, simple, limit, db)
1085 return [{'alink':b[0], 'comp':b[1], 'dtime':b[2], 'devId':b[3]}
1086 for b in beats]
1087
1088
1089 - def getAllComponentStatus(self,
1090 statclass,
1091 countField=None,
1092 severity=3,
1093 state=1,
1094 where=""):
1095 "Fetch the counts on all components matching statClass"
1096 if countField == None: countField = self.countField
1097 select = "select %s, %s, %s from %s where "\
1098 % (self.deviceField, self.componentField, countField,
1099 self.statusTable)
1100 where = self._wand(where, "%s = '%s'", self.eventClassField, statclass)
1101 where = self._wand(where, "%s >= %s", self.severityField, severity)
1102 where = self._wand(where, "%s <= %s", self.stateField, state)
1103 select += where
1104 conn = self.connect()
1105 try:
1106 curs = conn.cursor()
1107 curs.execute(select)
1108 result = {}
1109 for dev, comp, count in curs.fetchall():
1110 dev = self.cleanstring(dev)
1111 comp = self.cleanstring(comp)
1112 result[dev,comp] = count
1113 return result
1114 finally:
1115 self.close(conn)
1116
1117
1134
1135
1136 - def getComponentStatus(self, device, component, statclass=None,
1137 countField=None, severity=3, state=1, where=""):
1138 """see IEventStatus
1139 """
1140 if countField == None: countField = self.countField
1141 select = "select %s, %s, %s from %s where "\
1142 % (self.deviceField, self.componentField, countField,
1143 self.statusTable)
1144 where = self._wand(where, "%s = '%s'", self.eventClassField, statclass)
1145 where = self._wand(where, "%s >= %s", self.severityField, severity)
1146 where = self._wand(where, "%s <= %s", self.stateField, state)
1147 select += where
1148 statusCache = self.checkCache(select)
1149 if not statusCache:
1150 conn = self.connect()
1151 try:
1152 curs = conn.cursor()
1153 curs.execute(select)
1154 statusCache ={}
1155 for dev, comp, count in curs.fetchall():
1156 dev = self.cleanstring(dev)
1157 comp = self.cleanstring(comp)
1158 statusCache[dev+comp] = count
1159 self.addToCache(select,statusCache)
1160 finally: self.close(conn)
1161 return statusCache.get(device+component, 0)
1162
1164 """
1165 Given a list of dicts with keys 'device', 'component', make a query to
1166 get an overall severity and device status for the group.
1167 """
1168 severity, state = 3, 1
1169 components = list(components)
1170
1171 def doQuery(query):
1172 conn = self.connect()
1173 data = None
1174 try:
1175 curs = conn.cursor()
1176 curs.execute(query)
1177 data = curs.fetchall()
1178 finally: self.close(conn)
1179 return data
1180
1181 select = "select MAX(%s) from %s where " % (self.severityField,
1182 self.statusTable)
1183 where = self._wand("", "%s >= %s", self.severityField, severity)
1184 where = self._wand(where, "%s <= %s", self.stateField, state)
1185 def componentWhere(device, component):
1186 return "device = '%s' and component= '%s'" % (device, component)
1187 cwheres = ' and ' + ' or '.join(['(%s)'% componentWhere(**comp)
1188 for comp in components])
1189 sevquery = select + where + cwheres
1190
1191 select = "select MAX(%s) from %s where " % (self.countField,
1192 self.statusTable)
1193 where = self._wand("", "%s >= %s", self.severityField, severity)
1194 where = self._wand(where, "%s <= %s", self.stateField, state)
1195 where = self._wand(where, "%s = '%s'", self.eventClassField,
1196 '/Status/Ping')
1197 devwhere = lambda d:"device = '%s'" % d
1198 dwheres = ' and ' + '(%s)' % (' or '.join(
1199 map(devwhere, [x['device'] for x in components])))
1200 statquery = select + where + dwheres
1201
1202 maxseverity = doQuery(sevquery)[0][0]
1203 maxstatus = doQuery(statquery)[0][0]
1204 return maxseverity, maxstatus
1205
1215
1216
1218 """Return a list of userids that correspond to the events in where.
1219 select distinct ownerid from status where
1220 device="win2k.confmon.loc" and eventState > 2
1221 """
1222 select ="select distinct ownerid from status where "
1223 where = self._wand(where, "%s >= %s", self.severityField, severity)
1224 where = self._wand(where, "%s <= %s", self.stateField, state)
1225 select += where
1226
1227 statusCache = self.checkCache(select)
1228 if statusCache: return statusCache
1229 conn = self.connect()
1230 try:
1231 curs = conn.cursor()
1232 curs.execute(select)
1233 statusCache = [ uid[0] for uid in curs.fetchall() if uid[0] ]
1234 self.addToCache(select,statusCache)
1235 finally: self.close(conn)
1236 return statusCache
1237
1238
1240 """
1241 Lookup and build where clause for managed entity.
1242
1243 @param me: managed entity
1244 @type me: object
1245 @return: where clause
1246 @rtype: string
1247 """
1248 key = me.event_key + "Where"
1249 wheretmpl = getattr(aq_base(self), key, False)
1250 if not wheretmpl:
1251 raise ValueError("No 'where' clause found for event_key %s" % me.event_key)
1252 return eval(wheretmpl,{'me':me})
1253
1254
1256 """
1257 Lookup database field for managed entity default
1258 using event_key.
1259
1260 @param event_key: event
1261 @type event_key: string
1262 @return: field for the managed entity
1263 @rtype: object
1264 """
1265 key = event_key + "Field"
1266 return getattr(aq_base(self), key, event_key)
1267
1268
1270 """
1271 Gets the column names that should be requested in an event query for
1272 this entity type.
1273
1274 Returns a set of result fields predefined for this entity type. If
1275 none have been defined, returns the default result fields.
1276
1277 >>> f = dmd.ZenEventManager.lookupManagedEntityResultFields('Device')
1278 >>> f==dmd.ZenEventManager.DeviceResultFields
1279 True
1280 >>> f = dmd.ZenEventManager.lookupManagedEntityResultFields('Robot')
1281 >>> f==dmd.ZenEventManager.defaultResultFields
1282 True
1283
1284 @param event_key: The event key of a managed entity.
1285 @type event_key: string
1286 @return: A tuple of strings representing columns in the database.
1287 """
1288 key = event_key + "ResultFields"
1289 fields = getattr(aq_base(self), key, self.defaultResultFields)
1290 return fields
1291
1292
1293 - def _wand(self, where, fmt, field, value):
1294 """
1295 >>> dmd.ZenEventManager._wand('where 1=1', '%s=%s', 'a', 'b')
1296 'where 1=1 and a=b'
1297 >>> dmd.ZenEventManager._wand('where a=5', '%s=%s', 'a', 'b')
1298 'where a=5'
1299 >>> dmd.ZenEventManager._wand('where b=a', '%s=%s', 'a', 'b')
1300 'where b=a'
1301 """
1302 if value != None and where.find(field) == -1:
1303 if where: where += " and "
1304 where += fmt % (field, value)
1305 return where
1306
1309 """
1310 Make a start and end date range that is at least one day long.
1311 returns a start and end date as a proper database element.
1312 """
1313 if enddate is None:
1314 enddate = DateTime.DateTime()-1
1315 if startdate is None:
1316 startdate = DateTime.DateTime()
1317 if type(enddate) == types.StringType:
1318 enddate = DateTime.DateTime(enddate, datefmt='us')
1319 enddate = enddate.latestTime()
1320 if type(startdate) == types.StringType:
1321 startdate = DateTime.DateTime(startdate, datefmt='us')
1322 startdate = startdate.earliestTime()
1323 startdate = self.dateDB(startdate)
1324 enddate = self.dateDB(enddate)
1325 return startdate, enddate
1326
1328 conn = self.connect()
1329 try:
1330 curs = conn.cursor()
1331 selstatement = ("SELECT AVG(CHAR_LENGTH(mycol))+20 FROM (SELECT %s AS "
1332 "mycol FROM %s WHERE %s IS NOT NULL LIMIT 500) AS "
1333 "a;") % (fieldname, self.statusTable, fieldname)
1334 curs.execute(selstatement)
1335 avglen = curs.fetchone()
1336 finally: self.close(conn)
1337 try: return float(avglen[0])
1338 except TypeError: return 10.
1339
1340
1341
1342
1343
1344
1345 security.declareProtected(ZEN_SEND_EVENTS, 'sendEvents')
1347 """Send a group of events to the backend.
1348 """
1349 count = 0
1350 for event in events:
1351 try:
1352 self.sendEvent(event)
1353 count += 1
1354 except Exception, ex:
1355 log.exception(ex)
1356 return count
1357
1358
1359 security.declareProtected(ZEN_SEND_EVENTS, 'sendEvent')
1361 """
1362 Send an event to the backend.
1363
1364 @param event: event
1365 @type event: event object
1366 @todo: implement
1367 """
1368 raise NotImplementedError
1369
1370
1371
1372
1373
1374
1390
1391
1392 security.declareProtected(ZEN_VIEW, "getFieldList")
1394 """Return a list of all fields in the status table of the backend.
1395 """
1396 if not getattr(self, '_fieldlist', None):
1397 self.loadSchema()
1398 return self._fieldlist
1399
1404
1406 """Return a list of possible event actions.
1407 """
1408 return self.eventActions
1409
1410 security.declareProtected(ZEN_COMMON,'getSeverities')
1412 """Return a list of tuples of severities [('Warning', 3), ...]
1413 """
1414 return self.severityConversions
1415
1417 """Return a string representation of the severity.
1418 """
1419 try:
1420 return self.severities[severity]
1421 except KeyError:
1422 return "Unknown"
1423
1425 """Return a list of tuples of priorities [('Warning', 3), ...]
1426 """
1427 return self.priorityConversions
1428
1430 """Return the priority name
1431 """
1432 try:
1433 return self.priorities[priority]
1434 except IndexError:
1435 return "Unknown"
1436
1465
1466
1471
1472
1474 ''' Return the img source for a status number
1475 '''
1476 if status < 0:
1477 src = 'grey'
1478 elif status == 0:
1479 src = 'green'
1480 else:
1481 src = 'red'
1482 return '/zport/dmd/img/%s_dot.png' % src
1483
1484
1486 """return the css class name to be used for this event.
1487 """
1488 __pychecker__='no-constCond'
1489 value = severity < 0 and "unknown" or severity
1490 acked = acked and "acked" or "noack"
1491 return "zenevents_%s_%s %s" % (value, acked, acked)
1492
1493
1495 """Check to see if a column is of type date.
1496 """
1497 if not self._schema:
1498 self.getFieldList()
1499 return self._schema.get(colName, False)
1500
1501
1508
1509
1510
1512 """Convert a date to its database format.
1513 """
1514 if isinstance(value, DateTime.DateTime):
1515 return "%.3f" % value.timeTime()
1516 elif isinstance(value, basestring):
1517 return "%.3f" % DateTime.DateTime(value).timeTime()
1518 return value
1519
1520
1522 """
1523 Prepare string values for db by escaping special characters.
1524
1525 @param value: string
1526 @type value: string
1527 @todo: implement
1528 """
1529 raise NotImplementedError
1530
1531
1533 """Load schema from database. If field is a date set value to true."""
1534 schema = {}
1535 fieldlist = []
1536 sql = "describe %s;" % self.statusTable
1537 conn = self.connect()
1538 try:
1539 curs = conn.cursor()
1540 curs.execute(sql)
1541 for row in curs.fetchall():
1542 fieldlist.append(row[0])
1543 col = self.cleanstring(row[0])
1544 if self.backend == "mysql":
1545 type = row[1] in ("datetime", "timestamp", "double")
1546 schema[col] = type
1547 if schema: self._schema = schema
1548 self._fieldlist = fieldlist
1549 finally: self.close(conn)
1550
1551
1553 """Are there event controls on this event list.
1554 """
1555 if self.isManager() and self.statusTable in ["status","history"]:
1556 return 1
1557 return 0
1558
1559 - def updateEvents(self, stmt, whereClause, reason,
1560 table="status", toLog=True):
1561 userId = getSecurityManager().getUser().getId()
1562 insert = 'INSERT INTO log (evid, userName, text) ' + \
1563 'SELECT evid, "%s", "%s" ' % (userId, reason) + \
1564 'FROM %s ' % table + whereClause
1565 query = stmt + ' ' + whereClause
1566 conn = self.connect()
1567 try:
1568 curs = conn.cursor()
1569 if toLog: curs.execute(insert)
1570 curs.execute(query)
1571 finally: self.close(conn)
1572 self.clearCache()
1573 self.manage_clearCache()
1574
1575 security.declareProtected(ZEN_MANAGE_EVENTS,'manage_addEvent')
1577 ''' Create an event from user supplied data
1578 '''
1579 eventDict = dict(
1580 summary = REQUEST.get('summary', ''),
1581 message = REQUEST.get('message', ''),
1582 device = REQUEST.get('device', ''),
1583 component = REQUEST.get('component', ''),
1584 severity = REQUEST.get('severity', ''),
1585 eventClassKey = REQUEST.get('eventClassKey', ''),
1586 )
1587
1588
1589 if REQUEST.get('eventClass', None):
1590 eventDict['eventClass'] = REQUEST['eventClass']
1591
1592 if not eventDict['device'] and not eventDict['component']:
1593 if REQUEST:
1594 messaging.IMessageSender(self).sendToBrowser(
1595 'Invalid Event',
1596 'You must specify a device and/or a component.',
1597 priority=messaging.WARNING
1598 )
1599 return self.callZenScreen(REQUEST)
1600 else:
1601 return
1602 evid = self.sendEvent(eventDict)
1603 if REQUEST and 'RESPONSE' in REQUEST:
1604 REQUEST['RESPONSE'].redirect('/zport/dmd/Events/viewEvents')
1605 else:
1606 return evid
1607
1608
1610 self.updateEvents('DELETE FROM status', whereClause, reason)
1611
1612
1613 security.declareProtected(ZEN_MANAGE_EVENTS,'manage_deleteEvents')
1615 "Delete the given event ids"
1616 if type(evids) == type(''):
1617 evids = [evids]
1618 num = len(evids)
1619 if evids:
1620 evids = ",".join([ "'%s'" % evid for evid in evids])
1621 userid = getSecurityManager().getUser()
1622 update = "update status set ownerid='%s' " % userid
1623 whereClause = ' where evid in (%s)' % evids
1624 self.updateEvents(update, whereClause, '', toLog=False)
1625 self.deleteEvents(whereClause, 'Deleted by user')
1626 if REQUEST:
1627 messaging.IMessageSender(self).sendToBrowser(
1628 'Moved To History',
1629 '%s event%s have been moved to history.' % (
1630 num, (num != 1 and 's') or '')
1631 )
1632 return self.callZenScreen(REQUEST)
1633
1635 fields = self.getFieldList()
1636 if 'deletedTime' in fields:
1637 fields.remove('deletedTime')
1638 fields = ','.join(fields)
1639
1640 fields = fields.replace('clearid','NULL')
1641 evmgr = self.dmd.ZenEventManager
1642 evmgr.updateEvents('INSERT status ' + \
1643 'SELECT %s FROM history' % fields,
1644 whereClause + ' ON DUPLICATE KEY UPDATE '+
1645 'status.count=status.count+history.count',
1646 reason, 'history', toLog=False)
1647 evmgr.updateEvents('DELETE FROM history', whereClause, \
1648 reason, 'history')
1649
1650 security.declareProtected(ZEN_MANAGE_EVENTS,'manage_undeleteEvents')
1652 "Move the given event ids into status and delete from history"
1653 if type(evids) == type(''):
1654 evids = [evids]
1655 num = len(evids)
1656 if evids:
1657 evids = ",".join([ "'%s'" % evid for evid in evids])
1658 whereClause = ' where evid in (%s)' % evids
1659 self.undeleteEvents(whereClause, 'Undeleted by user')
1660 if REQUEST:
1661 messaging.IMessageSender(self).sendToBrowser(
1662 'Undeleted',
1663 '%s events have been moved out of history.' % num
1664 )
1665 return self.callZenScreen(REQUEST)
1666
1667
1668 security.declareProtected(ZEN_MANAGE_EVENTS,'manage_deleteAllEvents')
1679
1680
1681 security.declareProtected(ZEN_MANAGE_EVENTS,'manage_deleteHistoricalEvents')
1684 """
1685 Delete historical events. If devices is given then only delete
1686 events for that device. If agedDays is given then only delete
1687 events that are older than that many days.
1688 devname and agedDays are mutually exclusive. No real reason for this
1689 other than there is no current need to use both in same call and I
1690 don't want to test the combination.
1691 This is an option during device deletion. It is also used
1692 by zenactions to keep history table clean.
1693
1694 NB: Device.deleteDevice() is not currently calling this when devices
1695 are deleted. See ticket #2996.
1696 """
1697 import subprocess
1698 import os
1699 import Products.ZenUtils.Utils as Utils
1700
1701 cmd = Utils.zenPath('Products', 'ZenUtils', 'ZenDeleteHistory.py')
1702 if devname:
1703 args = ['--device=%s' % devname]
1704 elif agedDays:
1705 args = ['--numDays=%s' % agedDays]
1706 else:
1707 return
1708 proc = subprocess.Popen(
1709 [cmd]+args, stdout=subprocess.PIPE,
1710 stderr=subprocess.STDOUT, env=os.environ)
1711
1712
1713
1714 unused(proc)
1715 if REQUEST:
1716 messaging.IMessageSender(self).sendToBrowser(
1717 'Events Deleted',
1718 'Historical events have been deleted.'
1719 )
1720 return self.callZenScreen(REQUEST)
1721
1722
1723 security.declareProtected(ZEN_MANAGE_EVENTS,'manage_deleteHeartbeat')
1738
1739
1740 security.declareProtected(ZEN_MANAGE_EVENTS,'manage_ackEvents')
1753
1754
1755 security.declareProtected(ZEN_MANAGE_EVENTS,'manage_ackEvents')
1768
1769
1770 security.declareProtected(ZEN_MANAGE_EVENTS,'manage_setEventStates')
1773 reason = None
1774 if eventState is not None and evids:
1775 eventState = int(eventState)
1776 if eventState > 0 and not userid:
1777 userid = getSecurityManager().getUser().getId()
1778 update = "update status set eventState=%s, ownerid='%s' " % (
1779 eventState, userid)
1780 whereClause = "where evid in ("
1781 whereClause += ",".join([ "'%s'" % evid for evid in evids]) + ")"
1782 reason = 'Event state changed to '
1783 try:
1784 reason += self.eventStateConversions[eventState][0]
1785 except KeyError:
1786 reason += 'unknown (%d)' % eventState
1787 self.updateEvents(update, whereClause, reason)
1788 if REQUEST:
1789 return self.callZenScreen(REQUEST)
1790
1791
1792 security.declareProtected(ZEN_MANAGE_EVENTS,'manage_setEventStates')
1795 """Create an event map from an event or list of events.
1796 """
1797 evclass = None
1798 evmap = None
1799 numCreated = 0
1800 numNotUnknown = 0
1801 numNoKey = 0
1802 if eventClass and evids:
1803 evclass = self.getDmdRoot("Events").getOrganizer(eventClass)
1804 sel = """select eventClassKey, eventClass, message
1805 from %s where evid in ('%s')"""
1806 sel = sel % (self.statusTable, "','".join(evids))
1807 conn = self.connect()
1808 try:
1809 curs = conn.cursor()
1810 curs.execute(sel);
1811 for row in curs.fetchall():
1812 evclasskey, curevclass, msg = row
1813 if curevclass != Unknown:
1814 numNotUnknown += 1
1815 continue
1816 if not evclasskey:
1817 numNoKey += 1
1818 continue
1819 evmap = evclass.createInstance(evclasskey)
1820 evmap.eventClassKey = evclasskey
1821 evmap.example = msg
1822 numCreated += 1
1823 evmap.index_object()
1824 finally: self.close(conn)
1825 elif REQUEST:
1826 if not evids:
1827 messaging.IMessageSender(self).sendToBrowser(
1828 'Error',
1829 'No events selected',
1830 priority=messaging.WARNING
1831 )
1832 elif not eventClass:
1833 messaging.IMessageSender(self).sendToBrowser(
1834 'Error',
1835 'No event class selected',
1836 priority=messaging.WARNING
1837 )
1838
1839 msg = ''
1840 if numNotUnknown:
1841 msg += ((msg and ' ') +
1842 '%s event%s %s not class /Unknown.' % (
1843 numNotUnknown,
1844 (numNotUnknown != 1 and 's') or '',
1845 (numNotUnknown != 1 and 'are') or 'is'))
1846 if numNoKey:
1847 msg += ((msg and ' ') +
1848 '%s event%s %s not have an event class key.' % (
1849 numNoKey,
1850 (numNoKey != 1 and 's') or '',
1851 (numNoKey != 1 and 'do') or 'does'))
1852 msg += (msg and ' ') + 'Created %s event mapping%s.' % (
1853 numCreated,
1854 (numCreated != 1 and 's') or '')
1855
1856 url = None
1857 if len(evids) == 1 and evmap:
1858 url = evmap.absolute_url()
1859 elif evclass and evmap:
1860 url = evclass.absolute_url()
1861
1862 if REQUEST:
1863 msg = REQUEST.get('message', '') + msg
1864
1865 messaging.IMessageSender(self).sendToBrowser('Event Map', msg)
1866
1867
1868 if getattr(REQUEST, 'dontRender', False):
1869 return ''
1870 if url:
1871 REQUEST['RESPONSE'].redirect(url)
1872 else:
1873 return msg, url
1874
1875
1876 security.declareProtected(ZEN_MANAGE_EVENTMANAGER,'manage_refreshConversions')
1886
1887
1888 security.declareProtected(ZEN_MANAGE_EVENTMANAGER,'manage_editCache')
1890 """Reset cache values"""
1891 self.timeout = int(timeout)
1892 self.clearthresh = int(clearthresh)
1893 if REQUEST:
1894 message = "Cache parameters set"
1895 return self.editCache(self, REQUEST, manage_tabs_message=message)
1896
1897
1898 security.declareProtected(ZEN_MANAGE_EVENTMANAGER,'manage_clearCache')
1908
1909
1910 security.declareProtected(ZEN_MANAGE_EVENTMANAGER,'manage_editEventManager')
1912 ''' Call zmanage_editProperties then take care of saving a few
1913 values to ZenEventHistory
1914 '''
1915 assert(self == self.dmd.ZenEventManager)
1916 self.zmanage_editProperties(REQUEST)
1917 self.dmd.ZenEventHistory.timeout = REQUEST['history_timeout']
1918 self.dmd.ZenEventHistory.clearthresh = REQUEST['history_clearthresh']
1919 self.dmd.ZenEventHistory.username = self.dmd.ZenEventManager.username
1920 self.dmd.ZenEventHistory.password = self.dmd.ZenEventManager.password
1921 self.dmd.ZenEventHistory.database = self.dmd.ZenEventManager.database
1922 self.dmd.ZenEventHistory.host = self.dmd.ZenEventManager.host
1923 self.dmd.ZenEventHistory.port = self.dmd.ZenEventManager.port
1924 if REQUEST: return self.callZenScreen(REQUEST)
1925
1926
1927 security.declareProtected(ZEN_MANAGE_EVENTMANAGER,'manage_clearHeartbeats')
1940
1941 security.declareProtected(ZEN_MANAGE_EVENTMANAGER,'zmanage_editProperties')
1943 ''' Need to handle editing of history event fields differently
1944 '''
1945 assert(self == self.dmd.ZenEventManager)
1946 screenName = REQUEST.get('zenScreenName', '')
1947 if screenName == 'editEventManagerHistoryFields':
1948 obj = self.dmd.ZenEventHistory
1949 else:
1950 obj = self
1951 if screenName == 'editEventManager':
1952
1953
1954 if REQUEST.has_key('mysql_pass'):
1955 REQUEST.form['password'] = REQUEST['mysql_pass']
1956 editProperties = ZenModelRM.zmanage_editProperties
1957
1958 editProperties(obj, REQUEST)
1959 if REQUEST: return self.callZenScreen(REQUEST)
1960
1961 security.declareProtected(ZEN_MANAGE_EVENTS, 'manage_addLogMessage')
1963 """
1964 Add a log message to an event
1965 """
1966 if not evid:
1967 return
1968 userId = getSecurityManager().getUser().getId()
1969 conn = self.connect()
1970 try:
1971 curs = conn.cursor()
1972 insert = 'INSERT INTO log (evid, userName, text) '
1973 insert += 'VALUES ("%s", "%s", "%s")' % (evid,
1974 userId,
1975 conn.escape_string(message))
1976 curs.execute(insert)
1977 finally: self.close(conn)
1978 self.clearCache('evid' + evid)
1979 self.dmd.ZenEventHistory.clearCache('evid' + evid)
1980 if REQUEST: return self.callZenScreen(REQUEST)
1981
1982
1983 security.declareProtected(ZEN_MANAGE_EVENTMANAGER, 'manage_addCommand')
2011
2012
2013 security.declareProtected(ZEN_MANAGE_EVENTMANAGER, 'manage_deleteCommands')
2015 """
2016 Delete an EventCommand
2017
2018 @param ids: commands to delete
2019 @type ids: list of strings
2020 @param REQUEST: Zope REQUEST object
2021 @type REQUEST: Zope REQUEST object
2022 """
2023 for id in ids:
2024 self.commands._delObject(id)
2025 if REQUEST: return self.callZenScreen(REQUEST)
2026
2027
2028
2029
2030
2031
2033 """Install skins into portal.
2034 """
2035 from Products.CMFCore.utils import getToolByName
2036 from Products.CMFCore.DirectoryView import addDirectoryViews
2037 from cStringIO import StringIO
2038 import string
2039
2040 out = StringIO()
2041 skinstool = getToolByName(self, 'portal_skins')
2042 if 'zenevents' not in skinstool.objectIds():
2043 addDirectoryViews(skinstool, 'skins', globals())
2044 out.write("Added 'zenevents' directory view to portal_skins\n")
2045 skins = skinstool.getSkinSelections()
2046 for skin in skins:
2047 path = skinstool.getSkinPath(skin)
2048 path = map(string.strip, string.split(path,','))
2049 if 'zenevents' not in path:
2050 try: path.insert(path.index('zenmodel'), 'zenevents')
2051 except ValueError:
2052 path.append('zenevents')
2053 path = string.join(path, ', ')
2054 skinstool.addSkinSelection(skin, path)
2055 out.write("Added 'zenevents' to %s skin\n" % skin)
2056 else:
2057 out.write(
2058 "Skipping %s skin, 'zenevents' is already set up\n" % skin)
2059 return out.getvalue()
2060