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

# Source Code for Module Products.ZenModel.LinkManager

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