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

Source Code for Module Products.DataCollector.zendisc

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