Package Products :: Package ZenStatus :: Module pingtree |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenStatus.pingtree

      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  import sys
     15  import logging
     16  log = logging.getLogger("zen.ZenStatus")
     17
     18  from Products.ZenEvents.ZenEventClasses import Status_Ping
     19  from Products.ZenUtils.Utils import localIpCheck
     20  from Products.ZenStatus.AsyncPing import PingJob
     21
     22  from twisted.spread import pb
     23
     24 -def getStatus(device):
     25      # if there's a down event in the database, it must have failed twice
     26      status = device.getStatus(Status_Ping)
     27      if status == 1:
     28          status += 2
     29      return status
     30
     31
     32 -class RouterNode(pb.Copyable, pb.RemoteCopy):
     33      """RouterNode is a router node in the tree map.
     34      """
     35
     36 -    def __init__(self, ip, devname, status, parent=None):
     37          self.pj = PingJob(ip, devname, status, 20)
     38          self.pj.parent = parent
     39          self.parent = parent
     40          self.children = []
     41          self.nets = []
     42
     43
     44 -    def checkpath(self):
     45          """Walk back up the path to the ping server looking for failed routers.
     46          """
     47          node = self
     48          while node.parent and node.pj.status == 0:
     49              node = node.parent
     50          if node.parent: return node.pj.hostname
     51
     52
     53 -    def routerpj(self):
     54          """Return the pingJob of our parent router.
     55          """
     56          return self.pj
     57
     58
     59 -    def hasDev(self, tree, devname):
     60          return tree.deviceMap.has_key(devname)
     61
     62
     63 -    def hasNet(self, tree, netname):
     64          return tree.netsMap.has_key(netname)
     65
     66
     67 -    def addRouter(self, tree, ip, devname, status):
     68          if tree.deviceMap.has_key(devname):
     69              return tree.deviceMap[devname]
     70          tree.deviceMap[devname] = 1
     71          child = RouterNode(ip, devname, status, self)
     72          self.children.append(child)
     73          return child
     74
     75
     76 -    def addNet(self, tree, netip, enterip):
     77          if self.hasNet(tree, netip):
     78              return tree.netsMap[netip]
     79          net = Net(netip, enterip, self)
     80          self.nets.append(net)
     81          tree.netsMap[netip] = net
     82          return net
     83
     84
     85 -    def getNet(self, tree, netname):
     86          """Return the net node for net name
     87          """
     88          net = tree.netsMap.get(netname,None)
     89          if not net:
     90              net = tree.netsMap['default']
     91          return net
     92
     93
     94 -    def addDevice(self, tree, device):
     95          """Add a device to the ping tree.
     96          """
     97          if self.hasDev(tree, device.id):
     98              log.debug("device '%s' already exists.", device.id)
     99              return
    100          tree.deviceMap[device.id] = 1
    101          ip = device.getManageIp()
    102          if not ip:
    103              return
    104          netobj = device.getDmdRoot("Networks").getNet(ip)
    105          netname = "default"
    106          if netobj:
    107              netname = netobj.getNetworkName()
    108          net = self.getNet(tree, netname)
    109          if net.ip == 'default':
    110              log.warn("device '%s' network '%s' not in topology",
    111                              device.id, netname)
    112          pj = PingJob(ip, device.id, getStatus(device))
    113          net.addPingJob(pj)
    114          pj.parent = net
    115
    116
    117 -    def pjgen(self):
    118          self.pj.reset()
    119          yield self.pj
    120          # iterators with intelligence are bad
    121          # this should be handeled in caller if needed
    122          # removing pj.status != 0 check
    123          for rnode in self.children:
    124              for pj in rnode.pjgen():
    125                  yield pj
    126          for net in iter(self.nets):
    127              for pj in net.pjgen():
    128                  yield pj
    129
    130
    131 -    def pprint(self):
    132          allNodes = set()
    133          def recurse(nodes):
    134              nnodes = []
    135              for node in nodes:
    136                  if node in allNodes:
    137                      continue
    138                  allNodes.add(node)
    139                  print node
    140                  recurse(node.children)
    141              print
    142              return nnodes
    143          return recurse([self,])
    144
    145
    146 -    def pprint_gen(self, root=None):
    147          if root is None: root = self
    148          yield root
    149          last = root
    150          for node in self.pprint(root):
    151              for child in iter(node.children):
    152                  yield child
    153                  last = child
    154              if last == node: return
    155
    156 -    def __str__(self):
    157          parentStr = "top"
    158          if hasattr(self.parent, "parent"):
    159                  parentStr = self.parent.pj.ipaddr
    160          return "%s<-%s->(%s)" % (parentStr, self.pj.ipaddr, ", ".join(map(str,self.nets)))
    161
    162  pb.setUnjellyableForClass(RouterNode, RouterNode)
    163
    164
    165 -class Net(pb.Copyable, pb.RemoteCopy):
    166      """Net object represents a network in the tree map.
    167      """
    168 -    def __init__(self,ip,enterip,parent):
    169          self.ip = ip
    170          self.enterip = enterip
    171          self.parent = parent
    172          self.pingjobs = []
    173
    174
    175 -    def checkpath(self):
    176          """Walk back up the path to the ping server.
    177          """
    178          return self.parent.checkpath()
    179
    180
    181 -    def routerpj(self):
    182          """Return the pingJob of our parent router.
    183          """
    184          return self.parent.pj
    185
    186
    187 -    def pjgen(self):
    188          for pj in self.pingjobs:
    189              yield pj
    190
    191 -    def addPingJob(self, pj):
    192          self.pingjobs.append(pj)
    193
    194 -    def reset(self):
    195          map(lambda x: x.reset(), self.pingjobs)
    196
    197 -    def __str__(self):
    198          return self.ip
    199
    200  pb.setUnjellyableForClass(Net, Net)
    201
    202 -class PingTree(pb.Copyable, pb.RemoteCopy):
    203
    204      deviceMap = None
    205      netsMap = None
    206      root = None
    207
    208 -    def __init__(self, devname):
    209          self.netsMap = {}
    210          self.deviceMap = {devname:1}
    211          self.root = None
    212
    213 -    def rootNode(self):
    214          return self.root
    215
    216 -    def hasDev(self, device):
    217          return self.deviceMap.has_key(device)
    218
    219 -    def addDevice(self, device):
    220          self.root.addDevice(self, device)
    221
    222
    223  pb.setUnjellyableForClass(PingTree, PingTree)
    224
    225
    226 -def buildTree(root, rootnode=None, devs=None, memo=None, tree=None):
    227      """Returns tree where tree that maps the network from root's
    228      perspective  and nmap is a dict that points network ids to the
    229      network objects in the tree.  nmap is used to add devices to be pinged
    230      to the tree.
    231      """
    232      if memo is None: memo = []
    233      if devs is None:
    234          assert tree is None
    235          tree = PingTree(root.id)
    236          ipaddr = root.getManageIp()
    237          if not ipaddr:
    238              raise ValueError("zenping host %s has no manage ip"%root.id)
    239          rootnode = RouterNode(ipaddr, root.id, getStatus(root))
    240          tree.root = rootnode
    241          rootnode.addNet(tree, "default", "default")
    242          devs = [(root,rootnode)]
    243      nextdevs = []
    244      for dev, rnode in devs:
    245          if dev.id in memo: return
    246          log.debug("mapping device '%s'", dev.id)
    247          memo.append(dev.id)
    248          for route in dev.os.routes():
    249              if route.routetype == "direct":
    250                  netid = route.getTarget()
    251                  if not route.ipcheck(netid):
    252                      netid = route.getTarget()
    253                      if rootnode.hasNet(tree, netid): continue
    254                      net = rnode.addNet(tree, netid,route.getInterfaceIp())
    255                      log.debug("add net: %s to rnode: %s", net, rnode)
    256              else:
    257                  ndev = route.getNextHopDevice()
    258                  if ndev:
    259                      if rootnode.hasDev(tree, ndev.id): continue
    260                      if route.getNextHopDevice():
    261                          nextHopIp = route.getNextHopDevice().manageIp
    262                      else:
    263                          nextHopIp = route.getNextHopIp()
    264                      nrnode = rnode.addRouter(tree,
    265                                               nextHopIp,ndev.id,
    266                                               getStatus(ndev))
    267                      log.debug("create rnode: %s", nrnode)
    268                      nextdevs.append((ndev, nrnode))
    269          for iface in dev.os.interfaces():
    270              for ip in iface.ipaddresses():
    271                  netid = ip.getNetworkName()
    272                  if not netid: continue
    273                  if localIpCheck(dev, netid) or rootnode.hasNet(tree, netid): continue
    274                  net = rnode.addNet(tree, netid,ip.getIp())
    275                  log.debug("add net: %s to rnode: %s", net, rnode)
    276      if nextdevs:
    277          buildTree(root, rootnode, nextdevs, memo, tree)
    278      return tree
    279
    280
    281
    282
    283 -def netDistMap(root, nmap=None, distance=0, devs=None, memo=None):
    284      """Return a mapping object with network ip as key and distance as value.
    285      This is a recursive method that does a breadth first search of the route
    286      space.  It is called with no parameters (they are used by the recursion)
    287      """
    288      if nmap is None: nmap = {}
    289      if memo is None: memo = []
    290      if devs is None: devs = [root,]
    291      nextdevs = []
    292      for dev in devs:
    293          if dev.id in memo: return
    294          log.debug("mapping device '%s' distance '%s'", dev.id, distance)
    295          memo.append(dev.id)
    296          for route in dev.os.routes():
    297              if route.routetype == "direct":
    298                  netid=route.getTarget()
    299                  if not route.ipcheck(netid):
    300                      netip = route.getTargetIp()
    301                      curdist = nmap.get(netip,sys.maxint)
    302                      if curdist > distance:
    303                          log.debug("netip '%s' distance '%d'",
    304                                          netip, distance)
    305                          nmap[netip] = distance
    306              else:
    307                  ndev = route.getNextHopDevice()
    308                  if ndev: nextdevs.append(ndev)
    309      distance += 1
    310      netDistMap(root, nmap, distance, nextdevs, memo)
    311      return nmap
    312