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

Source Code for Module Products.ZenModel.IpNetwork

  1  ############################################################################## 
  2  #  
  3  # Copyright (C) Zenoss, Inc. 2008, 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  __doc__ = """IpNetwork 
 12   
 13  IpNetwork represents an IP network which contains 
 14  many IP addresses. 
 15  """ 
 16   
 17  import math 
 18  import transaction 
 19  from xml.dom import minidom 
 20  import logging 
 21  log = logging.getLogger('zen') 
 22   
 23  from ipaddr import IPAddress, IPNetwork 
 24   
 25  from Globals import DTMLFile 
 26  from Globals import InitializeClass 
 27  from Acquisition import aq_base 
 28  from AccessControl import ClassSecurityInfo 
 29  from AccessControl import Permissions as permissions 
 30  from Products.ZenModel.ZenossSecurity import * 
 31   
 32  from Products.ZenUtils.IpUtil import * 
 33  from Products.ZenRelations.RelSchema import * 
 34  from Products.ZenUtils.Search import makeCaseInsensitiveFieldIndex, makeMultiPathIndex, makeCaseSensitiveKeywordIndex\ 
 35      , makeCaseSensitiveFieldIndex 
 36  from IpAddress import IpAddress 
 37  from DeviceOrganizer import DeviceOrganizer 
 38   
 39  from Products.ZenModel.Exceptions import * 
 40   
 41  from Products.ZenUtils.Utils import isXmlRpc, setupLoggingHeader, executeCommand 
 42  from Products.ZenUtils.Utils import binPath, clearWebLoggingStream 
 43  from Products.ZenUtils import NetworkTree 
 44  from Products.ZenUtils.Utils import edgesToXML 
 45  from Products.ZenUtils.Utils import unused 
 46  from Products.Jobber.jobs import SubprocessJob 
 47  from Products.ZenWidgets import messaging 
 48   
49 -def manage_addIpNetwork(context, id, netmask=24, REQUEST = None, version=4):
50 """make a IpNetwork""" 51 net = IpNetwork(id, netmask=netmask, version=version) 52 context._setObject(net.id, net) 53 if id.endswith("Networks"): 54 net = context._getOb(net.id) 55 net.dmdRootName = id 56 net.buildZProperties() 57 net.createCatalog() 58 #manage_addZDeviceDiscoverer(context) 59 if REQUEST is not None: 60 REQUEST['RESPONSE'].redirect(context.absolute_url()+'/manage_main')
61 62 63 addIpNetwork = DTMLFile('dtml/addIpNetwork',globals()) 64 65 66 # When an IP is added the default location will be 67 # into class A->B->C network tree 68 defaultNetworkTree = (32,) 69
70 -class IpNetwork(DeviceOrganizer):
71 """IpNetwork object""" 72 73 isInTree = True 74 75 buildLinks = True 76 77 # Organizer configuration 78 dmdRootName = "Networks" 79 80 # Index name for IP addresses 81 default_catalog = 'ipSearch' 82 83 portal_type = meta_type = 'IpNetwork' 84 85 version = 4 86 87 _properties = ( 88 {'id':'netmask', 'type':'int', 'mode':'w'}, 89 {'id':'description', 'type':'text', 'mode':'w'}, 90 {'id':'version', 'type':'int', 'mode':'w'}, 91 ) 92 93 _relations = DeviceOrganizer._relations + ( 94 ("ipaddresses", ToManyCont(ToOne, "Products.ZenModel.IpAddress", "network")), 95 ("clientroutes", ToMany(ToOne,"Products.ZenModel.IpRouteEntry","target")), 96 ("location", ToOne(ToMany, "Products.ZenModel.Location", "networks")), 97 ) 98 99 # Screen action bindings (and tab definitions) 100 factory_type_information = ( 101 { 102 'id' : 'IpNetwork', 103 'meta_type' : 'IpNetwork', 104 'description' : """Arbitrary device grouping class""", 105 'icon' : 'IpNetwork_icon.gif', 106 'product' : 'ZenModel', 107 'factory' : 'manage_addIpNetwork', 108 'immediate_view' : 'viewNetworkOverview', 109 'actions' : 110 ( 111 { 'id' : 'overview' 112 , 'name' : 'Overview' 113 , 'action' : 'viewNetworkOverview' 114 , 'permissions' : ( 115 permissions.view, ) 116 }, 117 { 'id' : 'zProperties' 118 , 'name' : 'Configuration Properties' 119 , 'action' : 'zPropertyEdit' 120 , 'permissions' : ("Manage DMD",) 121 }, 122 ) 123 }, 124 ) 125 126 security = ClassSecurityInfo() 127 128
129 - def __init__(self, id, netmask=24, description='', version=4):
130 if id.find("/") > -1: id, netmask = id.split("/",1) 131 DeviceOrganizer.__init__(self, id, description) 132 if not id.endswith("Networks"): 133 checkip(id) 134 self.netmask = maskToBits(netmask) 135 self.version = version 136 self.description = description 137 self.title = ipunwrap(id)
138 139 security.declareProtected('Change Network', 'manage_addIpNetwork')
140 - def manage_addIpNetwork(self, newPath, REQUEST=None):
141 """ 142 From the GUI, create a new subnet (if necessary) 143 """ 144 net = self.createNet(newPath) 145 if REQUEST is not None: 146 REQUEST['RESPONSE'].redirect(net.absolute_url())
147
148 - def checkValidId(self, id, prep_id = False):
149 """Checks a valid id 150 """ 151 if id.find("/") > -1: id, netmask = id.split("/",1) 152 return super(IpNetwork, self).checkValidId(id, prep_id)
153 154
155 - def getNetworkRoot(self, version=None):
156 """This is a hook method do not remove!""" 157 if not isinstance(version, int): 158 version = self.version 159 if version is 6: 160 return self.dmd.getDmdRoot("IPv6Networks") 161 return self.dmd.getDmdRoot("Networks")
162 163
164 - def createNet(self, netip, netmask=24):
165 """ 166 Return and create if necessary network. netip is in the form 167 1.1.1.0/24 or with netmask passed as parameter. Subnetworks created 168 based on the zParameter zDefaulNetworkTree. 169 Called by IpNetwork.createIp and IpRouteEntry.setTarget 170 If the netmask is invalid, then a netmask of 24 is assumed. 171 172 @param netip: network IP address start 173 @type netip: string 174 @param netmask: network mask 175 @type netmask: integer 176 @todo: investigate IPv6 issues 177 """ 178 if '/' in netip: 179 netip, netmask = netip.split("/",1) 180 181 checkip(netip) 182 ipobj = IPAddress(ipunwrap_strip(netip)) 183 try: 184 netmask = int(netmask) 185 except (TypeError, ValueError): 186 netmask = 24 187 netmask = netmask if netmask < ipobj.max_prefixlen else 24 188 189 #hook method do not remove! 190 netroot = self.getNetworkRoot(ipobj.version) 191 netobj = netroot.getNet(netip) 192 if netmask == 0: 193 raise ValueError("netip '%s' without netmask" % netip) 194 if netobj and netobj.netmask >= netmask: # Network already exists. 195 return netobj 196 197 ipNetObj = IPNetwork(netip) 198 if ipNetObj.version == 4: 199 netip = getnetstr(netip, netmask) 200 netTree = getattr(self, 'zDefaultNetworkTree', defaultNetworkTree) 201 netTree = map(int, netTree) 202 if ipobj.max_prefixlen not in netTree: 203 netTree.append(ipobj.max_prefixlen) 204 else: 205 # IPv6 doesn't use subnet masks the same way 206 netip = getnetstr(netip, 64) 207 netmask = 64 208 # ISPs are supposed to provide the 48-bit prefix to orgs (RFC 3177) 209 netTree = (48,) 210 211 if netobj: 212 # strip irrelevant values from netTree if we're not starting at /0 213 netTree = [ m for m in netTree if m > netobj.netmask ] 214 else: 215 # start at /Networks if no containing network was found 216 netobj = netroot 217 218 for treemask in netTree: 219 if treemask >= netmask: 220 netobjParent = netobj 221 netobj = netobj.addSubNetwork(netip, netmask) 222 self.rebalance(netobjParent, netobj) 223 break 224 else: 225 supnetip = getnetstr(netip, treemask) 226 netobjParent = netobj 227 netobj = netobj.addSubNetwork(supnetip, treemask) 228 self.rebalance(netobjParent, netobj) 229 230 return netobj
231 232
233 - def rebalance(self, netobjParent, netobj):
234 """ 235 Look for children of the netobj at this level and move them to the 236 right spot. 237 """ 238 moveList = [] 239 for subnetOrIp in netobjParent.children(): 240 if subnetOrIp == netobj: 241 continue 242 if netobj.hasIp(subnetOrIp.id): 243 moveList.append(subnetOrIp.id) 244 if moveList: 245 netobjPath = netobj.getOrganizerName()[1:] 246 netobjParent.moveOrganizer(netobjPath, moveList)
247
248 - def findNet(self, netip, netmask=0):
249 """ 250 Find and return the subnet of this IpNetwork that matches the requested 251 netip and netmask. 252 """ 253 if netip.find("/") >= 0: 254 netip, netmask = netip.split("/", 1) 255 netmask = int(netmask) 256 for subnet in [self] + self.getSubNetworks(): 257 if netmask == 0 and subnet.id == netip: 258 return subnet 259 if subnet.id == netip and subnet.netmask == netmask: 260 return subnet 261 return None
262 263
264 - def getNet(self, ip):
265 """Return the net starting form the Networks root for ip. 266 """ 267 return self._getNet(ipunwrap(ip))
268 269
270 - def _getNet(self, ip):
271 """Recurse down the network tree to find the net of ip. 272 """ 273 274 # If we can find the IP in the catalog, use it. This is fast. 275 brains = self.ipSearch(id=ip) 276 path = self.getPrimaryUrlPath() 277 for brain in brains: 278 bp = brain.getPath() 279 if bp.startswith(path): 280 try: 281 return self.unrestrictedTraverse('/'.join(bp.split('/')[:-2])) 282 except KeyError: 283 pass 284 285 # Otherwise we have to traverse the entire network hierarchy. 286 for net in self.children(): 287 if net.hasIp(ip): 288 if len(net.children()): 289 subnet = net._getNet(ip) 290 if subnet: 291 return subnet 292 else: 293 return net 294 else: 295 return net
296 297
298 - def createIp(self, ip, netmask=24):
299 """Return an ip and create if nessesary in a hierarchy of 300 subnetworks based on the zParameter zDefaulNetworkTree. 301 """ 302 ipobj = self.findIp(ip) 303 if ipobj: return ipobj 304 netobj = self.createNet(ip, netmask) 305 ipobj = netobj.addIpAddress(ip,netmask) 306 return ipobj
307 308
309 - def freeIps(self):
310 """Number of free Ips left in this network. 311 """ 312 freeips = 0 313 try: 314 net = IPNetwork(ipunwrap(self.id)) 315 freeips = int(math.pow(2, net.max_prefixlen - self.netmask) - self.countIpAddresses()) 316 if self.netmask > net.max_prefixlen: 317 return freeips 318 return freeips - 2 319 except ValueError: 320 for net in self.children(): 321 freeips += net.freeIps() 322 return freeips
323 324
325 - def hasIp(self, ip):
326 """ 327 Could this network contain this IP? 328 """ 329 net = IPNetwork(ipunwrap(self.id)) 330 start = long(int(net.network)) 331 end = start + math.pow(2, net.max_prefixlen - self.netmask) 332 return start <= numbip(ip) < end
333
334 - def fullIpList(self):
335 """Return a list of all IPs in this network. 336 """ 337 net = IPNetwork(ipunwrap(self.id)) 338 if (self.netmask == net.max_prefixlen): return [self.id] 339 ipnumb = long(int(net)) 340 maxip = math.pow(2, net.max_prefixlen - self.netmask) 341 start = int(ipnumb+1) 342 end = int(ipnumb+maxip-1) 343 return map(strip, range(start,end))
344 345
346 - def deleteUnusedIps(self):
347 """Delete ips that are unused in this network. 348 """ 349 for ip in self.ipaddresses(): 350 if ip.device(): continue 351 self.ipaddresses.removeRelation(ip)
352 353
354 - def defaultRouterIp(self):
355 """Return the ip of the default router for this network. 356 It is based on zDefaultRouterNumber which specifies the sequence 357 number that locates the router in this network. If: 358 zDefaultRouterNumber==1 for 10.2.1.0/24 -> 10.2.1.1 359 zDefaultRouterNumber==254 for 10.2.1.0/24 -> 10.2.1.254 360 zDefaultRouterNumber==1 for 10.2.2.128/25 -> 10.2.2.129 361 zDefaultRouterNumber==126 for 10.2.2.128/25 -> 10.2.2.254 362 """ 363 roffset = getattr(self, "zDefaultRouterNumber", 1) 364 return strip((numbip(self.id) + roffset))
365 366
367 - def getNetworkName(self):
368 """return the full network name of this network""" 369 return "%s/%d" % (self.id, self.netmask)
370 371 372 security.declareProtected('View', 'primarySortKey')
373 - def primarySortKey(self):
374 """ 375 Sort by the IP numeric 376 377 >>> net = dmd.Networks.addSubNetwork('1.2.3.0', 24) 378 >>> net.primarySortKey() 379 16909056L 380 """ 381 return numbip(self.id)
382 383 384 security.declareProtected('Change Network', 'addSubNetwork')
385 - def addSubNetwork(self, ip, netmask=24):
386 """Return and add if nessesary subnetwork to this network. 387 """ 388 netobj = self.getSubNetwork(ip) 389 if not netobj: 390 net = IpNetwork(ipwrap(ip), netmask) 391 self._setObject(ipwrap(ip), net) 392 return self.getSubNetwork(ip)
393 394 395 security.declareProtected('View', 'getSubNetwork')
396 - def getSubNetwork(self, ip):
397 """get an ip on this network""" 398 return self._getOb(ipwrap(ip), None)
399 400
401 - def getSubNetworks(self):
402 """Return all network objects below this one. 403 """ 404 nets = self.children() 405 for subgroup in self.children(): 406 nets.extend(subgroup.getSubNetworks()) 407 return nets
408 409 security.declareProtected('Change Network', 'addIpAddress')
410 - def addIpAddress(self, ip, netmask=24):
411 """add ip to this network and return it""" 412 ipobj = IpAddress(ip,netmask) 413 self.ipaddresses._setObject(ipwrap(ip), ipobj) 414 return self.getIpAddress(ip)
415 416 417 security.declareProtected('View', 'getIpAddress')
418 - def getIpAddress(self, ip):
419 """get an ip on this network""" 420 return self.ipaddresses._getOb(ipwrap(ip), None)
421 422 security.declareProtected('Change Network', 'manage_deleteIpAddresses')
423 - def manage_deleteIpAddresses(self, ipaddresses=(), REQUEST=None):
424 """Delete ipaddresses by id from this network. 425 """ 426 for ipaddress in ipaddresses: 427 ip = self.getIpAddress(ipaddress) 428 self.ipaddresses.removeRelation(ip) 429 if REQUEST: 430 return self.callZenScreen(REQUEST)
431 432 433 security.declareProtected('View', 'countIpAddresses')
434 - def countIpAddresses(self, inuse=False):
435 """get an ip on this network""" 436 if inuse: 437 # When there are a large number of IPs this code is too slow 438 # we either need to cache all /Status/Ping events before hand 439 # and then integrate them with the list of IPs 440 # or blow off the whole feature. For now we just set the 441 # default to not use this code. -EAD 442 count = len(filter(lambda x: x.getStatus() == 0,self.ipaddresses())) 443 else: 444 count = self.ipaddresses.countObjects() 445 for net in self.children(): 446 count += net.countIpAddresses(inuse) 447 return count
448 449 security.declareProtected('View', 'countDevices') 450 countDevices = countIpAddresses 451 452
453 - def getAllCounts(self, devrel=None):
454 """Count all devices within a device group and get the 455 ping and snmp counts as well""" 456 unused(devrel) 457 counts = [ 458 self.ipaddresses.countObjects(), 459 self._status("Ping", "ipaddresses"), 460 self._status("Snmp", "ipaddresses"), 461 ] 462 for group in self.children(): 463 sc = group.getAllCounts() 464 for i in range(3): counts[i] += sc[i] 465 return counts
466 467
468 - def pingStatus(self, devrel=None):
469 """aggregate ping status for all devices in this group and below""" 470 unused(devrel) 471 return DeviceOrganizer.pingStatus(self, "ipaddresses")
472 473
474 - def snmpStatus(self, devrel=None):
475 """aggregate snmp status for all devices in this group and below""" 476 unused(devrel) 477 return DeviceOrganizer.snmpStatus(self, "ipaddresses")
478 479
480 - def getSubDevices(self, filter=None):
481 """get all the devices under and instance of a DeviceGroup""" 482 return DeviceOrganizer.getSubDevices(self, filter, "ipaddresses")
483 484
485 - def findIp(self, ip):
486 """Find an ipAddress. 487 """ 488 searchCatalog = self.getNetworkRoot().ipSearch 489 ret = searchCatalog(dict(id=ipwrap(ip))) 490 if not ret: return None 491 if len(ret) > 1: 492 raise IpAddressConflict( "IP address conflict for IP: %s" % ip ) 493 return ret[0].getObject()
494 495
496 - def buildZProperties(self):
497 if self.version == 6: 498 nets = self.getDmdRoot("IPv6Networks") 499 else: 500 nets = self.getDmdRoot("Networks") 501 if getattr(aq_base(nets), "zDefaultNetworkTree", False): 502 return 503 nets._setProperty("zDefaultNetworkTree", (64,128) if nets.id == "IPv6Networks" else (24,32), type="lines") 504 nets._setProperty("zDrawMapLinks", True, type="boolean") 505 nets._setProperty("zAutoDiscover", True, type="boolean") 506 nets._setProperty("zPingFailThresh", 168, type="int") 507 nets._setProperty("zIcon", "/zport/dmd/img/icons/network.png") 508 nets._setProperty("zPreferSnmpNaming", False, type="boolean") 509 nets._setProperty("zSnmpStrictDiscovery", False, type="boolean")
510 511
512 - def reIndex(self):
513 """Go through all ips in this tree and reindex them.""" 514 zcat = self._getCatalog() 515 zcat.manage_catalogClear() 516 for net in self.getSubNetworks(): 517 for ip in net.ipaddresses(): 518 ip.index_object()
519 520
521 - def createCatalog(self):
522 """make the catalog for device searching""" 523 from Products.ZCatalog.ZCatalog import manage_addZCatalog 524 525 # XXX convert to ManagableIndex 526 manage_addZCatalog(self, self.default_catalog, 527 self.default_catalog) 528 zcat = self._getOb(self.default_catalog) 529 cat = zcat._catalog 530 cat.addIndex('id', makeCaseInsensitiveFieldIndex('id')) 531 532 zcat._catalog.addIndex('ipAddressAsInt', makeCaseSensitiveFieldIndex('ipAddressAsInt')) 533 zcat._catalog.addIndex('path', makeMultiPathIndex('path'))
534 535
536 - def discoverNetwork(self, REQUEST=None):
537 """ 538 """ 539 path = '/'.join(self.getPrimaryPath()[4:]) 540 return self.discoverDevices([path], REQUEST=REQUEST)
541
542 - def discoverDevices(self, organizerPaths=None, REQUEST = None):
543 """ 544 Load a device into the database connecting its major relations 545 and collecting its configuration. 546 """ 547 xmlrpc = isXmlRpc(REQUEST) 548 549 if not organizerPaths: 550 if xmlrpc: return 1 551 return self.callZenScreen(REQUEST) 552 553 zDiscCommand = "empty" 554 555 from Products.ZenUtils.ZenTales import talesEval 556 557 orgroot = self.getNetworkRoot() 558 for organizerName in organizerPaths: 559 organizer = orgroot.getOrganizer(organizerName) 560 if organizer is None: 561 if xmlrpc: return 1 # XML-RPC error 562 log.error("Couldn't obtain a network entry for '%s' " 563 "-- does it exist?" % organizerName) 564 continue 565 566 zDiscCommand = getattr(organizer, "zZenDiscCommand", None) 567 if zDiscCommand: 568 cmd = talesEval('string:' + zDiscCommand, organizer).split(" ") 569 else: 570 cmd = ["zendisc", "run", "--net", organizer.getNetworkName()] 571 if getattr(organizer, "zSnmpStrictDiscovery", False): 572 cmd += ["--snmp-strict-discovery"] 573 if getattr(organizer, "zPreferSnmpNaming", False): 574 cmd += ["--prefer-snmp-naming"] 575 zd = binPath('zendisc') 576 zendiscCmd = [zd] + cmd[1:] 577 status = self.dmd.JobManager.addJob(SubprocessJob, 578 description="Discover devices in network %s" % organizer.getNetworkName(), 579 args=(zendiscCmd,)) 580 581 log.info('Done') 582 583 if REQUEST and not xmlrpc: 584 REQUEST.RESPONSE.redirect('/zport/dmd/JobManager/joblist') 585 586 if xmlrpc: return 0
587 588
589 - def setupLog(self, response):
590 """setup logging package to send to browser""" 591 from logging import StreamHandler, Formatter 592 root = logging.getLogger() 593 self._v_handler = StreamHandler(response) 594 fmt = Formatter("""<tr class="tablevalues"> 595 <td>%(asctime)s</td><td>%(levelname)s</td> 596 <td>%(name)s</td><td>%(message)s</td></tr> 597 """, "%Y-%m-%d %H:%M:%S") 598 self._v_handler.setFormatter(fmt) 599 root.addHandler(self._v_handler) 600 root.setLevel(10)
601 602
603 - def clearLog(self):
604 alog = logging.getLogger() 605 if getattr(self, "_v_handler", False): 606 alog.removeHandler(self._v_handler)
607 608
609 - def loaderFooter(self, response):
610 """add navigation links to the end of the loader output""" 611 response.write("""<tr class="tableheader"><td colspan="4"> 612 Navigate to network <a href=%s>%s</a></td></tr>""" 613 % (self.absolute_url(), self.id)) 614 response.write("</table></body></html>")
615 616 security.declareProtected('View', 'getXMLEdges')
617 - def getXMLEdges(self, depth=1, filter='/', start=()):
618 """ Gets XML """ 619 if not start: start=self.id 620 edges = NetworkTree.get_edges(self, depth, 621 withIcons=True, filter=filter) 622 return edgesToXML(edges, start)
623
624 - def getIconPath(self):
625 """ gets icon """ 626 try: 627 return self.primaryAq().zIcon 628 except AttributeError: 629 return '/zport/dmd/img/icons/noicon.png'
630 631
655 656 InitializeClass(IpNetwork) 657 658
659 -class AutoDiscoveryJob(SubprocessJob):
660 """ 661 Job encapsulating autodiscovery over a set of IP addresses. 662 663 Accepts a list of strings describing networks OR a list of strings 664 specifying IP ranges, not both. Also accepts a set of zProperties to be 665 set on devices that are discovered. 666 """
667 - def _run(self, nets=(), ranges=(), zProperties=()):
668 # Store the nets and ranges 669 self.nets = nets 670 self.ranges = ranges 671 672 # Store zProperties on the job 673 if zProperties: 674 self.setProperties(**zProperties) 675 # Build the zendisc command 676 cmd = [binPath('zendisc')] 677 cmd.extend(['run', '--now', 678 '--monitor', 'localhost', 679 '--deviceclass', '/Discovered', 680 '--parallel', '8', 681 '--job', self.request.id 682 ]) 683 if not self.nets and not self.ranges: 684 # Gotta have something 685 self.log.error("Must pass in either a network or a range.") 686 elif self.nets and self.ranges: 687 # Can't have both 688 self.log.error("Must pass in either networks or ranges, not both") 689 else: 690 if self.nets: 691 for net in self.nets: 692 cmd.extend(['--net', net]) 693 elif self.ranges: 694 for iprange in self.ranges: 695 cmd.extend(['--range', iprange]) 696 SubprocessJob._run(self, cmd)
697 698
699 -class IpNetworkPrinter(object):
700
701 - def __init__(self, out):
702 """out is the output stream to print to""" 703 self._out = out
704 705
706 -class TextIpNetworkPrinter(IpNetworkPrinter):
707 """ 708 Prints out IpNetwork hierarchy as text with indented lines. 709 """ 710
711 - def printIpNetwork(self, net):
712 """ 713 Print out the IpNetwork and IpAddress hierarchy under net. 714 """ 715 self._printIpNetworkLine(net) 716 self._printTree(net)
717
718 - def _printTree(self, net, indent=" "):
719 for child in net.children(): 720 self._printIpNetworkLine(child, indent) 721 self._printTree(child, indent + " ") 722 for ipaddress in net.ipaddresses(): 723 args = (indent, ipaddress, ipaddress.__class__.__name__) 724 self._out.write("%s%s (%s)\n" % args)
725
726 - def _printIpNetworkLine(self, net, indent=""):
727 args = (indent, net.id, net.netmask, net.__class__.__name__) 728 self._out.write("%s%s/%s (%s)\n" % args)
729 730
731 -class PythonIpNetworkPrinter(IpNetworkPrinter):
732 """ 733 Prints out the IpNetwork hierarchy as a python dictionary. 734 """ 735
736 - def printIpNetwork(self, net):
737 """ 738 Print out the IpNetwork and IpAddress hierarchy under net. 739 """ 740 tree = {} 741 self._createTree(net, tree) 742 from pprint import pformat 743 self._out.write("%s\n" % pformat(tree))
744
745 - def _walkTree(self, net, tree):
746 for child in net.children(): 747 self._createTree(child, tree) 748 for ip in net.ipaddresses(): 749 key = (ip.__class__.__name__, ip.id, ip.netmask) 750 tree[key] = True
751
752 - def _createTree(self, net, tree):
753 key = (net.__class__.__name__, net.id, net.netmask) 754 subtree = {} 755 tree[key] = subtree 756 self._walkTree(net, subtree)
757 758
759 -class XmlIpNetworkPrinter(IpNetworkPrinter):
760 """ 761 Prints out the IpNetwork hierarchy as XML. 762 """ 763
764 - def printIpNetwork(self, net):
765 """ 766 Print out the IpNetwork and IpAddress hierarchy under net. 767 """ 768 self._doc = minidom.parseString('<root/>') 769 root = self._doc.documentElement 770 self._createTree(net, root) 771 self._out.write(self._doc.toprettyxml())
772
773 - def _walkTree(self, net, tree):
774 for child in net.children(): 775 self._createTree(child, tree) 776 for ip in net.ipaddresses(): 777 self._appendChild(tree, ip)
778
779 - def _createTree(self, net, tree):
780 node = self._appendChild(tree, net) 781 self._walkTree(net, node)
782
783 - def _appendChild(self, tree, child):
784 node = self._doc.createElement(child.__class__.__name__) 785 node.setAttribute("id", child.id) 786 node.setAttribute("netmask", str(child.netmask)) 787 tree.appendChild(node) 788 return node
789 790
791 -class IpNetworkPrinterFactory(object):
792
793 - def __init__(self):
794 self._printerFactories = {'text': TextIpNetworkPrinter, 795 'python': PythonIpNetworkPrinter, 796 'xml': XmlIpNetworkPrinter}
797
798 - def createIpNetworkPrinter(self, format, out):
799 if format in self._printerFactories: 800 factory = self._printerFactories[format] 801 return factory(out) 802 else: 803 args = (format, self._printerFactories.keys()) 804 raise Exception("Invalid format '%s' must be one of %s" % args)
805