1
2
3
4
5
6
7
8
9
10
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
30
31
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
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
54 """Return the pingJob of our parent router.
55 """
56 return self.pj
57
58
59 - def hasDev(self, tree, devname):
61
62
63 - def hasNet(self, tree, netname):
65
66
67 - def addRouter(self, tree, ip, devname, status):
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
115
116
118 self.pj.reset()
119 yield self.pj
120
121
122
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
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
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
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 """
169 self.ip = ip
170 self.enterip = enterip
171 self.parent = parent
172 self.pingjobs = []
173
174
176 """Walk back up the path to the ping server.
177 """
178 return self.parent.checkpath()
179
180
182 """Return the pingJob of our parent router.
183 """
184 return self.parent.pj
185
186
188 for pj in self.pingjobs:
189 yield pj
190
192 self.pingjobs.append(pj)
193
195 map(lambda x: x.reset(), self.pingjobs)
196
199
200 pb.setUnjellyableForClass(Net, Net)
201
202 -class PingTree(pb.Copyable, pb.RemoteCopy):
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