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

Source Code for Module Products.ZenModel.IpNetwork

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