Package Products :: Package ZenEvents :: Package events2 :: Module proxy
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenEvents.events2.proxy

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2010, Zenoss Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify it 
  7  # under the terms of the GNU General Public License version 2 or (at your 
  8  # option) any later version as published by the Free Software Foundation. 
  9  # 
 10  # For complete information please visit: http://www.zenoss.com/oss/ 
 11  # 
 12  ########################################################################### 
 13  from itertools import imap 
 14  from Products.ZenUtils.Time import LocalDateTimeFromMilli 
 15  from Products.ZenEvents.events2.fields import EventField, EventSummaryField, ZepRawEventField 
 16  from zenoss.protocols.protobufs.model_pb2 import DEVICE, COMPONENT 
 17  from zenoss.protocols.protobufs.zep_pb2 import ( 
 18      STATUS_NEW, 
 19      STATUS_ACKNOWLEDGED, 
 20      STATUS_SUPPRESSED, 
 21      STATUS_CLOSED, 
 22      STATUS_CLEARED, 
 23      STATUS_DROPPED, 
 24      STATUS_AGED, 
 25      SEVERITY_CLEAR, 
 26      EventTag, 
 27      EventDetail 
 28  ) 
 29  from zenoss.protocols.jsonformat import to_dict 
 30   
 31  import logging 
 32  log = logging.getLogger('zen.%s' % __name__) 
33 34 -class EventTagProxy(object):
35 """ 36 A proxy for a tag UUID dictionary. Maps org.zenoss.protocols.zep.EventTag 37 to a dictionary. 38 """
39 - def __init__(self, eventProtobufWithTags):
40 self._eventProtobuf = eventProtobufWithTags 41 self._tags = {} 42 self._load()
43
44 - def _load(self):
45 for tag in self._eventProtobuf.tags: 46 tag_uuids = self._tags.get(tag.type) 47 if not tag_uuids: 48 self._tags[tag.type] = tag_uuids = set() 49 for tagUuid in tag.uuid: 50 tag_uuids.add(tagUuid)
51
52 - def add(self, type, uuid):
53 tag_uuids = self._tags.get(type) 54 if not tag_uuids: 55 self._tags[type] = tag_uuids = set() 56 57 if not uuid in tag_uuids: 58 tag_uuids.add(uuid) 59 60 event_tag = None 61 for tag in self._eventProtobuf.tags: 62 if tag.type == type: 63 event_tag = tag 64 break 65 else: 66 event_tag = self._eventProtobuf.tags.add() 67 event_tag.type = type 68 69 event_tag.uuid.append(uuid)
70
71 - def addAll(self, type, uuids):
72 for uuid in uuids: 73 self.add(type, uuid)
74
75 - def getByType(self, type):
76 return self._tags.get(type, ())
77
78 - def clearType(self, removetype):
79 # accept a single type or a list of types - if a single value given, make it a 1-element list 80 81 # if a generator was given, consume it into a temporary list 82 if hasattr(removetype, 'next'): 83 removetype = list(removetype) 84 85 # make single value into a temporary list 86 if not hasattr(removetype, '__iter__'): 87 removetype = [removetype] 88 89 # remove all entries from mapping 90 for typ in removetype: 91 if typ in self._tags: 92 del self._tags[typ] 93 94 # clear values from protobuf tags by assigning new list comprehension into 95 # protobuf tags list in place (using [:] slice would be a lot easier, but not implemented) 96 97 # This doesn't work - see http://code.google.com/p/protobuf/issues/detail?id=286 98 #saveTags = [tag for tag in self._eventProtobuf.tags if tag.type not in removetype] 99 saveTags = [] 100 for tag in self._eventProtobuf.tags: 101 if tag.type not in removetype: 102 cloned = EventTag() 103 cloned.MergeFrom(tag) 104 saveTags.append(cloned) 105 106 del self._eventProtobuf.tags[:] 107 self._eventProtobuf.tags.extend(saveTags)
108
109 110 -class EventDetailProxy(object):
111 """ 112 A proxy for a details dictionary. Maps org.zenoss.protocols.zep.EventDetail 113 to a dictionary. 114 """
115 - def __init__(self, eventProtobuf):
116 self.__dict__['_eventProtobuf'] = eventProtobuf 117 self.__dict__['_map'] = {} 118 119 for detail in self._eventProtobuf.details: 120 self._map[detail.name] = detail
121
122 - def __getattr__(self, name):
123 try: 124 return self[name] 125 except KeyError: 126 raise AttributeError(name)
127
128 - def __setattr__(self, name, value):
129 self[name] = value
130
131 - def __delitem__(self, key):
132 if key in self._map: 133 item = self._map.pop(key) 134 # This doesn't work - see http://code.google.com/p/protobuf/issues/detail?id=286 135 #savedetails = [det for det in self._eventProtobuf.details if det is not item] 136 savedetails = [] 137 for det in self._eventProtobuf.details: 138 if det.name != item.name: 139 cloned = EventDetail() 140 cloned.MergeFrom(det) 141 savedetails.append(cloned) 142 self._map[cloned.name] = cloned 143 del self._eventProtobuf.details[:] 144 self._eventProtobuf.details.extend(savedetails)
145
146 - def __getitem__(self, key):
147 item = self._map[key] 148 # Details are expected to be single values, 149 # we'll just have to do our best to make it so 150 if len(item.value) == 0: 151 return None 152 if len(item.value) == 1: 153 return item.value[0] 154 else: 155 raise Exception('Detail %s has more than one value but the old event system expects only one: %s' % (item.name, item.value))
156
157 - def __setitem__(self, key, value):
158 # Prep the field 159 if value: 160 if not key in self._map: 161 item = self._eventProtobuf.details.add() 162 item.name = key 163 self._map[key] = item 164 item = self._map[key] 165 item.ClearField(EventField.Detail.VALUE) 166 # Assume multivalue details 167 if not isinstance(value, (set, list, tuple)): 168 value = (value,) 169 # Set each detail if it exists 170 for val in imap(str, value): 171 if val: 172 item.value.append(val)
173
174 - def __contains__(self, key):
175 return key in self._map
176
177 - def __len__(self):
178 return len(self._map)
179
180 - def get(self, key, default=None):
181 try: 182 return self[key] 183 except KeyError: 184 return default
185
186 - def set(self, key, value):
187 self[key] = value
188
189 - def getAll(self, key, default=None):
190 """ 191 The normal __getitem__ and get() methods throw an exception for multi-valued details. This one specifically 192 allows multi-valued details. 193 """ 194 try: 195 return self._map[key].value 196 except KeyError: 197 return default
198
199 -class ProtobufWrapper(object):
200 """ 201 Conveinence wrapper for protobufs to make sure fields 202 are actually set. 203 """
204 - def __init__(self, pb):
205 self.__dict__['_pb'] = pb
206
207 - def get(self, key, default=None):
208 if self._pb.HasField(key): 209 return getattr(self._pb, key) 210 else: 211 return default
212
213 - def set(self, key, value):
214 setattr(self.__dict__['_pb'], key, value)
215
216 - def __getattr__(self, name):
217 return getattr(self._pb, name)
218
219 - def __setattr__(self, name, value):
220 self.set(name, value)
221
222 - def __delattr__(self, name):
223 self._pb.ClearField(name)
224
225 - def HasField(self, name):
226 return self._pb.HasField(name)
227
228 -class EventProxy(object):
229 """ 230 Wraps an org.zenoss.protobufs.zep.Event 231 and makes it look like an old style Event. 232 """ 233 234 DEVICE_PRIORITY_DETAIL_KEY = "zenoss.device.priority" 235 PRODUCTION_STATE_DETAIL_KEY = "zenoss.device.production_state" 236 DEVICE_IP_ADDRESS_DETAIL_KEY = 'zenoss.device.ip_address' 237 DEVICE_SYSTEMS_DETAIL_KEY = 'zenoss.device.systems' 238 DEVICE_GROUPS_DETAIL_KEY = 'zenoss.device.groups' 239 DEVICE_LOCATION_DETAIL_KEY = 'zenoss.device.location' 240 DEVICE_CLASS_DETAIL_KEY = 'zenoss.device.device_class' 241
242 - def __init__(self, eventProtobuf):
243 self.__dict__['_event'] = ProtobufWrapper(eventProtobuf) 244 self.__dict__['_clearClasses'] = set() 245 self.__dict__['_readOnly'] = {} 246 self.__dict__['details'] = EventDetailProxy(self._event) 247 self.__dict__['_tags'] = EventTagProxy(self._event)
248
249 - def updateFromDict(self, data):
250 for key, value in data.iteritems(): 251 setattr(self, key, value)
252 253 @property
254 - def created(self):
255 t = self._event.get(EventField.CREATED_TIME) 256 if t: 257 return t / 1000
258 @property
259 - def agent(self):
260 return self._event.get(EventField.AGENT)
261 262 @agent.setter
263 - def agent(self, val):
264 self._event.set(EventField.AGENT, val)
265 266 @property
267 - def severity(self):
268 return self._event.get(EventField.SEVERITY)
269 270 @severity.setter
271 - def severity(self, val):
272 self._event.set(EventField.SEVERITY, int(val))
273 274 @property
275 - def device(self):
276 return self._event.actor.element_identifier
277 278 @device.setter
279 - def device(self, val):
280 self._event.actor.element_identifier = val 281 self._event.actor.element_type_id = DEVICE 282 self._event.actor.ClearField(EventField.Actor.ELEMENT_UUID)
283 284 @property
285 - def component(self):
286 return self._event.actor.element_sub_identifier
287 288 @component.setter
289 - def component(self, val):
290 self._event.actor.element_sub_identifier = val 291 self._event.actor.element_sub_type_id = COMPONENT 292 self._event.actor.ClearField(EventField.Actor.ELEMENT_SUB_UUID)
293 294 @property
295 - def eventClass(self):
296 eventClassValue = self._event.get(EventField.EVENT_CLASS) 297 if isinstance( eventClassValue, unicode ): 298 eventClassValue = str( eventClassValue ) 299 return eventClassValue
300 301 @eventClass.setter
302 - def eventClass(self, val):
303 self._event.set(EventField.EVENT_CLASS, val)
304 305 @property
306 - def prodState(self):
307 state = self.details.get(EventProxy.PRODUCTION_STATE_DETAIL_KEY) 308 if state: 309 return int(state)
310 311 @prodState.setter
312 - def prodState(self, val):
314 315 @property
316 - def summary(self):
317 return self._event.get(EventField.SUMMARY)
318 319 @summary.setter
320 - def summary(self, val):
321 self._event.set(EventField.SUMMARY, val)
322 323 @property
324 - def message(self):
325 return self._event.get(EventField.MESSAGE)
326 327 @message.setter
328 - def message(self, val):
329 self._event.set(EventField.MESSAGE, val)
330 331 @property
332 - def facility(self):
333 return self._event.get(EventField.SYSLOG_FACILITY)
334 335 @facility.setter
336 - def facility(self, val):
337 self._event.set(EventField.SYSLOG_FACILITY, val)
338 339 @property
340 - def eventClassKey(self):
341 return self._event.get(EventField.EVENT_CLASS_KEY)
342 343 @eventClassKey.setter
344 - def eventClassKey(self, val):
345 self._event.set(EventField.EVENT_CLASS_KEY, val)
346 347 @property
348 - def dedupid(self):
349 return self._event.get(EventField.FINGERPRINT)
350 351 @dedupid.setter
352 - def dedupid(self, val):
353 self._event.set(EventField.FINGERPRINT, val)
354 355 @property
356 - def monitor(self):
357 return self._event.get(EventField.MONITOR)
358 359 @monitor.setter
360 - def monitor(self, val):
361 self._event.set(EventField.MONITOR, val)
362 363 @property
364 - def ntevid(self):
365 return self._event.get(EventField.NT_EVENT_CODE)
366 367 @ntevid.setter
368 - def ntevid(self, val):
369 self._event.set(EventField.NT_EVENT_CODE, val)
370 371 @property
372 - def DevicePriority(self):
376 377 @DevicePriority.setter
378 - def DevicePriority(self, val):
380 381 @property
382 - def priority(self):
383 return self._event.get(EventField.SYSLOG_PRIORITY)
384 385 @priority.setter
386 - def priority(self, val):
387 self._event.set(EventField.SYSLOG_PRIORITY, val)
388 389 @property
390 - def evid(self):
391 return self._event.get(EventField.UUID)
392 393 @property
394 - def eventKey(self):
395 return self._event.get(EventField.EVENT_KEY)
396 397 @eventKey.setter
398 - def eventKey(self, val):
399 self._event.set(EventField.EVENT_KEY, val)
400 401 @property
402 - def eventGroup(self):
403 return self._event.get(EventField.EVENT_GROUP)
404 405 @eventGroup.setter
406 - def eventGroup(self, val):
407 self._event.set(EventField.EVENT_GROUP, val)
408 409 @property
410 - def ipAddress(self):
412 413 @ipAddress.setter
414 - def ipAddress(self, val):
416 417 @property
418 - def DeviceClass(self):
420 421 @DeviceClass.setter
422 - def DeviceClass(self, val):
424 425 @property
426 - def eventState(self):
427 return self._event.get(EventSummaryField.STATUS, STATUS_NEW)
428 429 @eventState.setter
430 - def eventState(self, val):
431 self._event.set(EventSummaryField.STATUS, val)
432 433 @property
434 - def tags(self):
435 return self._tags
436 437 @property
438 - def Location(self):
440 441 @property
442 - def Systems(self):
443 values = self.details.getAll(EventProxy.DEVICE_SYSTEMS_DETAIL_KEY) 444 if values: 445 return '|' + '|'.join(values)
446 447 @property
448 - def DeviceGroups(self):
449 values = self.details.getAll(EventProxy.DEVICE_GROUPS_DETAIL_KEY) 450 if values: 451 return '|' + '|'.join(values)
452
453 - def setReadOnly(self, name, value):
454 """ 455 Adds a read only attribute for transforms to read. 456 These properties are not sent with the event to the queue. 457 """ 458 self._readOnly[name] = value
459
460 - def resetReadOnly(self, name):
461 """ 462 Clears a read only attribute so it can be updated. 463 """ 464 self._readOnly.pop(name, None)
465 466 # Just put everything else in the details
467 - def __getattr__(self, name):
468 try: 469 if name in self._readOnly: 470 return self._readOnly[name] 471 472 try: 473 return self.__dict__['details'][name] 474 except KeyError: 475 raise AttributeError(name) 476 except: 477 log.debug('Could not get key %s', name) 478 raise
479
480 - def __setattr__(self, name, value):
481 if hasattr(self.__class__, name): 482 object.__setattr__(self, name, value) 483 else: 484 self.__dict__['details'][name] = value
485
486 -class EventSummaryProxy(EventProxy):
487 """ 488 Wraps an org.zenoss.protobufs.zep.EventSummary 489 490 and makes it look like an old style Event. 491 """
492 - def __init__(self, eventSummaryProtobuf):
493 self.__dict__['_eventSummary'] = ProtobufWrapper(eventSummaryProtobuf) 494 if not self._eventSummary.occurrence: 495 self._eventSummary.occurrence.add() 496 497 event = self._eventSummary.occurrence[0] 498 EventProxy.__init__(self, event)
499 500 @property
501 - def evid(self):
502 return self._eventSummary.get(EventSummaryField.UUID)
503 504 @property
505 - def stateChange(self):
506 t = self._eventSummary.get(EventSummaryField.STATUS_CHANGE_TIME) 507 if t: 508 return LocalDateTimeFromMilli(t)
509 510 @property
511 - def clearid(self):
512 return self._eventSummary.get(EventSummaryField.CLEARED_BY_EVENT_UUID)
513 514 @clearid.setter
515 - def clearid(self, val):
516 self._eventSummary.set(EventSummaryField.CLEARED_BY_EVENT_UUID, val)
517 518 @property
519 - def firstTime(self):
520 t = self._eventSummary.get(EventSummaryField.FIRST_SEEN_TIME) 521 if t: 522 return LocalDateTimeFromMilli(t)
523 524 @property
525 - def lastTime(self):
526 t = self._eventSummary.get(EventSummaryField.LAST_SEEN_TIME) 527 if t: 528 return LocalDateTimeFromMilli(t)
529 530 @property
531 - def count(self):
532 return self._eventSummary.get(EventSummaryField.COUNT, 0)
533 534 @property
535 - def ownerid(self):
536 return self._eventSummary.get(EventSummaryField.CURRENT_USER_NAME)
537 538 @ownerid.setter
539 - def ownerid(self, val):
540 self._eventSummary.set(EventSummaryField.CURRENT_USER_NAME, val)
541 542 @property
543 - def eventState(self):
544 return self._eventSummary.get(EventSummaryField.STATUS, STATUS_NEW)
545 546 @eventState.setter
547 - def eventState(self, val):
548 self._eventSummary.set(EventSummaryField.STATUS, val)
549
550 -class ZepRawEventProxy(EventProxy):
551 """ 552 Wraps an org.zenoss.protobufs.zep.ZepRawEvent and makes it look like 553 an old style Event. It is the proper event proxy to use for transforms 554 since transforms use _action and _clearClasses. 555 """ 556 ACTION_HISTORY = 'history' 557 ACTION_DROP = 'drop' 558 ACTION_STATUS = 'status' 559 ACTION_HEARTBEAT = 'heartbeat' 560 ACTION_LOG = 'log' 561 ACTION_ALERT_STATE = 'alert_state' 562 ACTION_DETAIL = 'detail' 563 564 ACTION_STATUS_MAP = { 565 ACTION_HISTORY : STATUS_CLOSED, 566 ACTION_STATUS : STATUS_NEW, 567 ACTION_DROP : STATUS_DROPPED, 568 None : STATUS_NEW, 569 } 570 571 STATUS_ACTION_MAP = { 572 STATUS_NEW : ACTION_STATUS, 573 STATUS_ACKNOWLEDGED : ACTION_STATUS, 574 STATUS_SUPPRESSED : ACTION_STATUS, 575 STATUS_CLOSED : ACTION_HISTORY, 576 STATUS_CLEARED : ACTION_HISTORY, 577 STATUS_DROPPED : ACTION_DROP, 578 STATUS_AGED : ACTION_HISTORY, 579 None : ACTION_STATUS, 580 } 581
582 - def __init__(self, zepRawEvent):
583 self.__dict__['_zepRawEvent'] = ProtobufWrapper(zepRawEvent) 584 EventProxy.__init__(self, self._zepRawEvent.event) 585 586 classes = [] 587 if self._zepRawEvent.clear_event_class: 588 classes = list(self._zepRawEvent.clear_event_class) 589 590 self.__dict__['_clearClassesSet'] = set(classes) 591 self._refreshClearClasses()
592
593 - def __str__(self):
594 return "{_zepRawEvent:%s}" % str(to_dict(self._zepRawEvent))
595
596 - def _refreshClearClasses(self):
597 # Add this dynamically in case severity or event_class changes 598 if self._event.severity == SEVERITY_CLEAR and self._event.get(EventField.EVENT_CLASS): 599 self._clearClassesSet.add(self._event.event_class) 600 601 del self._zepRawEvent.clear_event_class 602 for eventClass in self._clearClassesSet: 603 self._zepRawEvent.clear_event_class.append(eventClass)
604 605 @property
606 - def _clearClasses(self):
607 return list(self._clearClassesSet)
608 609 @_clearClasses.setter
610 - def _clearClasses(self, val):
611 self._clearClassesSet.clear() 612 self._clearClassesSet.update(val) 613 self._refreshClearClasses()
614 615 @property
616 - def _action(self):
617 return self.STATUS_ACTION_MAP.get(self.eventState, self.STATUS_ACTION_MAP[None])
618 619 @_action.setter
620 - def _action(self, val):
621 current_status = self.STATUS_ACTION_MAP.get(self.eventState) 622 if current_status != val: 623 self.eventState = self.ACTION_STATUS_MAP.get(val, self.ACTION_STATUS_MAP[None])
624 625 @property
626 - def eventClassMapping(self):
627 return self.details.get('eventClassMapping', '')
628 629 @eventClassMapping.setter
630 - def eventClassMapping(self, val):
631 # TODO: event_class_mapping_uuid needs to be set separately to avoid 632 # duplicate lookups 633 self.details['eventClassMapping'] = val
634 635 636 # add lists to introspect valid fields for types 637 for typ in (EventProxy, EventSummaryProxy): 638 typ.FIELDS = [name for name in dir(typ) if isinstance(getattr(typ,name), property)] 639