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

# Source Code for Module Products.ZenEvents.events2.proxy

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