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