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                      yield self.proxy.get(plugin.snmpGetMap.getoids())
    120                      self._getdata[pname] = driver.next()
    121                  for tmap in plugin.snmpGetTableMaps:
    122                      rowSize = len(tmap.getoids())
    123                      maxRepetitions = max(DEFAULT_MAX_OIDS_BACK / rowSize, 1)
    124                      yield self.proxy.getTable(tmap.getoids(),
    125                                                maxRepetitions=maxRepetitions,
    126                                                limit=sys.maxint)
    127                      self._tabledata[pname][tmap] = driver.next()
    128              except Exception, ex:
    129                  if not isinstance( ex, error.TimeoutError ):
    130                      log.exception("device %s plugin %s unexpected error",
    131                                    self.hostname, pname)
    132
    133
    134 -    def getResults(self):
    135          """Return data for this client in the form
    136          ((plugin, (getdata, tabledata),)
    137          getdata = {'.1.2.4.5':"value",}
    138          tabledata = {tableMap : {'.1.2.3.4' : {'.1.2.3.4.1': "value",...}}}
    139          """
    140          data = []
    141          for plugin in self.plugins:
    142              pname = plugin.name()
    143              getdata = self._getdata.get(pname,{})
    144              tabledata = self._tabledata.get(pname,{})
    145              if getdata or tabledata:
    146                  data.append((plugin, (getdata, tabledata)))
    147          return data
    148
    149 -    def clientFinished(self, result):
    150          log.info("snmp client finished collection for %s" % self.hostname)
    151          if isinstance(result, failure.Failure):
    152              from twisted.internet import error
    153              if isinstance(result.value, error.TimeoutError):
    154                  log.warning("Device %s timed out: are "
    155                              "your SNMP settings correct?", self.hostname)
    156              else:
    157                  log.error("Device %s had an error: %s", self.hostname, result)
    158          self.proxy.close()
    159          """tell the datacollector that we are all done"""
    160          if self.datacollector:
    161              self.datacollector.clientFinished(self)
    162          else:
    163              reactor.stop()
    164
    165
    166
    167 -def buildOptions(parser=None, usage=None):
    168      "build options list that both telnet and ssh use"
    169
    170      if not usage:
    171          usage = "%prog [options] hostname[:port] oids"
    172
    173      if not parser:
    174          from optparse import OptionParser
    175          parser = OptionParser(usage=usage)
    176
    177      parser.add_option('--snmpCommunity',
    178                  dest='snmpCommunity',
    179                  default=defaultSnmpCommunity,
    180                  help='Snmp Community string')
    181
    182
    183  if __name__ == "__main__":
    184      import pprint
    185      logging.basicConfig()
    186      log = logging.getLogger()
    187      log.setLevel(20)
    188      import sys
    189      sys.path.append("plugins")
    190      from plugins.zenoss.snmp.InterfaceMap import InterfaceMap
    191      ifmap = InterfaceMap()
    192      sc = SnmpClient("gate.confmon.loc", community="zentinel", plugins=[ifmap,])
    193      reactor.run()
    194      pprint.pprint(sc.getResults())
    195