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

# Source Code for Module Products.DataCollector.SnmpClient

      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  import sys
     15  import logging
     16  log = logging.getLogger("zen.SnmpClient")
     17
     18  from twisted.internet import reactor, error, defer
     19  from twisted.python import failure
     20  from twisted.internet.error import TimeoutError
     21
     22  from pynetsnmp.twistedsnmp import snmpprotocol
     23
     24  import Globals
     25
     26  from Products.ZenUtils.Driver import drive
     27
     28  global defaultTries, defaultTimeout
     29  defaultTries = 2
     30  defaultTimeout = 1
     31  defaultSnmpCommunity = 'public'
     32
     33  DEFAULT_MAX_OIDS_BACK = 40
     34
     35  from BaseClient import BaseClient
     36
     37 -class SnmpClient(BaseClient):
     38
     39 -    def __init__(self, hostname, ipaddr, options=None, device=None,
     40                   datacollector=None, plugins=[]):
     41          BaseClient.__init__(self, device, datacollector)
     42          global defaultTries, defaultTimeout
     43          self.hostname = hostname
     44          self.device = device
     45          self.options = options
     46          self.datacollector = datacollector
     47          self.plugins = plugins
     48
     49          self._getdata = {}
     50          self._tabledata = {}
     51
     52          from Products.ZenHub.services.PerformanceConfig import SnmpConnInfo
     53          self.connInfo = SnmpConnInfo(device)
     54          srcport = snmpprotocol.port()
     55          self.proxy = self.connInfo.createSession(srcport.protocol)
     56
     57
     58 -    def run(self):
     59          """Start snmp collection.
     60          """
     61          log.debug("Starting %s", self.connInfo.summary())
     62          self.proxy.open()
     63          drive(self.doRun).addBoth(self.clientFinished)
     64
     65
     66      # FIXME: cleanup --force option #2660
     67 -    def checkCiscoChange(self, driver):
     68          """Check to see if a cisco box has changed.
     69          """
     70          device = self.device
     71          yield self.proxy.get(['.1.3.6.1.4.1.9.9.43.1.1.1.0'])
     72          lastpolluptime = device.getLastPollSnmpUpTime()
     73          log.debug("lastpolluptime = %s", lastpolluptime)
     74          result = True
     75          try:
     76              lastchange = driver.next().values()[0]
     77              log.debug("lastchange = %s", lastchange)
     78              if lastchange <= lastpolluptime:
     79                  log.info("skipping cisco device %s no change detected",
     80                           device.id)
     81                  result = False
     82              else:
     83                  device.setLastPollSnmpUpTime(lastchange)
     84          except Exception:
     85              pass
     86          yield defer.succeed(result)
     87
     88
     89 -    def doRun(self, driver):
     90          # test snmp connectivity
     91          log.debug("Testing SNMP configuration")
     92          yield self.proxy.walk('.1.3')
     93          try:
     94              driver.next()
     95          except TimeoutError, ex:
     96              log.info("Device timed out: " + self.connInfo.summary())
     97              return
     98          except Exception, ex:
     99              log.exception("Unable to talk: " + self.connInfo.summary())
    100              return
    101
    102          changed = True
    103          # FIXME: cleanup --force option #2660
    104          if not self.options.force and self.device.snmpOid.startswith(".1.3.6.1.4.1.9"):
    105              yield drive(self.checkCiscoChange)
    106              changed = driver.next()
    107          if changed:
    108              yield drive(self.collect)
    109
    110
    111 -    def collect(self, driver):
    112          for plugin in self.plugins:
    113              try:
    114                  log.debug('running %s', plugin)
    115                  pname = plugin.name()
    116                  self._tabledata[pname] = {}
    117                  log.debug("sending queries for plugin %s", pname)
    118                  if plugin.snmpGetMap:
    119                      results = {}
    120                      for oid in plugin.snmpGetMap.getoids():
    121                          yield self.proxy.get([oid])
    122                          results.update(driver.next())
    123                      self._getdata[pname] = results
    124                  for tmap in plugin.snmpGetTableMaps:
    125                      rowSize = len(tmap.getoids())
    126                      maxRepetitions = max(DEFAULT_MAX_OIDS_BACK / rowSize, 1)
    127                      yield self.proxy.getTable(tmap.getoids(),
    128                                                maxRepetitions=maxRepetitions,
    129                                                limit=sys.maxint)
    130                      self._tabledata[pname][tmap] = driver.next()
    131              except Exception, ex:
    132                  if not isinstance( ex, error.TimeoutError ):
    133                      log.exception("device %s plugin %s unexpected error",
    134                                    self.hostname, pname)
    135
    136
    137 -    def getResults(self):
    138          """Return data for this client in the form
    139          ((plugin, (getdata, tabledata),)
    140          getdata = {'.1.2.4.5':"value",}
    141          tabledata = {tableMap : {'.1.2.3.4' : {'.1.2.3.4.1': "value",...}}}
    142          """
    143          data = []
    144          for plugin in self.plugins:
    145              pname = plugin.name()
    146              getdata = self._getdata.get(pname,{})
    147              tabledata = self._tabledata.get(pname,{})
    148              if getdata or tabledata:
    149                  data.append((plugin, (getdata, tabledata)))
    150          return data
    151
    152 -    def clientFinished(self, result):
    153          log.info("snmp client finished collection for %s" % self.hostname)
    154          if isinstance(result, failure.Failure):
    155              from twisted.internet import error
    156              if isinstance(result.value, error.TimeoutError):
    157                  log.warning("Device %s timed out: are "
    158                              "your SNMP settings correct?", self.hostname)
    159              else:
    160                  log.error("Device %s had an error: %s", self.hostname, result)
    161          self.proxy.close()
    162          """tell the datacollector that we are all done"""
    163          if self.datacollector:
    164              self.datacollector.clientFinished(self)
    165          else:
    166              reactor.stop()
    167
    168
    169 -    def stop(self):
    170          self.proxy.close()
    171
    172
    173 -def buildOptions(parser=None, usage=None):
    174      "build options list that both telnet and ssh use"
    175
    176      if not usage:
    177          usage = "%prog [options] hostname[:port] oids"
    178
    179      if not parser:
    180          from optparse import OptionParser
    181          parser = OptionParser(usage=usage)
    182
    183      parser.add_option('--snmpCommunity',
    184                  dest='snmpCommunity',
    185                  default=defaultSnmpCommunity,
    186                  help='Snmp Community string')
    187
    188
    189  if __name__ == "__main__":
    190      import pprint
    191      logging.basicConfig()
    192      log = logging.getLogger()
    193      log.setLevel(20)
    194      import sys
    195      sys.path.append("plugins")
    196      from plugins.zenoss.snmp.InterfaceMap import InterfaceMap
    197      ifmap = InterfaceMap()
    198      sc = SnmpClient("gate.confmon.loc", community="zentinel", plugins=[ifmap,])
    199      reactor.run()
    200      pprint.pprint(sc.getResults())
    201