Package Products :: Package DataCollector :: Module zendisc
[hide private]
[frames] | no frames]

Source Code for Module Products.DataCollector.zendisc

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2007, 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__ = """zendisc 
 15  Scan networks and routes looking for devices to add to the ZODB 
 16  """ 
 17   
 18  import socket 
 19   
 20  # IMPORTANT! The import of the pysamba.twisted.reactor module should come before 
 21  # any other libraries that might possibly use twisted. This will ensure that 
 22  # the proper WmiReactor is installed before anyone else grabs a reference to 
 23  # the wrong reactor. 
 24  import pysamba.twisted.reactor 
 25   
 26  import Globals 
 27  from optparse import SUPPRESS_HELP 
 28   
 29  from Products.DataCollector.zenmodeler import ZenModeler 
 30  from Products.ZenUtils.Exceptions import ZentinelException 
 31  from Products.ZenUtils.Utils import unused 
 32  from Products.ZenUtils.Driver import drive 
 33  from Products.ZenUtils.IpUtil import asyncNameLookup 
 34  from Products.ZenUtils.IpUtil import isip 
 35  from Products.ZenUtils.IpUtil import parse_iprange 
 36  from Products.ZenUtils.NJobs import NJobs 
 37  from Products.ZenUtils.snmp import SnmpV1Config, SnmpV2cConfig 
 38  from Products.ZenUtils.snmp import SnmpAgentDiscoverer 
 39  from Products.ZenModel.Exceptions import NoIPAddress 
 40  from Products.ZenEvents.ZenEventClasses import Status_Snmp 
 41  from Products.ZenEvents.Event import Info 
 42  from Products.ZenStatus.AsyncPing import Ping 
 43  from Products.ZenHub.PBDaemon import FakeRemote, PBDaemon 
 44  from Products.ZenHub.services  import DiscoverService, ModelerService 
 45  unused(DiscoverService, ModelerService) # for pb 
 46   
 47   
 48  from twisted.internet.defer import succeed 
 49  from twisted.python.failure import Failure 
 50  from twisted.internet import reactor 
 51  from twisted.names.error import DNSNameError 
 52   
 53   
54 -class ZenDisc(ZenModeler):
55 """ 56 Scan networks and routes looking for devices to add to the ZODB 57 """ 58 59 initialServices = PBDaemon.initialServices + ['DiscoverService'] 60 name = 'zendisc' 61 scanned = 0 62
63 - def __init__(self, single=True ):
64 """ 65 Initalizer 66 67 @param single: collect from a single device? 68 @type single: boolean 69 """ 70 ZenModeler.__init__(self, single ) 71 if not self.options.useFileDescriptor: 72 self.openPrivilegedPort('--ping') 73 self.discovered = [] 74 sock = None 75 if self.options.useFileDescriptor: 76 sock = int(self.options.useFileDescriptor) 77 self.ping = Ping(self.options.tries, 78 self.options.timeout, 79 sock=sock)
80 81
82 - def config(self):
83 """ 84 Get the DiscoverService 85 86 @return: a DiscoverService from zenhub 87 @rtype: function 88 """ 89 return self.services.get('DiscoverService', FakeRemote())
90 91
92 - def discoverIps(self, nets):
93 """ 94 Ping all ips, create entries in the network if necessary. 95 96 @param nets: list of networks to discover 97 @type nets: list 98 @return: successful result is a list of IPs that were added 99 @rtype: Twisted deferred 100 """ 101 def inner(driver): 102 """ 103 Twisted driver class to iterate through devices 104 105 @param driver: Zenoss driver 106 @type driver: Zenoss driver 107 @return: successful result is a list of IPs that were added 108 @rtype: Twisted deferred 109 """ 110 ips = [] 111 goodCount = 0 112 # it would be nice to interleave ping/discover 113 for net in nets: 114 if self.options.subnets and len(net.children()) > 0: 115 continue 116 if not getattr(net, "zAutoDiscover", False): 117 self.log.info( 118 "Skipping network %s because zAutoDiscover is False" 119 % net.getNetworkName()) 120 continue 121 self.log.info("Discover network '%s'", net.getNetworkName()) 122 yield NJobs(self.options.chunkSize, 123 self.ping.ping, 124 net.fullIpList()).start() 125 results = driver.next() 126 goodips = [ 127 v.ipaddr for v in results if not isinstance(v, Failure)] 128 badips = [ 129 v.value.ipaddr for v in results if isinstance(v, Failure)] 130 goodCount += len(goodips) 131 self.log.debug("Got %d good IPs and %d bad IPs", 132 len(goodips), len(badips)) 133 yield self.config().callRemote('pingStatus', 134 net, 135 goodips, 136 badips, 137 self.options.resetPtr, 138 self.options.addInactive) 139 ips += driver.next() 140 self.log.info("Discovered %s active ips", goodCount) 141 # make sure this is the return result for the driver 142 yield succeed(ips) 143 driver.next()
144 145 d = drive(inner) 146 return d
147
148 - def discoverRanges(self, driver):
149 """ 150 Ping all IPs in the range and create devices for the ones that come 151 back. 152 153 @param ranges: list of ranges to discover 154 @type ranges: list 155 """ 156 if isinstance(self.options.range, basestring): 157 self.options.range = [self.options.range] 158 # in case someone uses 10.0.0.0-5,192.168.0.1-5 instead of 159 # --range 10.0.0.0-5 --range 192.168.0.1-5 160 if (isinstance(self.options.range, list) and 161 self.options.range[0].find(",") > -1): 162 self.options.range = [n.strip() for n in 163 self.options.range[0].split(',')] 164 ips = [] 165 goodCount = 0 166 for iprange in self.options.range: 167 # Parse to find ips included 168 ips.extend(parse_iprange(iprange)) 169 yield NJobs(self.options.chunkSize, 170 self.ping.ping, 171 ips).start() 172 results = driver.next() 173 goodips = [v.ipaddr for v in results if not isinstance(v, Failure)] 174 badips = [v.value.ipaddr for v in results if isinstance(v, Failure)] 175 goodCount += len(goodips) 176 self.log.debug("Got %d good IPs and %d bad IPs", 177 len(goodips), len(badips)) 178 yield self.discoverDevices(goodips) 179 yield succeed("Discovered %d active IPs" % goodCount) 180 driver.next()
181 182
183 - def discoverRouters(self, rootdev, seenips=None):
184 """ 185 Discover all default routers based on DMD configuration. 186 187 @param rootdev: device root in DMD 188 @type rootdev: device class 189 @param seenips: list of IP addresses 190 @type seenips: list of strings 191 @return: Twisted/Zenoss Python iterable 192 @rtype: Python iterable 193 """ 194 if not seenips: 195 seenips = [] 196 197 def inner(driver): 198 """ 199 Twisted driver class to iterate through devices 200 201 @param driver: Zenoss driver 202 @type driver: Zenoss driver 203 @return: successful result is a list of IPs that were added 204 @rtype: Twisted deferred 205 """ 206 yield self.config().callRemote('followNextHopIps', rootdev.id) 207 for ip in driver.next(): 208 if ip in seenips: 209 continue 210 self.log.info("device '%s' next hop '%s'", rootdev.id, ip) 211 seenips.append(ip) 212 yield self.discoverDevice(ip, devicepath="/Network/Router") 213 router = driver.next() 214 if not router: 215 continue 216 yield self.discoverRouters(router, seenips) 217 driver.next()
218 219 return drive(inner) 220 221
222 - def sendDiscoveredEvent(self, ip, dev=None, sev=2):
223 """ 224 Send a 'device discovered' event through zenhub 225 226 @param ip: IP addresses 227 @type ip: strings 228 @param dev: remote device name 229 @type dev: device object 230 @param sev: severity 231 @type sev: integer 232 """ 233 devname = comp = ip 234 if dev: 235 devname = dev.id 236 msg = "'Discovered device name '%s' for ip '%s'" % (devname, ip) 237 evt = dict(device=devname,ipAddress=ip,eventKey=ip, 238 component=comp,eventClass=Status_Snmp, 239 summary=msg, severity=sev, 240 agent="Discover") 241 self.sendEvent(evt)
242 243
244 - def discoverDevices(self, 245 ips, 246 devicepath="/Discovered", 247 prodState=1000):
248 """ 249 Discover devices by active ips that are not associated with a device. 250 251 @param ips: list of IP addresses 252 @type ips: list of strings 253 @param devicepath: where in the DMD to put any discovered devices 254 @type devicepath: string 255 @param prodState: production state (see Admin Guide for a description) 256 @type prodState: integer 257 @return: Twisted/Zenoss Python iterable 258 @rtype: Python iterable 259 """ 260 def discoverDevice(ip): 261 """ 262 Discover a particular device 263 NB: Wrapper around self.discoverDevice() 264 265 @param ip: IP address 266 @type ip: string 267 @return: Twisted/Zenoss Python iterable 268 @rtype: Python iterable 269 """ 270 return self.discoverDevice(ip, devicepath, prodState)
271 272 return NJobs(self.options.parallel, discoverDevice, ips).start() 273 274
275 - def findRemoteDeviceInfo(self, ip, devicePath, deviceSnmpCommunities=None):
276 """ 277 Scan a device for ways of naming it: PTR DNS record or a SNMP name 278 279 @param ip: IP address 280 @type ip: string 281 @param devicePath: where in the DMD to put any discovered devices 282 @type devicePath: string 283 @param deviceSnmpCommunities: Optional list of SNMP community strings 284 to try, overriding those set on the device class 285 @type deviceSnmpCommunities: list 286 @return: result is None or a tuple containing 287 (community, port, version, snmp name) 288 @rtype: deferred: Twisted deferred 289 """ 290 from pynetsnmp.twistedsnmp import AgentProxy 291 292 def inner(driver): 293 """ 294 Twisted driver class to iterate through devices 295 296 @param driver: Zenoss driver 297 @type driver: Zenoss driver 298 @return: successful result is a list of IPs that were added 299 @rtype: Twisted deferred 300 """ 301 self.log.debug("Doing SNMP lookup on device %s", ip) 302 yield self.config().callRemote('getSnmpConfig', devicePath) 303 communities, port, version, timeout, retries = driver.next() 304 305 # Override the device class communities with the ones set on 306 # this device, if they exist 307 if deviceSnmpCommunities is not None: 308 communities = deviceSnmpCommunities 309 310 # Reverse the communities so that ones earlier in the list have a 311 # higher weight. 312 communities.reverse() 313 314 configs = [] 315 for i, community in enumerate(communities): 316 configs.append(SnmpV1Config( 317 ip, weight=i, port=port, timeout=timeout, 318 retries=retries, community=community)) 319 configs.append(SnmpV2cConfig( 320 ip, weight=i+100, port=port, timeout=timeout, 321 retries=retries, community=community)) 322 323 yield SnmpAgentDiscoverer().findBestConfig(configs) 324 driver.next() 325 self.log.debug("Finished SNMP lookup on device %s", ip)
326 327 return drive(inner) 328 329
330 - def discoverDevice(self, ip, devicepath="/Discovered", prodState=1000):
331 """ 332 Discover a device based on its IP address. 333 334 @param ip: IP address 335 @type ip: string 336 @param devicepath: where in the DMD to put any discovered devices 337 @type devicepath: string 338 @param prodState: production state (see Admin Guide for a description) 339 @type prodState: integer 340 @return: Twisted/Zenoss Python iterable 341 @rtype: Python iterable 342 """ 343 self.scanned += 1 344 if self.options.maxdevices: 345 if self.scanned >= self.options.maxdevices: 346 self.log.info("Limit of %d devices reached" % 347 self.options.maxdevices) 348 return succeed(None) 349 350 def inner(driver): 351 """ 352 Twisted driver class to iterate through devices 353 354 @param driver: Zenoss driver 355 @type driver: Zenoss driver 356 @return: successful result is a list of IPs that were added 357 @rtype: Twisted deferred 358 @todo: modularize this function (130+ lines is ridiculous) 359 """ 360 try: 361 kw = dict(deviceName=ip, 362 discoverProto=None, 363 devicePath=devicepath, 364 performanceMonitor=self.options.monitor) 365 366 # If zProperties are set via a job, get them and pass them in 367 if self.options.job: 368 yield self.config().callRemote('getJobProperties', 369 self.options.job) 370 job_props = driver.next() 371 if job_props is not None: 372 # grab zProperties from Job 373 kw['zProperties'] = job_props.get('zProperties', {}) 374 # grab other Device properties from jobs 375 #deviceProps = job_props.get('deviceProps', {}) 376 #kw.update(deviceProps) 377 #@FIXME we are not getting deviceProps, check calling 378 # chain for clues. twisted upgrade heartburn perhaps? 379 380 snmpDeviceInfo = None 381 # if we are using SNMP, lookup the device SNMP info and use the 382 # name defined there for deviceName 383 if not self.options.nosnmp: 384 self.log.debug("Scanning device with address %s", ip) 385 snmpCommunities = kw.get('zProperties', {}).get( 386 'zSnmpCommunities', None) 387 yield self.findRemoteDeviceInfo(ip, devicepath, 388 snmpCommunities) 389 snmp_config = driver.next() 390 if snmp_config: 391 if snmp_config.sysName: 392 kw['deviceName'] = snmp_config.sysName 393 394 if snmp_config.version: 395 kw['zSnmpVer'] = snmp_config.version 396 397 if snmp_config.port: 398 kw['zSnmpPort'] = snmp_config.port 399 400 if snmp_config.community: 401 kw['zSnmpCommunity'] = snmp_config.community 402 403 # if we are using SNMP, did not find any snmp info, 404 # and we are in strict discovery mode, do not 405 # create a device 406 elif self.options.zSnmpStrictDiscovery: 407 self.log.info('zSnmpStrictDiscovery is True. ' + 408 'Not creating device for %s.' 409 % ip ) 410 return 411 412 # RULES FOR DEVICE NAMING: 413 # 1. If zPreferSnmpNaming is true: 414 # If snmp name is returned, use snmp name. Otherwise, 415 # use the passed device name. If no device name was passed, 416 # do a dns lookup on the ip. 417 # 2. If zPreferSnmpNaming is false: 418 # If we are discovering a single device and a name is 419 # passed in instead of an IP, use the passed-in name. 420 # Otherwise, do a dns lookup on the ip. 421 if self.options.zPreferSnmpNaming and \ 422 not isip( kw['deviceName'] ): 423 # In this case, we want to keep kw['deviceName'] as-is, 424 # because it is what we got from snmp 425 pass 426 elif self.options.device and not isip(self.options.device): 427 kw['deviceName'] = self.options.device 428 else: 429 # An IP was passed in so we do a reverse lookup on it to get 430 # deviceName 431 yield asyncNameLookup(ip) 432 try: 433 kw.update(dict(deviceName=driver.next())) 434 except Exception, ex: 435 self.log.debug("Failed to lookup %s (%s)" % (ip, ex)) 436 437 # If it's discovering a particular device, 438 # ignore zAutoDiscover limitations 439 forceDiscovery = bool(self.options.device) 440 441 442 # now create the device by calling zenhub 443 yield self.config().callRemote('createDevice', ip, 444 force=forceDiscovery, **kw) 445 446 result = driver.next() 447 if isinstance(result, Failure): 448 raise ZentinelException(result.value) 449 dev, created = result 450 451 # if no device came back from createDevice we assume that it 452 # was told to not auto-discover the device. This seems very 453 # dubious to me! -EAD 454 if not dev: 455 self.log.info("IP '%s' on no auto-discover, skipping",ip) 456 return 457 else: 458 # A device came back and it already existed. 459 if not created and not dev.temp_device: 460 # if we shouldn't remodel skip the device by returning 461 # at the end of this block 462 if not self.options.remodel: 463 self.log.info("Found IP '%s' on device '%s';" 464 " skipping discovery", ip, dev.id) 465 if self.options.device: 466 self.setExitCode(3) 467 yield succeed(dev) 468 driver.next() 469 return 470 else: 471 # we continue on to model the device. 472 self.log.info("IP '%s' on device '%s' remodel", 473 ip, dev.id) 474 self.sendDiscoveredEvent(ip, dev) 475 476 # use the auto-allocate flag to change the device class 477 # FIXME - this does not currently work 478 newPath = self.autoAllocate(dev) 479 if newPath: 480 yield self.config().callRemote('moveDevice', dev.id, 481 newPath) 482 driver.next() 483 484 # the device that we found/created or that should be remodeled 485 # is added to the list of devices to be modeled later 486 if not self.options.nosnmp: 487 self.discovered.append(dev.id) 488 yield succeed(dev) 489 driver.next() 490 except ZentinelException, e: 491 self.log.exception(e) 492 evt = dict(device=ip, 493 component=ip, 494 ipAddress=ip, 495 eventKey=ip, 496 eventClass=Status_Snmp, 497 summary=str(e), 498 severity=Info, 499 agent="Discover") 500 if self.options.snmpMissing: 501 self.sendEvent(evt) 502 except Exception, e: 503 self.log.exception("Failed device discovery for '%s'", ip) 504 505 else: 506 yield self.config().callRemote('succeedDiscovery', dev.id) 507 driver.next() 508 #device needs to be the last thing yielded so that 509 #calling methods will get the deviceproxy 510 yield succeed(dev) 511 driver.next() 512 513 self.log.debug("Finished scanning device with address %s", ip)
514 515 return drive(inner) 516 517
518 - def collectNet(self, driver):
519 """ 520 Twisted driver class to iterate through networks 521 522 @param driver: Zenoss driver 523 @type driver: Zenoss driver 524 @return: successful result is a list of IPs that were added 525 @rtype: Twisted deferred 526 """ 527 528 import types 529 # net option from the config file is a string 530 if type(self.options.net) in types.StringTypes: 531 self.options.net = [self.options.net] 532 # in case someone uses 10.0.0.0,192.168.0.1 instead of 533 # --net 10.0.0.0 --net 192.168.0.1 534 if isinstance(self.options.net, list) and \ 535 self.options.net[0].find(",") > -1: 536 self.options.net = [ 537 n.strip() for n in self.options.net[0].split(',') 538 ] 539 count = 0 540 devices = [] 541 if not self.options.net: 542 yield self.config().callRemote('getDefaultNetworks') 543 self.options.net = driver.next() 544 545 if not self.options.net: 546 self.log.warning("No networks configured") 547 return 548 549 for net in self.options.net: 550 try: 551 yield self.config().callRemote('getNetworks', 552 net, 553 self.options.subnets) 554 nets = driver.next() 555 if not nets: 556 self.log.warning("No networks found for %s" % (net,)) 557 continue 558 yield self.discoverIps(nets) 559 ips = driver.next() 560 devices += ips 561 count += len(ips) 562 except Exception, ex: 563 self.log.exception("Error performing net discovery on %s", ex) 564 def discoverDevice(ip): 565 """ 566 Discover a particular device 567 NB: Wrapper around self.discoverDevice() 568 569 @param ip: IP address 570 @type ip: string 571 @return: Twisted/Zenoss Python iterable 572 @rtype: Python iterable 573 """ 574 return self.discoverDevice(ip, 575 self.options.deviceclass, 576 self.options.productionState)
577 yield NJobs(self.options.parallel, discoverDevice, devices).start() 578 yield succeed("Discovered %d devices" % count) 579 driver.next() 580 581
582 - def printResults(self, results):
583 """ 584 Display the results that we've obtained 585 586 @param results: what we've discovered 587 @type results: string 588 """ 589 if isinstance(results, Failure): 590 self.log.error("Error: %s", results) 591 else: 592 self.log.info("Result: %s", results) 593 self.main()
594 595
596 - def createDevice(self, driver):
597 """ 598 Add a device to the system by name or IP. 599 600 @param driver: driver object 601 @type driver: Twisted/Zenoss object 602 @return: Twisted deferred 603 @rtype: Twisted deferred 604 """ 605 deviceName = self.options.device 606 self.log.info("Looking for %s" % deviceName) 607 ip = None 608 if isip(deviceName): 609 ip = deviceName 610 else: 611 try: 612 # FIXME ZenUtils.IpUtil.asyncIpLookup is probably a better tool 613 # for this, but it hasn't been tested, so it's for another day 614 ip = socket.gethostbyname(deviceName) 615 except socket.error: 616 ip = "" 617 if not ip: 618 raise NoIPAddress("No IP found for name %s" % deviceName) 619 else: 620 self.log.debug("Found IP %s for device %s" % (ip, deviceName)) 621 yield self.config().callRemote('getDeviceConfig', [deviceName]) 622 me, = driver.next() or [None] 623 if not me or me.temp_device or self.options.remodel: 624 yield self.discoverDevice(ip, 625 devicepath=self.options.deviceclass, 626 prodState=self.options.productionState) 627 yield succeed("Discovered device %s." % deviceName) 628 driver.next()
629 630
631 - def walkDiscovery(self, driver):
632 """ 633 Python iterable to go through discovery 634 635 @return: Twisted deferred 636 @rtype: Twisted deferred 637 """ 638 myname = socket.getfqdn() 639 self.log.debug("My hostname = %s", myname) 640 myip = None 641 try: 642 myip = socket.gethostbyname(myname) 643 self.log.debug("My IP address = %s", myip) 644 except (socket.error, DNSNameError): 645 raise SystemExit("Failed lookup of my IP for name %s", myname) 646 647 yield self.config().callRemote('getDeviceConfig', [myname]) 648 me, = driver.next() or [None] 649 if not me or self.options.remodel: 650 yield self.discoverDevice(myip, 651 devicepath=self.options.deviceclass, 652 prodState=self.options.productionState) 653 me = driver.next() 654 if not me: 655 raise SystemExit("SNMP discover of self '%s' failed" % myname) 656 if not myip: 657 myip = me.manageIp 658 if not myip: 659 raise SystemExit("Can't find my IP for name %s" % myname) 660 661 yield self.discoverRouters(me, [myip]) 662 663 driver.next() 664 if self.options.routersonly: 665 self.log.info("Only routers discovered, skipping ping sweep.") 666 else: 667 yield self.config().callRemote('getSubNetworks') 668 yield self.discoverIps(driver.next()) 669 ips = driver.next() 670 if not self.options.nosnmp: 671 yield self.discoverDevices(ips) 672 driver.next()
673 674
675 - def getDeviceList(self):
676 """ 677 Our device list comes from our list of newly discovered devices 678 679 @return: list of discovered devices 680 @rtype: Twisted succeed() object 681 """ 682 return succeed(self.discovered)
683 684
685 - def connected(self):
686 """ 687 Called by Twisted once a connection has been established. 688 """ 689 d = self.configure() 690 d.addCallback(self.startDiscovery) 691 d.addErrback(self.reportError)
692 693 694
695 - def startDiscovery(self, data):
696 if self.options.walk: 697 d = drive(self.walkDiscovery) 698 699 elif self.options.device: 700 d = drive(self.createDevice) 701 702 elif self.options.range: 703 d = drive(self.discoverRanges) 704 705 else: 706 d = drive(self.collectNet) 707 708 d.addBoth(self.printResults)
709 710
711 - def autoAllocate(self, device=None):
712 """ 713 Execute a script that will auto allocate devices into their 714 Device Classes 715 716 @param device: device object 717 @type device: device object 718 @return: Device class path to put the new device 719 @rtype: string 720 @todo: make it actually work 721 """ 722 self.log.debug("trying to auto-allocate device %s" % device.id ) 723 if not device: 724 return 725 script = getattr(device, "zAutoAllocateScript", None) 726 self.log.debug("no auto-allocation script found") 727 if script: 728 import string 729 script = string.join(script, "\n") 730 self.log.debug("using script\n%s" % script) 731 try: 732 compile(script, "zAutoAllocateScript", "exec") 733 except: 734 self.log.error("zAutoAllocateScript contains error") 735 return 736 vars = {'dev': device, 'log': self.log} 737 try: 738 exec(script, vars) 739 except: 740 self.log.error( 741 "error executing zAutoAllocateScript:\n%s" % script) 742 return vars.get('devicePath', None) 743 return
744 745
746 - def buildOptions(self):
747 """ 748 Command-line option builder for optparse 749 """ 750 ZenModeler.buildOptions(self) 751 self.parser.add_option('--net', dest='net', action="append", 752 help="Discover all device on this network") 753 self.parser.add_option('--range', dest='range', action='append', 754 help="Discover all IPs in this range") 755 self.parser.add_option('--deviceclass', dest='deviceclass', 756 default="/Discovered", 757 help="Default device class for discovered devices") 758 self.parser.add_option('--prod_state', dest='productionState', 759 default=1000, 760 help="Initial production state for discovered devices") 761 self.parser.add_option('--remodel', dest='remodel', 762 action="store_true", default=False, 763 help="Remodel existing objects") 764 self.parser.add_option('--routers', dest='routersonly', 765 action="store_true", default=False, 766 help="Only discover routers") 767 self.parser.add_option('--tries', dest='tries', default=1, type="int", 768 help="How many ping tries") 769 self.parser.add_option('--timeout', dest='timeout', 770 default=2, type="float", 771 help="ping timeout in seconds") 772 self.parser.add_option('--chunk', dest='chunkSize', 773 default=10, type="int", 774 help="number of in flight ping packets") 775 self.parser.add_option('--snmp-missing', dest='snmpMissing', 776 action="store_true", default=False, 777 help="Send an event if SNMP is not found on the device") 778 self.parser.add_option('--add-inactive', dest='addInactive', 779 action="store_true", default=False, 780 help="Add all IPs found, even if they are unresponsive") 781 self.parser.add_option('--reset-ptr', dest='resetPtr', 782 action="store_true", default=False, 783 help="Reset all ip PTR records") 784 self.parser.add_option('--no-snmp', dest='nosnmp', 785 action="store_true", default=False, 786 help="Skip SNMP discovery on found IP addresses") 787 self.parser.add_option('--subnets', dest='subnets', 788 action="store_true", default=False, 789 help="Recurse into subnets for discovery") 790 self.parser.add_option('--useFileDescriptor', 791 dest='useFileDescriptor', default=None, 792 help="Use the given (privileged) file descriptor for ping") 793 self.parser.add_option('--assign-devclass-script', dest='autoAllocate', 794 action="store_true", default=False, 795 help="have zendisc auto allocate devices after discovery") 796 self.parser.add_option('--walk', dest='walk', action='store_true', 797 default=False, 798 help="Walk the route tree, performing discovery on all networks") 799 self.parser.add_option('--max-devices', dest='maxdevices', 800 default=0, 801 type='int', 802 help="Collect a maximum number of devices. Default is no limit.") 803 self.parser.add_option('--snmp-strict-discovery', 804 dest='zSnmpStrictDiscovery', 805 action="store_true", default=False, 806 help="Only add devices that can be modeled via snmp." ) 807 self.parser.add_option('--prefer-snmp-naming', 808 dest='zPreferSnmpNaming', 809 action="store_true", default=False, 810 help="Prefer snmp name to dns name when modeling via snmp." ) 811 # --job: a development-only option that jobs will use to communicate 812 # their existence to zendisc. Not for users, so help is suppressed. 813 self.parser.add_option('--job', dest='job', help=SUPPRESS_HELP )
814 815 816 817 if __name__ == "__main__": 818 d = ZenDisc() 819 d.processOptions() 820 reactor.run = d.reactorLoop 821 d.run() 822