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):
    313          self.details.set(EventProxy.PRODUCTION_STATE_DETAIL_KEY, int(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):
    373          priority = self.details.get(EventProxy.DEVICE_PRIORITY_DETAIL_KEY)
    374          if priority:
    375              return int(priority)
    376
    377      @DevicePriority.setter
    378 -    def DevicePriority(self, val):
    379          self.details.set(EventProxy.DEVICE_PRIORITY_DETAIL_KEY, int(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):
    411          return self.details.get(EventProxy.DEVICE_IP_ADDRESS_DETAIL_KEY)
    412
    413      @ipAddress.setter
    414 -    def ipAddress(self, val):
    415          self.details.set(EventProxy.DEVICE_IP_ADDRESS_DETAIL_KEY, val)
    416
    417      @property
    418 -    def DeviceClass(self):
    419          return self.details.get(EventProxy.DEVICE_CLASS_DETAIL_KEY)
    420
    421      @DeviceClass.setter
    422 -    def DeviceClass(self, val):
    423          self.details.set(EventProxy.DEVICE_CLASS_DETAIL_KEY, 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):
    439          return self.details.get(EventProxy.DEVICE_LOCATION_DETAIL_KEY)
    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