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