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.ZenModel.Exceptions import NoIPAddress 
 38  from Products.ZenEvents.ZenEventClasses import Status_Snmp 
 39  from Products.ZenEvents.Event import Info 
 40  from Products.ZenStatus.AsyncPing import Ping 
 41  from Products.ZenHub.PBDaemon import FakeRemote, PBDaemon 
 42  from Products.ZenHub.services  import DiscoverService, ModelerService 
 43  unused(DiscoverService, ModelerService) # for pb 
 44   
 45   
 46  from twisted.internet.defer import succeed 
 47  from twisted.python.failure import Failure 
 48  from twisted.internet import reactor 
 49  from twisted.names.error import DNSNameError 
 50   
 51   
52 -class ZenDisc(ZenModeler):
53 """ 54 Scan networks and routes looking for devices to add to the ZODB 55 """ 56 57 initialServices = PBDaemon.initialServices + ['DiscoverService'] 58 name = 'zendisc' 59 scanned = 0 60
61 - def __init__(self, single=True ):
62 """ 63 Initalizer 64 65 @param single: collect from a single device? 66 @type single: boolean 67 """ 68 ZenModeler.__init__(self, single ) 69 if not self.options.useFileDescriptor: 70 self.openPrivilegedPort('--ping') 71 self.discovered = [] 72 sock = None 73 if self.options.useFileDescriptor: 74 sock = int(self.options.useFileDescriptor) 75 self.ping = Ping(self.options.tries, 76 self.options.timeout, 77 sock=sock)
78 79
80 - def config(self):
81 """ 82 Get the DiscoverService 83 84 @return: a DiscoverService from zenhub 85 @rtype: function 86 """ 87 return self.services.get('DiscoverService', FakeRemote())
88 89
90 - def discoverIps(self, nets):
91 """ 92 Ping all ips, create entries in the network if necessary. 93 94 @param nets: list of networks to discover 95 @type nets: list 96 @return: successful result is a list of IPs that were added 97 @rtype: Twisted deferred 98 """ 99 def inner(driver): 100 """ 101 Twisted driver class to iterate through devices 102 103 @param driver: Zenoss driver 104 @type driver: Zenoss driver 105 @return: successful result is a list of IPs that were added 106 @rtype: Twisted deferred 107 """ 108 ips = [] 109 goodCount = 0 110 # it would be nice to interleave ping/discover 111 for net in nets: 112 if self.options.subnets and len(net.children()) > 0: 113 continue 114 if not getattr(net, "zAutoDiscover", False): 115 self.log.info( 116 "Skipping network %s because zAutoDiscover is False" 117 % net.getNetworkName()) 118 continue 119 self.log.info("Discover network '%s'", net.getNetworkName()) 120 yield NJobs(self.options.chunkSize, 121 self.ping.ping, 122 net.fullIpList()).start() 123 results = driver.next() 124 goodips = [ 125 v.ipaddr for v in results if not isinstance(v, Failure)] 126 badips = [ 127 v.value.ipaddr for v in results if isinstance(v, Failure)] 128 goodCount += len(goodips) 129 self.log.debug("Got %d good IPs and %d bad IPs", 130 len(goodips), len(badips)) 131 yield self.config().callRemote('pingStatus', 132 net, 133 goodips, 134 badips, 135 self.options.resetPtr, 136 self.options.addInactive) 137 ips += driver.next() 138 self.log.info("Discovered %s active ips", goodCount) 139 # make sure this is the return result for the driver 140 yield succeed(ips) 141 driver.next()
142 143 d = drive(inner) 144 return d
145
146 - def discoverRanges(self, driver):
147 """ 148 Ping all IPs in the range and create devices for the ones that come 149 back. 150 151 @param ranges: list of ranges to discover 152 @type ranges: list 153 """ 154 if isinstance(self.options.range, basestring): 155 self.options.range = [self.options.range] 156 # in case someone uses 10.0.0.0-5,192.168.0.1-5 instead of 157 # --range 10.0.0.0-5 --range 192.168.0.1-5 158 if (isinstance(self.options.range, list) and 159 self.options.range[0].find(",") > -1): 160 self.options.range = [n.strip() for n in 161 self.options.range[0].split(',')] 162 ips = [] 163 goodCount = 0 164 for iprange in self.options.range: 165 # Parse to find ips included 166 ips.extend(parse_iprange(iprange)) 167 yield NJobs(self.options.chunkSize, 168 self.ping.ping, 169 ips).start() 170 results = driver.next() 171 goodips = [v.ipaddr for v in results if not isinstance(v, Failure)] 172 badips = [v.value.ipaddr for v in results if isinstance(v, Failure)] 173 goodCount += len(goodips) 174 self.log.debug("Got %d good IPs and %d bad IPs", 175 len(goodips), len(badips)) 176 yield self.discoverDevices(goodips) 177 yield succeed("Discovered %d active IPs" % goodCount) 178 driver.next()
179 180
181 - def discoverRouters(self, rootdev, seenips=None):
182 """ 183 Discover all default routers based on DMD configuration. 184 185 @param rootdev: device root in DMD 186 @type rootdev: device class 187 @param seenips: list of IP addresses 188 @type seenips: list of strings 189 @return: Twisted/Zenoss Python iterable 190 @rtype: Python iterable 191 """ 192 if not seenips: 193 seenips = [] 194 195 def inner(driver): 196 """ 197 Twisted driver class to iterate through devices 198 199 @param driver: Zenoss driver 200 @type driver: Zenoss driver 201 @return: successful result is a list of IPs that were added 202 @rtype: Twisted deferred 203 """ 204 yield self.config().callRemote('followNextHopIps', rootdev.id) 205 for ip in driver.next(): 206 if ip in seenips: 207 continue 208 self.log.info("device '%s' next hop '%s'", rootdev.id, ip) 209 seenips.append(ip) 210 yield self.discoverDevice(ip, devicepath="/Network/Router") 211 router = driver.next() 212 if not router: 213 continue 214 yield self.discoverRouters(router, seenips) 215 driver.next()
216 217 return drive(inner) 218 219
220 - def sendDiscoveredEvent(self, ip, dev=None, sev=2):
221 """ 222 Send a 'device discovered' event through zenhub 223 224 @param ip: IP addresses 225 @type ip: strings 226 @param dev: remote device name 227 @type dev: device object 228 @param sev: severity 229 @type sev: integer 230 """ 231 devname = comp = ip 232 if dev: 233 devname = dev.id 234 msg = "'Discovered device name '%s' for ip '%s'" % (devname, ip) 235 evt = dict(device=devname,ipAddress=ip,eventKey=ip, 236 component=comp,eventClass=Status_Snmp, 237 summary=msg, severity=sev, 238 agent="Discover") 239 self.sendEvent(evt)
240 241
242 - def discoverDevices(self, 243 ips, 244 devicepath="/Discovered", 245 prodState=1000):
246 """ 247 Discover devices by active ips that are not associated with a device. 248 249 @param ips: list of IP addresses 250 @type ips: list of strings 251 @param devicepath: where in the DMD to put any discovered devices 252 @type devicepath: string 253 @param prodState: production state (see Admin Guide for a description) 254 @type prodState: integer 255 @return: Twisted/Zenoss Python iterable 256 @rtype: Python iterable 257 """ 258 def discoverDevice(ip): 259 """ 260 Discover a particular device 261 NB: Wrapper around self.discoverDevice() 262 263 @param ip: IP address 264 @type ip: string 265 @return: Twisted/Zenoss Python iterable 266 @rtype: Python iterable 267 """ 268 return self.discoverDevice(ip, devicepath, prodState)
269 270 return NJobs(self.options.parallel, discoverDevice, ips).start() 271 272
273 - def findRemoteDeviceInfo(self, ip, devicePath, deviceSnmpCommunities=None):
274 """ 275 Scan a device for ways of naming it: PTR DNS record or a SNMP name 276 277 @param ip: IP address 278 @type ip: string 279 @param devicePath: where in the DMD to put any discovered devices 280 @type devicePath: string 281 @param deviceSnmpCommunities: Optional list of SNMP community strings 282 to try, overriding those set on the device class 283 @type deviceSnmpCommunities: list 284 @return: result is None or a tuple containing 285 (community, port, version, snmp name) 286 @rtype: deferred: Twisted deferred 287 """ 288 from pynetsnmp.twistedsnmp import AgentProxy 289 290 def inner(driver): 291 """ 292 Twisted driver class to iterate through devices 293 294 @param driver: Zenoss driver 295 @type driver: Zenoss driver 296 @return: successful result is a list of IPs that were added 297 @rtype: Twisted deferred 298 """ 299 self.log.debug("Doing SNMP lookup on device %s", ip) 300 yield self.config().callRemote('getSnmpConfig', devicePath) 301 communities, port, version, timeout, retries = driver.next() 302 303 # Override the device class communities with the ones set on 304 # this device, if they exist 305 if deviceSnmpCommunities is not None: 306 communities = deviceSnmpCommunities 307 308 oid = ".1.3.6.1.2.1.1.5.0" 309 goodcommunity = "" 310 goodversion = "" 311 devname = "" 312 for version in ("v2c", "v1"): 313 for community in communities: 314 proxy = AgentProxy(ip, 315 port, 316 timeout=timeout, 317 community=community, 318 snmpVersion=version, 319 tries=retries - 1) 320 proxy.open() 321 try: 322 yield proxy.get([oid]) 323 devname = driver.next().values()[0] 324 proxy.close() 325 goodcommunity = community 326 goodversion = version 327 break 328 except: 329 pass 330 if goodcommunity: 331 yield succeed((goodcommunity, port, goodversion, devname)) 332 break 333 else: 334 yield succeed(None) 335 driver.next() 336 self.log.debug("Finished SNMP lookup on device %s", ip)
337 338 return drive(inner) 339 340
341 - def discoverDevice(self, ip, devicepath="/Discovered", prodState=1000):
342 """ 343 Discover a device based on its IP address. 344 345 @param ip: IP address 346 @type ip: string 347 @param devicepath: where in the DMD to put any discovered devices 348 @type devicepath: string 349 @param prodState: production state (see Admin Guide for a description) 350 @type prodState: integer 351 @return: Twisted/Zenoss Python iterable 352 @rtype: Python iterable 353 """ 354 self.scanned += 1 355 if self.options.maxdevices: 356 if self.scanned >= self.options.maxdevices: 357 self.log.info("Limit of %d devices reached" % 358 self.options.maxdevices) 359 return succeed(None) 360 361 def inner(driver): 362 """ 363 Twisted driver class to iterate through devices 364 365 @param driver: Zenoss driver 366 @type driver: Zenoss driver 367 @return: successful result is a list of IPs that were added 368 @rtype: Twisted deferred 369 @todo: modularize this function (130+ lines is ridiculous) 370 """ 371 try: 372 kw = dict(deviceName=ip, 373 discoverProto=None, 374 devicePath=devicepath, 375 performanceMonitor=self.options.monitor) 376 377 # If zProperties are set via a job, get them and pass them in 378 if self.options.job: 379 yield self.config().callRemote('getJobProperties', 380 self.options.job) 381 job_props = driver.next() 382 if job_props is not None: 383 kw['zProperties'] = job_props.get('zProperties', {}) 384 385 snmpDeviceInfo = None 386 # if we are using SNMP, lookup the device SNMP info and use the 387 # name defined there for deviceName 388 if not self.options.nosnmp: 389 self.log.debug("Scanning device with address %s", ip) 390 snmpCommunities = kw.get('zProperties', {}).get( 391 'zSnmpCommunities', None) 392 yield self.findRemoteDeviceInfo(ip, devicepath, 393 snmpCommunities) 394 snmpDeviceInfo = driver.next() 395 if snmpDeviceInfo: 396 keys = ('zSnmpCommunity', 'zSnmpPort', 'zSnmpVer', 397 'deviceName') 398 snmpDeviceInfo = dict(zip(keys, snmpDeviceInfo)) 399 for k, v in snmpDeviceInfo.iteritems(): 400 # Only override if not empty 401 if v: kw[k] = v 402 # if we are using SNMP, did not find any snmp info, 403 # and we are in strict discovery mode, do not 404 # create a device 405 elif self.options.zSnmpStrictDiscovery: 406 self.log.info('zSnmpStrictDiscovery is True. ' + 407 'Not creating device for %s.' 408 % ip ) 409 return 410 411 # RULES FOR DEVICE NAMING: 412 # 1. If zPreferSnmpNaming is true: 413 # If snmp name is returned, use snmp name. Otherwise, 414 # use the passed device name. If no device name was passed, 415 # do a dns lookup on the ip. 416 # 2. If zPreferSnmpNaming is false: 417 # If we are discovering a single device and a name is 418 # passed in instead of an IP, use the passed-in name. 419 # Otherwise, do a dns lookup on the ip. 420 #import pydevd;pydevd.settrace() 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 if self.options.walk: 690 d = drive(self.walkDiscovery) 691 692 elif self.options.device: 693 d = drive(self.createDevice) 694 695 elif self.options.range: 696 d = drive(self.discoverRanges) 697 698 else: 699 d = drive(self.collectNet) 700 701 d.addBoth(self.printResults)
702 703
704 - def autoAllocate(self, device=None):
705 """ 706 Execute a script that will auto allocate devices into their 707 Device Classes 708 709 @param device: device object 710 @type device: device object 711 @return: Device class path to put the new device 712 @rtype: string 713 @todo: make it actually work 714 """ 715 self.log.debug("trying to auto-allocate device %s" % device.id ) 716 if not device: 717 return 718 script = getattr(device, "zAutoAllocateScript", None) 719 self.log.debug("no auto-allocation script found") 720 if script: 721 import string 722 script = string.join(script, "\n") 723 self.log.debug("using script\n%s" % script) 724 try: 725 compile(script, "zAutoAllocateScript", "exec") 726 except: 727 self.log.error("zAutoAllocateScript contains error") 728 return 729 vars = {'dev': device, 'log': self.log} 730 try: 731 exec(script, vars) 732 except: 733 self.log.error( 734 "error executing zAutoAllocateScript:\n%s" % script) 735 return vars.get('devicePath', None) 736 return
737 738
739 - def buildOptions(self):
740 """ 741 Command-line option builder for optparse 742 """ 743 ZenModeler.buildOptions(self) 744 self.parser.add_option('--net', dest='net', action="append", 745 help="Discover all device on this network") 746 self.parser.add_option('--range', dest='range', action='append', 747 help="Discover all IPs in this range") 748 self.parser.add_option('--deviceclass', dest='deviceclass', 749 default="/Discovered", 750 help="Default device class for discovered devices") 751 self.parser.add_option('--prod_state', dest='productionState', 752 default=1000, 753 help="Initial production state for discovered devices") 754 self.parser.add_option('--remodel', dest='remodel', 755 action="store_true", default=False, 756 help="Remodel existing objects") 757 self.parser.add_option('--routers', dest='routersonly', 758 action="store_true", default=False, 759 help="Only discover routers") 760 self.parser.add_option('--tries', dest='tries', default=1, type="int", 761 help="How many ping tries") 762 self.parser.add_option('--timeout', dest='timeout', 763 default=2, type="float", 764 help="ping timeout in seconds") 765 self.parser.add_option('--chunk', dest='chunkSize', 766 default=10, type="int", 767 help="number of in flight ping packets") 768 self.parser.add_option('--snmp-missing', dest='snmpMissing', 769 action="store_true", default=False, 770 help="Send an event if SNMP is not found on the device") 771 self.parser.add_option('--add-inactive', dest='addInactive', 772 action="store_true", default=False, 773 help="Add all IPs found, even if they are unresponsive") 774 self.parser.add_option('--reset-ptr', dest='resetPtr', 775 action="store_true", default=False, 776 help="Reset all ip PTR records") 777 self.parser.add_option('--no-snmp', dest='nosnmp', 778 action="store_true", default=False, 779 help="Skip SNMP discovery on found IP addresses") 780 self.parser.add_option('--subnets', dest='subnets', 781 action="store_true", default=False, 782 help="Recurse into subnets for discovery") 783 self.parser.add_option('--useFileDescriptor', 784 dest='useFileDescriptor', default=None, 785 help="Use the given (privileged) file descriptor for ping") 786 self.parser.add_option('--assign-devclass-script', dest='autoAllocate', 787 action="store_true", default=False, 788 help="have zendisc auto allocate devices after discovery") 789 self.parser.add_option('--walk', dest='walk', action='store_true', 790 default=False, 791 help="Walk the route tree, performing discovery on all networks") 792 self.parser.add_option('--max-devices', dest='maxdevices', 793 default=0, 794 type='int', 795 help="Collect a maximum number of devices. Default is no limit.") 796 self.parser.add_option('--snmp-strict-discovery', 797 dest='zSnmpStrictDiscovery', 798 action="store_true", default=False, 799 help="Only add devices that can be modeled via snmp." ) 800 self.parser.add_option('--prefer-snmp-naming', 801 dest='zPreferSnmpNaming', 802 action="store_true", default=False, 803 help="Prefer snmp name to dns name when modeling via snmp." ) 804 # --job: a development-only option that jobs will use to communicate 805 # their existence to zendisc. Not for users, so help is suppressed. 806 self.parser.add_option('--job', dest='job', help=SUPPRESS_HELP )
807 808 809 810 if __name__ == "__main__": 811 d = ZenDisc() 812 d.processOptions() 813 reactor.run = d.reactorLoop 814 d.run() 815