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