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