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