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