1
2
3
4
5
6
7
8
9
10
11 """
12 Operations for Events.
13
14 Available at: /zport/dmd/evconsole_router
15 """
16
17 import time
18 import logging
19 import re
20 from json import loads
21 from AccessControl import getSecurityManager
22 from zenoss.protocols.exceptions import NoConsumersException, PublishException
23 from zenoss.protocols.protobufs.zep_pb2 import STATUS_NEW, STATUS_ACKNOWLEDGED
24 from Products import Zuul
25 from Products.ZenUtils.Ext import DirectRouter
26 from Products.ZenUtils.extdirect.router import DirectResponse
27 from Products.ZenUtils.Time import isoToTimestamp
28 from Products.Zuul.decorators import require, serviceConnectionError
29 from Products.ZenUtils.guid.interfaces import IGlobalIdentifier, IGUIDManager
30 from Products.ZenEvents.EventClass import EventClass
31 from Products.ZenMessaging.audit import audit
32 from Products.ZenModel.ZenossSecurity import ZEN_MANAGE_EVENTS
33 from Products.ZenUtils.deprecated import deprecated
34 from Products.Zuul.utils import resolve_context
35 from Products.Zuul.utils import ZuulMessageFactory as _t
36 from Products.ZenUI3.browser.eventconsole.grid import column_config
37 from Products.Zuul.interfaces import ICatalogTool
38 from Products.Zuul.infos.event import EventCompatInfo, EventCompatDetailInfo
39 from zenoss.protocols.services import ServiceResponseError
40 from lxml.html.clean import clean_html
41
42
43 log = logging.getLogger('zen.%s' % __name__)
46 """
47 Parses the filter related params received from the ui to search
48 for "or clauses", "NULLs" and "NOTs"
49 """
50
51 NOT_SEPARATOR = "!!"
52 OR_SEPARATOR = "||"
53 NULL_CHAR='""'
54
56 """ """
57
58 detail_list = zep_facade.getDetailsMap().keys()
59 param_to_detail_mapping = zep_facade.ZENOSS_DETAIL_OLD_TO_NEW_MAPPING
60 null_numeric_detail_value = zep_facade.ZENOSS_NULL_NUMERIC_DETAIL_INDEX_VALUE
61 null_text_detail_value = zep_facade.ZENOSS_NULL_TEXT_DETAIL_INDEX_VALUE
62 numeric_details = [ d['key'] for d in zep_facade.getDetails() if d['type'] == 2 ]
63
64
65 self.PARSEABLE_PARAMS = [ 'device', 'component', 'eventClass', 'ownerid', 'summary', 'message', 'monitor' ]
66 self.PARAM_TO_FIELD_MAPPING = { 'device': 'element_title',
67 'component': 'element_sub_title',
68 'eventClass': 'event_class',
69 'ownerid': 'current_user_name',
70 'summary': 'event_summary',
71 'message' :'message',
72 'monitor': 'monitor' }
73 self.PARSEABLE_DETAILS = detail_list
74 self.PARAM_TO_DETAIL_MAPPING = param_to_detail_mapping
75 for detail in self.PARSEABLE_DETAILS:
76 if detail not in self.PARAM_TO_DETAIL_MAPPING.values():
77 self.PARAM_TO_DETAIL_MAPPING[detail] = detail
78 self.TRANSLATE_NULL = self.PARAM_TO_DETAIL_MAPPING.values()
79 self.EXCLUDABLE = self.PARSEABLE_PARAMS + self.PARAM_TO_DETAIL_MAPPING.keys()
80 self.NULL_NUMERIC_INDEX = null_numeric_detail_value
81 self.NULL_TEXT_INDEX = null_text_detail_value
82 self.NO_FRONT_WILDCARD = [ 'device', 'component', 'eventClass' ]
83 self.NUMERIC_DETAILS = numeric_details
84 self.NO_WILDCARD = self.NUMERIC_DETAILS[:]
85
87 """
88 Look for filter params that contain the NOT_SEPARATOR
89 @type params: dictionary
90 @param params: dictionary containing filter parameters from the ui
91 @return: dictionary with the params that must be NOT filtered
92 """
93 exclude_params = {}
94 if params is not None and isinstance(params, dict) and len(params) > 0:
95 for param in self.EXCLUDABLE:
96 value = params.get(param)
97 if value is not None and isinstance(value, basestring) and self.NOT_SEPARATOR in value:
98 value = self._cleanText(value)
99 clauses = value.split(self.NOT_SEPARATOR)
100 inclusion_clause = clauses[0].strip()
101 exclusion_clause = clauses[1].strip()
102
103 if len(exclusion_clause) > 0:
104 exclude_params[param] = exclusion_clause
105 if len(inclusion_clause) == 0:
106 del params[param]
107 else:
108 params[param] = inclusion_clause
109
110 return exclude_params
111
112 - def _cleanText(self, clause):
113 """ """
114 clause = re.sub('\s+', ' ', clause)
115 clause = clause.strip(' *')
116 return clause
117
119 """ """
120 filter = value.strip()
121 if filter != self.NULL_CHAR and field not in self.NO_WILDCARD:
122 if field in self.NO_FRONT_WILDCARD:
123 filter = '{0}*'.format(filter.strip())
124 else:
125 filter = '*{0}*'.format(filter.strip())
126
127 return filter
128
130 """
131 Given a filter field value, check if it contains the OR_SEPARATOR.
132 @type field: string
133 @param field: name of the field
134 @type value: string
135 @param value: field value received from the UI
136 @return: list of OR clauses
137 """
138 or_clauses = []
139
140 if isinstance(value, basestring):
141 value = self._cleanText(value)
142 if self.OR_SEPARATOR in value:
143 temp_or_clauses = value.split(self.OR_SEPARATOR)
144 or_clauses = [ self._addWildcardsToFilter(field, clause) for clause in temp_or_clauses if len(clause)>0 and clause != ' ']
145 elif field in self.TRANSLATE_NULL and self.NULL_CHAR in value:
146 or_clauses.append(self.NULL_CHAR)
147 else:
148 or_clauses.append(self._addWildcardsToFilter(field, value))
149 elif isinstance(value, list):
150 or_clauses = value
151
152
153
154
155
156 if len(or_clauses) > 0 and field in self.TRANSLATE_NULL:
157 null_index = self.NULL_NUMERIC_INDEX if field in self.NUMERIC_DETAILS else self.NULL_TEXT_INDEX
158 or_clauses = [ null_index if self.NULL_CHAR in str(c) else c for c in or_clauses ]
159
160 return or_clauses
161
163 """
164 Parses the filter params passed from the UI looking
165 for OR clauses or NULL values
166 @type params: dictionary
167 @param params: dict of filter params passed from the UI
168 @return
169 """
170 parsed_params = {}
171 for par in self.PARSEABLE_PARAMS:
172 if params.get(par) is not None:
173 value = params.get(par)
174 or_clauses = self._getOrClauses(field=par, value=value)
175 filter_param = self.PARAM_TO_FIELD_MAPPING[par]
176 parsed_params[filter_param] = or_clauses
177 return parsed_params
178
180 """
181 Parses the filter details passed from the UI looking
182 for OR clauses or NULL values
183 @type details: dictionary
184 @param details: dict of filter details passed from the UI
185 @return
186 """
187 parsed_details = {}
188 for detail in self.PARSEABLE_DETAILS:
189 if details.get(detail) is not None:
190 detail_value = details.get(detail)
191 or_clauses = self._getOrClauses(field=detail, value=detail_value)
192 parsed_details[detail] = or_clauses
193 return parsed_details
194
196 """
197 A JSON/ExtDirect interface to operations on events in ZEP
198 """
199
201 super(EventsRouter, self).__init__(context, request)
202 self.zep = Zuul.getFacade('zep', context)
203 self.catalog = ICatalogTool(context)
204 self.manager = IGUIDManager(context.dmd)
205 self._filterParser = _FilterParser(self.zep)
206
208 """
209 To view any events you either have to have administered roles or
210 be a global roled user
211 """
212 user = self.context.dmd.ZenUsers.getUserSettings()
213 if not user.hasNoGlobalRoles():
214 return True
215
216 return len(user.getAllAdminRoles()) > 0
217
219 try:
220 values = []
221 for t in value.split('/'):
222 values.append(int(isoToTimestamp(t)) * 1000)
223 return values
224 except ValueError:
225 log.warning("Invalid timestamp: %s", value)
226 return ()
227
229 """
230 When querying archived events we need to make sure that
231 we do not link to devices and components that are no longer valid
232 """
233 manager = self.manager
234 for event_summary in events:
235 occurrence = event_summary['occurrence'][0]
236 actor = occurrence['actor']
237
238 if actor.get('element_uuid') and \
239 actor.get('element_uuid') not in manager.table:
240 del actor['element_uuid']
241
242
243 if actor.get('element_sub_uuid') and \
244 actor.get('element_sub_uuid') not in manager.table:
245 del actor['element_sub_uuid']
246 yield event_summary
247
248 @serviceConnectionError
249 @require('ZenCommon')
250 - def queryArchive(self, page=None, limit=0, start=0, sort='lastTime', dir='desc', params=None, exclusion_filter=None, keys=None, uid=None, detailFormat=False):
251 if not self._canViewEvents():
252 return DirectResponse.succeed(
253 events = [],
254 totalCount = 0,
255 asof = time.time()
256 )
257
258 exclude_params = self._filterParser.findExclusionParams(params)
259 if len(exclude_params) > 0:
260 if exclusion_filter is None:
261 exclusion_filter = exclude_params
262 else:
263 exclusion_filter.update(exclude_params)
264
265 filter = self._buildFilter([uid], params)
266 if exclusion_filter is not None:
267 exclusion_filter = self._buildFilter([uid], exclusion_filter)
268 events = self.zep.getEventSummariesFromArchive(limit=limit, offset=start, sort=self._buildSort(sort,dir),
269 filter=filter, exclusion_filter=exclusion_filter)
270 eventFormat = EventCompatInfo
271 if detailFormat:
272 eventFormat = EventCompatDetailInfo
273
274 dmd = self.context.dmd
275
276 evdata = self._filterInvalidUuids(events['events'])
277 eventObs = [eventFormat(dmd, e) for e in evdata]
278 return DirectResponse.succeed(
279 events = Zuul.marshal(eventObs, keys),
280 totalCount = events['total'],
281 asof = time.time()
282 )
283
284 @serviceConnectionError
285 @require('ZenCommon')
286 - def query(self, limit=0, start=0, sort='lastTime', dir='desc', params=None, exclusion_filter=None, keys=None,
287 page=None, archive=False, uid=None, detailFormat=False):
288 """
289 Query for events.
290
291 @type limit: integer
292 @param limit: (optional) Max index of events to retrieve (default: 0)
293 @type start: integer
294 @param start: (optional) Min index of events to retrieve (default: 0)
295 @type sort: string
296 @param sort: (optional) Key on which to sort the return results (default:
297 'lastTime')
298 @type dir: string
299 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
300 (default: 'DESC')
301 @type params: dictionary
302 @param params: (optional) Key-value pair of filters for this search.
303 (default: None)
304 @type history: boolean
305 @param history: (optional) True to search the event history table instead
306 of active events (default: False)
307 @type uid: string
308 @param uid: (optional) Context for the query (default: None)
309 @rtype: dictionary
310 @return: B{Properties}:
311 - events: ([dictionary]) List of objects representing events
312 - totalCount: (integer) Total count of events returned
313 - asof: (float) Current time
314 """
315 if not self._canViewEvents():
316 return DirectResponse.succeed(
317 events = [],
318 totalCount = 0,
319 asof = time.time()
320 )
321
322 if archive:
323 return self.queryArchive(limit=limit, start=start, sort=sort,
324 dir=dir, params=params, exclusion_filter=exclusion_filter, keys=keys, uid=uid,
325 detailFormat=detailFormat)
326
327
328 if uid == "/zport/dmd/Devices":
329 uids = [x.getPrimaryId() for x in self.context.dmd.Devices.children()]
330 else:
331 uids = [uid]
332
333 exclude_params = self._filterParser.findExclusionParams(params)
334 if len(exclude_params) > 0:
335 if exclusion_filter is None:
336 exclusion_filter = exclude_params
337 else:
338 exclusion_filter.update(exclude_params)
339
340 filter = self._buildFilter(uids, params)
341 if exclusion_filter is not None:
342 exclusion_filter = self._buildFilter(uids, exclusion_filter)
343 events = self.zep.getEventSummaries(limit=limit, offset=start, sort=self._buildSort(sort,dir), filter=filter, exclusion_filter=exclusion_filter)
344 eventFormat = EventCompatInfo
345 if detailFormat:
346 eventFormat = EventCompatDetailInfo
347
348 dmd = self.context.dmd
349
350 evdata = self._filterInvalidUuids(events['events'])
351 eventObs = [eventFormat(dmd, e) for e in evdata]
352
353 return DirectResponse.succeed(
354 events = Zuul.marshal(eventObs, keys),
355 totalCount = events['total'],
356 asof = time.time()
357 )
358
359
360 @serviceConnectionError
361 @require('ZenCommon')
362 - def queryGenerator(self, sort='lastTime', dir='desc', evids=None, excludeIds=None, params=None,
363 archive=False, uid=None, detailFormat=False):
364 """
365 Query for events.
366
367 @type sort: string
368 @param sort: (optional) Key on which to sort the return results (default:
369 'lastTime')
370 @type dir: string
371 @param dir: (optional) Sort order; can be either 'ASC' or 'DESC'
372 (default: 'DESC')
373 @type params: dictionary
374 @param params: (optional) Key-value pair of filters for this search.
375 (default: None)
376 @type archive: boolean
377 @param archive: (optional) True to search the event archive instead
378 of active events (default: False)
379 @type uid: string
380 @param uid: (optional) Context for the query (default: None)
381 @rtype: generator
382 @return: Generator returning events.
383 """
384 if not self._canViewEvents():
385 return
386 includeFilter, excludeFilter = self._buildRequestFilters(uid, params, evids, excludeIds)
387
388 events = self.zep.getEventSummariesGenerator(filter=includeFilter, exclude=excludeFilter,
389 sort=self._buildSort(sort,dir), archive=archive)
390 eventFormat = EventCompatInfo
391 if detailFormat:
392 eventFormat = EventCompatDetailInfo
393 for event in events:
394 yield Zuul.marshal(eventFormat(self.context.dmd, event))
395
396 - def _buildSort(self, sort='lastTime', dir='desc'):
397 sort_list = [(sort,dir)]
398
399 if sort not in ('lastTime','evid'):
400 sort_list.append(('lastTime','desc'))
401 return sort_list
402
403
404 - def _buildFilter(self, uids, params, specificEventUuids=None, includeContextInUid=True):
405 """
406 Construct a dictionary that can be converted into an EventFilter protobuf.
407
408 @type params: dictionary
409 @param params: (optional) Key-value pair of filters for this search.
410 (default: None)
411 @type uids: iterable(string)
412 @param uids: (optional) Contexts for the query (default: None)
413 """
414 if not uids:
415 uids=[]
416 elif isinstance(uids, basestring):
417 uids = [uids]
418
419 if params:
420 log.debug('logging params for building filter: %s', params)
421 if isinstance(params, basestring):
422 params = loads(params)
423
424
425
426
427
428 params, details = self.zep.parseParameterDetails(params)
429
430 filterEventUuids = []
431
432
433 if specificEventUuids is None:
434 log.debug('No specific event uuids were passed in.')
435
436
437
438
439 evid = params.get('evid')
440 if evid:
441 if not isinstance(evid,(list, tuple)):
442 evid = [evid]
443 filterEventUuids.extend(evid)
444
445
446 else:
447 log.debug('Specific event uuids passed in: %s', specificEventUuids)
448 if not isinstance(specificEventUuids,(list, tuple)):
449 filterEventUuids = [specificEventUuids]
450 else:
451 filterEventUuids = specificEventUuids
452
453 log.debug('FilterEventUuids is: %s', filterEventUuids)
454
455
456
457 param_tags = params.get('tags')
458 if params.get('excludeNonActionables') and not Zuul.checkPermission(ZEN_MANAGE_EVENTS, self.context):
459 if not param_tags:
460 us = self.context.dmd.ZenUsers.getUserSettings()
461 param_tags = [IGlobalIdentifier(ar.managedObject()).getGUID() for ar in us.getAllAdminRoles()]
462 if param_tags:
463 param_tags = [tag for tag in param_tags if Zuul.checkPermission(ZEN_MANAGE_EVENTS, self.manager.getObject(tag))]
464 if not param_tags:
465 param_tags = ['dne']
466
467 filter_params = {
468 'severity': params.get('severity'),
469 'status': [i for i in params.get('eventState', [])],
470 'event_class': filter(None, [params.get('eventClass')]),
471 'first_seen': params.get('firstTime') and self._timeRange(params.get('firstTime')),
472 'last_seen': params.get('lastTime') and self._timeRange(params.get('lastTime')),
473 'status_change': params.get('stateChange') and self._timeRange(params.get('stateChange')),
474 'uuid': filterEventUuids,
475 'count_range': params.get('count'),
476 'element_title': params.get('device'),
477 'element_sub_title': params.get('component'),
478 'event_summary': params.get('summary'),
479 'current_user_name': params.get('ownerid'),
480 'agent': params.get('agent'),
481 'monitor': params.get('monitor'),
482 'fingerprint': params.get('dedupid'),
483 'tags': param_tags,
484 'details': details,
485 'event_key': params.get('eventKey'),
486 'event_class_key': params.get('eventClassKey'),
487 'event_group': params.get('eventGroup'),
488 'message': params.get('message'),
489 }
490 parsed_params = self._filterParser.parseParams(params)
491 filter_params.update(parsed_params)
492
493 parsed_details = self._filterParser.parseDetails(details)
494 if len(parsed_details) > 0:
495 filter_params['details'].update(parsed_details)
496
497 event_filter = self.zep.createEventFilter(**filter_params)
498 log.debug('Found params for building filter, ended up building the following:')
499 log.debug(event_filter)
500 elif specificEventUuids:
501
502 event_filter = self.zep.createEventFilter(
503 uuid = specificEventUuids
504 )
505 else:
506 log.debug('Did not get parameters, using empty filter.')
507 event_filter = {}
508
509 if not uids and includeContextInUid:
510 uids = [self.context]
511
512 contexts = (resolve_context(uid) for uid in uids)
513
514 context_uuids = []
515 for context in contexts:
516 if context and context.id not in ('Events', 'dmd'):
517 try:
518
519 if not context_uuids:
520 context_tag_filter = {
521 'tag_uuids': context_uuids
522 }
523
524
525 tag_filter = event_filter.setdefault('tag_filter', [])
526 tag_filter.append(context_tag_filter)
527 context_uuids.append(IGlobalIdentifier(context).getGUID())
528
529 except TypeError:
530 if isinstance(context, EventClass):
531 event_filter['event_class'] = [context.getDmdKey()]
532 else:
533 raise Exception('Unknown context %s' % context)
534
535 log.debug('Final filter will be:')
536 log.debug(event_filter)
537
538 return event_filter
539
541 """
542 Get event details.
543
544 @type evid: string
545 @param evid: Event ID to get details
546 @type history: boolean
547 @param history: Deprecated
548 @rtype: DirectResponse
549 @return: B{Properties}:
550 - event: ([dictionary]) List containing a dictionary representing
551 event details
552 """
553 event_summary = self.zep.getEventSummary(evid)
554 if event_summary:
555 eventData = Zuul.marshal(EventCompatDetailInfo(self.context.dmd, event_summary))
556 return DirectResponse.succeed(event=[eventData])
557 else:
558 raise Exception('Could not find event %s' % evid)
559
560 - def manage_events(self, evids=None, excludeIds=None, params=None, uid=None, asof=None, limit=None, timeout=None):
561 if Zuul.checkPermission(ZEN_MANAGE_EVENTS, self.context):
562 return True
563 if params.get('excludeNonActionables'):
564 return Zuul.checkPermission('ZenCommon', self.context)
565 return False
566
568 data = self.detail(evid).data['event'][0]
569 uuid = data['component_uuid'] or data['device_uuid']
570 if uuid is None:
571 ctx = self.context
572 else:
573 ctx = self.manager.getObject(uuid)
574 return Zuul.checkPermission(ZEN_MANAGE_EVENTS, ctx)
575
576 @require(write_event_logs)
577 - def write_log(self, evid=None, message=None):
578 """
579 Write a message to an event's log.
580
581 @type evid: string
582 @param evid: Event ID to log to
583 @type message: string
584 @param message: Message to log
585 @rtype: DirectResponse
586 @return: Success message
587 """
588
589 userName = getSecurityManager().getUser().getId()
590
591 self.zep.addNote(uuid=evid, message=clean_html(message), userName=userName)
592
593 return DirectResponse.succeed()
594
595 @require(ZEN_MANAGE_EVENTS)
596 - def postNote(self, uuid, note):
597 self.zep.postNote(uuid, note)
598 return DirectResponse.succeed()
599
601 """
602 Given common request parameters, build the inclusive and exclusive
603 filters for event update requests.
604 """
605
606 if uid is None and isinstance(self.context, EventClass):
607 uid = self.context
608
609 log.debug('Context while building request filters is: %s', uid)
610
611
612
613
614
615 includeUuids = None
616 if isinstance(evids, (list, tuple)):
617 log.debug('Found specific event ids, adding to params.')
618 includeUuids = evids
619
620 includeFilter = self._buildFilter([uid], params, specificEventUuids=includeUuids)
621 exclude_params = self._filterParser.findExclusionParams(params)
622
623
624
625 excludeFilter = None
626 if excludeIds or len(exclude_params) > 0:
627 if excludeIds is None:
628 excludeIds = {}
629
630
631 excludeFilter = self._buildFilter(None, exclude_params,
632 specificEventUuids=excludeIds.keys(),
633 includeContextInUid=False)
634
635 log.debug('The exclude filter:' + str(excludeFilter))
636 log.debug('Finished building request filters.')
637
638 return includeFilter, excludeFilter
639
640 @require(ZEN_MANAGE_EVENTS)
642 """
643 When performing updates from the event console, updates are performed in batches
644 to allow the user to see the progress of event changes and cancel out of updates
645 while they are in progress. This works by specifying a limit to one of the close,
646 acknowledge, or reopen calls in this router. The response will contain an
647 EventSummaryUpdateResponse, and if there are additional updates to be performed,
648 it will contain a next_request field with all of the parameters used to update
649 the next range of events.
650
651 @type next_request: dictionary
652 @param next_request: The next_request field from the previous updates.
653 """
654 log.debug('Starting next batch of updates')
655 status, summaryUpdateResponse = self.zep.nextEventSummaryUpdate(next_request)
656
657 log.debug('Completed updates: %s', summaryUpdateResponse)
658 return DirectResponse.succeed(data=summaryUpdateResponse)
659
660 @require(ZEN_MANAGE_EVENTS)
662 """
663 @type params: dictionary
664 @param params: Key-value pair of filters for this search.
665 """
666 if isinstance(params, basestring):
667 params = loads(params)
668
669 device = params['device']
670
671 log.debug('Clearing heartbeats for device: {device}'.format(device=device))
672
673 params['eventState'] = [STATUS_NEW, STATUS_ACKNOWLEDGED]
674 params['eventClass'] = '/Status/Heartbeat'
675
676 includeFilter, excludeFilter = self._buildRequestFilters(None, params, None, None)
677
678 status, summaryUpdateResponse = self.zep.closeEventSummaries(
679 eventFilter=includeFilter,
680 exclusionFilter=excludeFilter,
681 limit=limit,
682 )
683
684 log.debug('Done clearing heartbeats for device: {device}'.format(device=device))
685 log.debug(summaryUpdateResponse)
686 audit('UI.Device.ClearHeartbeats', device=device)
687
688 return DirectResponse.succeed(data=summaryUpdateResponse)
689
690 @require(manage_events)
691 - def close(self, evids=None, excludeIds=None, params=None, uid=None, asof=None, limit=None, timeout=None):
692 """
693 Close event(s).
694
695 @type evids: [string]
696 @param evids: (optional) List of event IDs to close (default: None)
697 @type excludeIds: [string]
698 @param excludeIds: (optional) List of event IDs to exclude from
699 close (default: None)
700 @type params: dictionary
701 @param params: (optional) Key-value pair of filters for this search.
702 (default: None)
703 @type uid: string
704 @param uid: (optional) Context for the query (default: None)
705 @type asof: float
706 @param asof: (optional) Only close if there has been no state
707 change since this time (default: None)
708 @type limit: The maximum number of events to update in this batch.
709 @param limit: (optional) Maximum number of events to update (default: None).
710 @type timeout: int
711 @param timeout: The time (in seconds) before the underlying saved search times out.
712 @rtype: DirectResponse
713 @return: Success message
714 """
715
716 log.debug('Issuing a close request.')
717
718 includeFilter, excludeFilter = self._buildRequestFilters(uid, params, evids, excludeIds)
719
720 status, summaryUpdateResponse = self.zep.closeEventSummaries(
721 eventFilter=includeFilter,
722 exclusionFilter=excludeFilter,
723 limit=limit,
724 timeout=timeout,
725 )
726
727 log.debug('Done issuing close request.')
728 log.debug(summaryUpdateResponse)
729
730 return DirectResponse.succeed(data=summaryUpdateResponse)
731
732 @require(manage_events)
733 - def acknowledge(self, evids=None, excludeIds=None, params=None, uid=None, asof=None, limit=None, timeout=None):
734 """
735 Acknowledge event(s).
736
737 @type evids: [string]
738 @param evids: (optional) List of event IDs to acknowledge (default: None)
739 @type excludeIds: [string]
740 @param excludeIds: (optional) List of event IDs to exclude from
741 acknowledgment (default: None)
742 @type params: dictionary
743 @param params: (optional) Key-value pair of filters for this search.
744 (default: None)
745 @type uid: string
746 @param uid: (optional) Context for the query (default: None)
747 @type asof: float
748 @param asof: (optional) Only acknowledge if there has been no state
749 change since this time (default: None)
750 @type limit: The maximum number of events to update in this batch.
751 @param limit: (optional) Maximum number of events to update (default: None).
752 @type timeout: int
753 @param timeout: The time (in seconds) before the underlying saved search times out.
754 @rtype: DirectResponse
755 @return: Success message
756 """
757 log.debug('Issuing an acknowledge request.')
758
759 includeFilter, excludeFilter = self._buildRequestFilters(uid, params, evids, excludeIds)
760
761 status, summaryUpdateResponse = self.zep.acknowledgeEventSummaries(
762 eventFilter=includeFilter,
763 exclusionFilter=excludeFilter,
764 limit=limit,
765 timeout=timeout,
766 )
767 log.debug('Done issuing acknowledge request.')
768 log.debug(summaryUpdateResponse)
769
770 return DirectResponse.succeed(data=summaryUpdateResponse)
771
772 @require(manage_events)
773 @deprecated
775 """
776 Deprecated, Use reopen
777 """
778 return self.reopen(*args, **kwargs)
779
780 @require(manage_events)
781 - def reopen(self, evids=None, excludeIds=None, params=None, uid=None, asof=None, limit=None, timeout=None):
782 """
783 Reopen event(s).
784
785 @type evids: [string]
786 @param evids: (optional) List of event IDs to reopen (default: None)
787 @type excludeIds: [string]
788 @param excludeIds: (optional) List of event IDs to exclude from
789 reopen (default: None)
790 @type params: dictionary
791 @param params: (optional) Key-value pair of filters for this search.
792 (default: None)
793 @type uid: string
794 @param uid: (optional) Context for the query (default: None)
795 @type asof: float
796 @param asof: (optional) Only reopen if there has been no state
797 change since this time (default: None)
798 @type limit: The maximum number of events to update in this batch.
799 @param limit: (optional) Maximum number of events to update (Default: None).
800 @type timeout: int
801 @param timeout: The time (in seconds) before the underlying saved search times out.
802 @rtype: DirectResponse
803 @return: Success message
804 """
805
806 log.debug('Issuing a reopen request.')
807
808 includeFilter, excludeFilter = self._buildRequestFilters(uid, params, evids, excludeIds)
809
810 status, summaryUpdateResponse = self.zep.reopenEventSummaries(
811 eventFilter=includeFilter,
812 exclusionFilter=excludeFilter,
813 limit=limit,
814 timeout=timeout,
815 )
816
817 log.debug('Done issuing reopen request.')
818 log.debug(summaryUpdateResponse)
819
820 return DirectResponse.succeed(data=summaryUpdateResponse)
821
822
823 @require(ZEN_MANAGE_EVENTS)
824 - def updateEventSummaries(self, update, event_filter=None, exclusion_filter=None, limit=None, timeout=None):
825 status, response = self.zep.updateEventSummaries(update, event_filter, exclusion_filter, limit, timeout=timeout)
826 return DirectResponse.succeed(data=response)
827
828
829 @require(ZEN_MANAGE_EVENTS)
830 - def add_event(self, summary, device, component, severity, evclasskey, evclass=None):
831 """
832 Create a new event.
833
834 @type summary: string
835 @param summary: New event's summary
836 @type device: string
837 @param device: Device id to use for new event
838 @type component: string
839 @param component: Component uid to use for new event
840 @type severity: string
841 @param severity: Severity of new event. Can be one of the following:
842 Critical, Error, Warning, Info, Debug, or Clear
843 @type evclasskey: string
844 @param evclasskey: The Event Class Key to assign to this event
845 @type evclass: string
846 @param evclass: Event class for the new event
847 @rtype: DirectResponse
848 """
849 device = device.strip()
850 try:
851 self.zep.create(summary, severity, device, component, eventClassKey=evclasskey,
852 eventClass=evclass)
853 return DirectResponse.succeed("Created event")
854 except NoConsumersException:
855
856
857 msg = 'Queued event. Check zeneventd status on <a href="/zport/dmd/daemons">Services</a>'
858 return DirectResponse.succeed(msg, sticky=True)
859 except PublishException, e:
860
861 log.exception("Failed creating event")
862 return DirectResponse.exception(e, "Failed to create event")
863
864 @property
866 configSchema =[{
867 'id': 'event_age_disable_severity',
868 'name': _t("Don't Age This Severity and Above"),
869 'xtype': 'eventageseverity',
870 },{
871 'id': 'event_age_severity_inclusive',
872 'xtype': 'hidden',
873 },{
874 'id': 'event_age_interval_minutes',
875 'name': _t('Event Aging Threshold (minutes)'),
876 'xtype': 'numberfield',
877 'minValue': 0,
878 'allowNegative': False,
879 },{
880 'id': 'aging_interval_milliseconds',
881 'name': _t('Event Aging Interval (milliseconds)'),
882 'xtype': 'numberfield',
883 'minValue': 1,
884 'allowNegative': False
885 },{
886 'id': 'aging_limit',
887 'name': _t('Event Aging Limit'),
888 'xtype': 'numberfield',
889 'minValue': 1,
890 'allowNegative': False
891 },{
892 'id': 'event_archive_interval_minutes',
893 'name': _t('Event Archive Threshold (minutes)'),
894 'xtype': 'numberfield',
895 'minValue': 1,
896 'maxValue': 43200,
897 'allowNegative': False,
898 },{
899 'id': 'archive_interval_milliseconds',
900 'name': _t('Event Archive Interval (milliseconds)'),
901 'xtype': 'numberfield',
902 'minValue': 1,
903 'allowNegative': False,
904 },{
905 'id': 'archive_limit',
906 'name': _t('Event Archive Limit'),
907 'xtype': 'numberfield',
908 'minValue': 1,
909 'allowNegative': False,
910 },{
911 'id': 'event_archive_purge_interval_days',
912 'minValue': 1,
913 'name': _t('Delete Archived Events Older Than (days)'),
914 'xtype': 'numberfield',
915 'allowNegative': False,
916 },{
917 'id': 'default_syslog_priority',
918 'name': _t('Default Syslog Priority'),
919 'xtype': 'numberfield',
920 'allowNegative': False,
921 'value': self.context.dmd.ZenEventManager.defaultPriority
922 },{
923 'id': 'default_availability_days',
924 'name': _t('Default Availability Report (days)'),
925 'xtype': 'numberfield',
926 'allowNegative': False,
927 'minValue': 1,
928 'value': self.context.dmd.ZenEventManager.defaultAvailabilityDays
929 },{
930 'id': 'event_max_size_bytes',
931 'name': _t('Max Event Size In Bytes'),
932 'xtype': 'numberfield',
933 'allowNegative': False,
934 'minValue': 8192,
935 'maxValue': 102400,
936 },{
937 'id': 'index_summary_interval_milliseconds',
938 'name': _t('Summary Index Interval (milliseconds)'),
939 'xtype': 'numberfield',
940 'allowNegative': False,
941 'minValue': 1
942 },{
943 'id': 'index_archive_interval_milliseconds',
944 'name': _t('Archive Index Interval (milliseconds)'),
945 'xtype': 'numberfield',
946 'allowNegative': False,
947 'minValue': 1
948 },{
949 'id': 'index_limit',
950 'name': _t('Index Limit'),
951 'xtype': 'numberfield',
952 'allowNegative': False,
953 'minValue': 1
954 },{
955 'id': 'event_time_purge_interval_days',
956 'name': _t('Event Time Purge Interval (days)'),
957 'xtype': 'numberfield',
958 'allowNegative': False,
959 'minValue': 1
960 },{
961 'id': 'enable_event_flapping_detection',
962 'name': _t('Enable Event Flapping Detection'),
963 'xtype': 'checkbox',
964 }, {
965 'id': 'flapping_event_class',
966 'name': _t('Event Flapping Event Class'),
967 'xtype': 'eventclass'
968 }]
969 return configSchema
970
972 """
973 Copy the values and defaults from ZEP to our schema
974 """
975 for conf in configSchema:
976 if not data.get(conf['id']):
977 continue
978 prop = data[conf['id']]
979 conf.update(prop)
980 return configSchema
981
982 @require('ZenCommon')
990
991 @require('Manage DMD')
993 """
994 @type values: Dictionary
995 @param values: Key Value pairs of config values
996 """
997
998 empty_keys = [k for k,v in values.iteritems() if isinstance(v, basestring) and not len(v)]
999 for empty_key in empty_keys:
1000 del values[empty_key]
1001
1002
1003 defaultSyslogPriority = values.pop('default_syslog_priority', None)
1004 if defaultSyslogPriority is not None:
1005 self.context.dmd.ZenEventManager.defaultPriority = int(defaultSyslogPriority)
1006
1007 defaultAvailabilityDays = values.pop('default_availability_days', None)
1008 if defaultAvailabilityDays is not None:
1009 self.context.dmd.ZenEventManager.defaultAvailabilityDays = int(defaultAvailabilityDays)
1010
1011 self.zep.setConfigValues(values)
1012 return DirectResponse.succeed()
1013
1015 """
1016 Get the current event console field column configuration.
1017
1018 @type uid: string
1019 @param uid: (optional) UID context to use (default: None)
1020 @type archive: boolean
1021 @param archive: (optional) True to use the event archive instead
1022 of active events (default: False)
1023 @rtype: [dictionary]
1024 @return: A list of objects representing field columns
1025 """
1026 return column_config(self.request, archive)
1027
1028 @require(ZEN_MANAGE_EVENTS)
1030 """
1031 Associate event(s) with an event class.
1032
1033 @type evrows: [dictionary]
1034 @param evrows: List of event rows to classify
1035 @type evclass: string
1036 @param evclass: Event class to associate events to
1037 @rtype: DirectResponse
1038 @return: B{Properties}:
1039 - msg: (string) Success/failure message
1040 - success: (boolean) True if class update successful
1041 """
1042 msg, url = self.zep.createEventMapping(evrows, evclass)
1043 if url:
1044 msg += " | "+url.split('/dmd/')[1]
1045 return DirectResponse(msg, success=bool(url))
1046
1047 @require(ZEN_MANAGE_EVENTS)
1049 """
1050 Clear all heartbeat events
1051
1052 @rtype: DirectResponse
1053 @return: B{Properties}:
1054 - success: (boolean) True if heartbeats deleted successfully
1055 """
1056 self.zep.deleteHeartbeats()
1057 audit('UI.Event.ClearHeartbeats', self.context)
1058 return DirectResponse.succeed()
1059
1060 @require(ZEN_MANAGE_EVENTS)
1062 """
1063 Clears a specific heartbeat event.
1064
1065 @type monitor: basestring
1066 @param monitor: The heartbeat monitor (i.e. 'localhost').
1067 @type daemon: basestring
1068 @param daemon: The heartbeat daemon (i.e. 'zenhub').
1069 @rtype: DirectResponse
1070 @return: A DirectResponse indicating success or failure.
1071 """
1072 self.zep.deleteHeartbeat(monitor, daemon)
1073 audit('UI.Event.ClearHeartbeat', self.context, monitor=monitor,
1074 daemon=daemon)
1075 return DirectResponse.succeed()
1076
1077 @require(ZEN_MANAGE_EVENTS)
1079 """
1080 On success, returns the status.
1081 """
1082 try:
1083 resp = self.zep.updateDetails(evid, **detailInfo)
1084 except ServiceResponseError as ex:
1085 return DirectResponse.fail(msg=str(ex))
1086 audit('UI.Event.UpdateEventDetails', self.context, evid=evid,
1087 details=detailInfo)
1088 return DirectResponse.succeed(status=resp[0]['status'])
1089