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

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