Package Products :: Package ZenModel :: Module LinkManager |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenModel.LinkManager

      1  ##############################################################################
      2  #
      3  # Copyright (C) Zenoss, Inc. 2007, 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 groupby
     12
     13  from Acquisition import aq_base
     14
     15  from Globals import InitializeClass
     16  from AccessControl import ClassSecurityInfo
     17
     18  from OFS.Folder import Folder
     19
     20  from json import dumps
     21  from Products.CMFCore.utils import getToolByName
     22  from Products.ZCatalog.ZCatalog import manage_addZCatalog
     23  from Products.ZenModel.Device import Device
     24  from Products.ZenUtils.Search import makeCaseInsensitiveFieldIndex
     25  from Products.ZenUtils.NetworkTree import NetworkLink
     26  from Products.Zuul import getFacade
     27  from Products.ZenEvents.events2.processing import Manager
     28  from zenoss.protocols.protobufs.zep_pb2 import (SEVERITY_CRITICAL, SEVERITY_ERROR,
     29                                                  SEVERITY_WARNING, SEVERITY_INFO,
     30                                                  SEVERITY_DEBUG, SEVERITY_CLEAR)
     31  from zenoss.protocols.protobufs.zep_pb2 import STATUS_NEW, STATUS_ACKNOWLEDGED
     32
     33  security = ClassSecurityInfo()
     34
     35  NODE_IDS = dict(
     36      layer_3 = {'IpNetwork':'networkId', 'Device':'deviceId'},
     37      layer_2 = {'LAN':'lanId', 'Device':'deviceId'}
     38  )
     39
     40 -def _getComplement(context, layer=3):
     41      key = 'layer_%d' % layer
     42      nodestuff = NODE_IDS[key]
     43      if not isinstance(context, basestring):
     44          try:
     45              context = nodestuff[context.meta_type]
     46          except KeyError:
     47              return None
     48      first, second = nodestuff.values()
     49      if context==first:
     50          return second
     51      else:
     52          return first
     53
     54 -def manage_addLinkManager(context, id="ZenLinkManager"):
     55      """ Make a LinkManager """
     56      mgr = LinkManager(id)
     57      context._setObject(mgr.id, mgr)
     58      mgr = context._getOb(id)
     59      _create_catalogs(mgr)
     60
     61
     62 -def _create_layer2_catalog(mgr):
     63      layer_2_indices = (
     64          ('lanId', makeCaseInsensitiveFieldIndex),
     65          ('macaddress', makeCaseInsensitiveFieldIndex),
     66          ('deviceId', makeCaseInsensitiveFieldIndex),
     67          ('interfaceId', makeCaseInsensitiveFieldIndex)
     68      )
     69      mgr._addLinkCatalog('layer2_catalog', layer_2_indices)
     70
     71
     72 -def _create_layer3_catalog(mgr):
     73      layer_3_indices = (
     74          ('networkId', makeCaseInsensitiveFieldIndex),
     75          ('ipAddressId', makeCaseInsensitiveFieldIndex),
     76          ('deviceId', makeCaseInsensitiveFieldIndex),
     77          ('interfaceId', makeCaseInsensitiveFieldIndex)
     78      )
     79      mgr._addLinkCatalog('layer3_catalog', layer_3_indices)
     80
     81
     82 -def _create_catalogs(mgr):
     83      _create_layer2_catalog(mgr)
     84      _create_layer3_catalog(mgr)
     85
     86
     87 -class Layer3Link(object):
     88      """
     89      Provides an API for navigating paired groups of brains.
     90      """
     91 -    def __init__(self, dmd, twokeydict):
     92          a, b = twokeydict.items()
     93          aid, self.abrains = a
     94          bid, self.bbrains = b
     95          self.a = dmd.unrestrictedTraverse(aid)
     96          self.b = dmd.unrestrictedTraverse(bid)
     97          self.zep = getFacade('zep', dmd)
     98          self.idmgr = Manager(dmd)
     99
    100 -    def _getComponentUuid(self, devuuid, compid):
    101          try:
    102              dev = self.idmgr.getElementByUuid(devuuid)
    103              compuuid = self.idmgr.getElementUuidById(dev, Device, compid)
    104              return compuuid
    105          except Exception:
    106              return None
    107
    108 -    def getStatus(self):
    109          brains = self.abrains + self.bbrains
    110
    111          # lookup all device uuids, make sure at least one exists
    112          devUuids = [self.idmgr.findDeviceUuid(a.deviceId, None) for a in brains]
    113          validDevUuids = filter(None, devUuids)
    114          if not validDevUuids:
    115              return SEVERITY_CLEAR
    116
    117          # if there is any open /Status/Ping event on any device, return CRITICAL severity
    118          statusPingFilter = self.zep.createEventFilter(
    119              tags = validDevUuids,
    120              event_class = '/Status/Ping/',
    121              status = (STATUS_NEW, STATUS_ACKNOWLEDGED),
    122              severity = (SEVERITY_WARNING, SEVERITY_ERROR, SEVERITY_CRITICAL)
    123          )
    124          maxpingrec = self.zep.getEventSummaries(0, filter=statusPingFilter, sort=(('count','desc'),), limit=1)
    125          if maxpingrec and maxpingrec['total'] > 0:
    126              return SEVERITY_CRITICAL
    127
    128          # no /Status/Ping events found, just return worst severity of all events on all interface components
    129          devCompPairs = zip(devUuids, (a.interfaceId for a in brains))
    130          compUuids = (self._getComponentUuid(devuuid, compid)
    131                          for devuuid, compid in devCompPairs
    132                          if devuuid is not None)
    133          components = filter(None, compUuids)
    134          if components:
    135              sev = self.zep.getWorstSeverity(components)
    136              return sev
    137
    138          return SEVERITY_CLEAR
    139
    140 -    def getAddresses(self):
    141          return (self.a.address, self.b.address)
    142
    143
    144 -class LinkManager(Folder):
    145      """
    146      A tool that keeps track of OSI layer links between objects.
    147      """
    148 -    def __init__(self, id, *args, **kwargs):
    149          Folder.__init__(self, id, *args, **kwargs)
    150          self.id = id
    151
    152 -    def _getCatalog(self, layer=3):
    153          try:
    154              return getToolByName(self, 'layer%d_catalog' % layer)
    155          except AttributeError:
    156              return None
    157
    158 -    def _addLinkCatalog(self, id, indices):
    159          manage_addZCatalog(self, id, id)
    160          zcat = self._getOb(id)
    161          cat = zcat._catalog
    162          for index, factory in indices:
    163              cat.addIndex(index, factory(index))
    164              zcat.addColumn(index)
    165
    166 -    def getLinkedNodes(self, meta_type, id, layer=3, visited=None):
    167          cat = self._getCatalog(layer)
    168          col = NODE_IDS['layer_%d' % layer][meta_type]
    169          nextcol = _getComplement(col, layer)
    170          brains = cat(**{col:id})
    171          gen1ids = set(getattr(brain, nextcol) for brain in brains)
    172          if visited:
    173              gen1ids = gen1ids - visited # Don't go places we've been!
    174          gen2 = cat(**{nextcol:list(gen1ids)})
    175          return gen2, gen1ids
    176
    177 -    def getChildLinks(self, organizer):
    178          catalog = getToolByName(self.dmd.Devices, 'deviceSearch')
    179          result = {}
    180          locs = organizer.children()
    181          locpaths = ['/'.join(loc.getPrimaryPath()) for loc in locs]
    182          locpaths.reverse() # otherwise the "startswith" call gets too eager
    183          path = '/'.join(organizer.getPhysicalPath())
    184          subdevs = catalog(path=path)
    185          subids = dict((x.id, x.path) for x in subdevs)
    186
    187          def _whichorg(brain):
    188              for path in locpaths:
    189                  try:
    190                      brainpath = subids[brain.deviceId]
    191                  except KeyError:
    192                      return '__outside'
    193                  if filter(lambda x:'/'.join(x).startswith(path), brainpath):
    194                      return path
    195              return '__outside'
    196
    197          def _whichnet(brain):
    198              return brain.networkId
    199
    200          def _whichdev(brain):
    201              return brain.deviceId
    202
    203          links, nets = self.getLinkedNodes('Device', subids.keys())
    204          links = map(aq_base, links) # For comparison, can't be ImplicitAcq
    205
    206          byloc = {}
    207          for k, g in groupby(links, _whichorg):
    208              byloc.setdefault(k, []).extend(g)
    209          if '__outside' in byloc: del byloc['__outside']
    210
    211          bynet = {}
    212          for k, g in groupby(links, _whichnet):
    213              if getattr(self.dmd.unrestrictedTraverse(k), 'zDrawMapLinks', True):
    214                  bynet.setdefault(k, []).extend(g)
    215
    216          final = {}
    217          linkobs = []
    218
    219          inverted_loc = {}
    220          for loc in byloc:
    221              for dev in byloc[loc]:
    222                  inverted_loc[dev.deviceId] = loc
    223          for net in bynet:
    224              devs = bynet[net]
    225              alllocs = set()
    226              for dev in devs:
    227                  if dev.deviceId and dev.deviceId in inverted_loc:
    228                      alllocs.add(inverted_loc[dev.deviceId])
    229              if len(alllocs)>=2:
    230                  for dev in devs:
    231                      if dev.deviceId:
    232                          loc = inverted_loc.get(dev.deviceId, None)
    233                          if loc:
    234                              final.setdefault(loc, []).append(dev)
    235          def haslink(locs1, locs2):
    236              for l in locs1:
    237                  for b in locs2:
    238                      if l.networkId==b.networkId:
    239                          return True
    240          locs = final.keys()
    241          while locs:
    242              loc = locs.pop()
    243              for loc2 in locs:
    244                  first = final[loc]
    245                  second = final[loc2]
    246                  if haslink(first, second):
    247                      link = Layer3Link(self.dmd, {loc:first, loc2:second})
    248                      linkobs.append(link)
    249          return dumps([(x.getAddresses(), x.getStatus()) for x in linkobs])
    250
    251 -    def getChildLinks_recursive(self, context):
    252          """ Returns all links under a given Organizer, aggregated """
    253          result = set()
    254          severities = {}
    255          links = self.getNetworkLinks(context)
    256          for x in links:
    257              geomapdata = x.getGeomapData(context)
    258              severities[geomapdata] = max(
    259                  x.getStatus(),
    260                  severities.get(geomapdata, 0)
    261              )
    262              result.add(geomapdata)
    263          addresses = [x for x in list(result) if x]
    264          severities = [severities[x] for x in addresses]
    265          return map(list, zip(map(list, addresses), severities))
    266
    267 -    def getNetworkLinks(self, context):
    268          """
    269          An alternate way to get links under an Organizer.
    270          """
    271          result = set()
    272          networks = filter(lambda x:x.zDrawMapLinks,
    273                            self.dmd.Networks.getSubNetworks())
    274          siblings = [x.getPrimaryId() for x in context.children()]
    275          for net in networks:
    276              locdict = {}
    277              def addToDict(iface):
    278                  loc = iface.device().location()
    279                  if not loc: return
    280                  here = loc.getPrimaryId()
    281                  matched = False
    282                  for sib in siblings:
    283                      if here.startswith(sib):
    284                          locdict.setdefault(sib, []).append(iface)
    285                          matched = True
    286                          break
    287                  if not matched:
    288                      locdict.setdefault(here, []).append(iface)
    289              for ip in net.ipaddresses.objectValuesGen():
    290                  iface = ip.interface()
    291                  if iface: addToDict(iface)
    292              if len(locdict)<=1: continue
    293              locgroups = locdict.values()
    294              while locgroups:
    295                  lg = locgroups.pop()
    296                  targets = []
    297                  for g in locgroups: targets.extend(g)
    298                  for l in lg:
    299                      for t in targets:
    300                          n = NetworkLink()
    301                          n.setEndpoints(l, t)
    302                          result.add(n)
    303          return result
    304  InitializeClass(LinkManager)
    305