Package Products :: Package ZenUtils :: Module snmp |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenUtils.snmp

      1  ###########################################################################
      2  #
      3  # This program is part of Zenoss Core, an open source monitoring platform.
      4  # Copyright (C) 2010, Zenoss Inc.
      5  #
      6  # This program is free software; you can redistribute it and/or modify it
      7  # under the terms of the GNU General Public License version 2 or (at your
      8  # option) any later version as published by the Free Software Foundation.
      9  #
     10  # For complete information please visit: http://www.zenoss.com/oss/
     11  #
     12  ###########################################################################
     13
     14  import logging
     15  from twisted.internet import reactor
     16  from twisted.internet.defer import Deferred
     17  from pynetsnmp.twistedsnmp import AgentProxy
     18
     19  _LOG = logging.getLogger("zen.ZenUtils.snmp")
     20
     21 -class SnmpConfig(object):
     22      succeeded = None
     23      sysName = None
     24
     25      @property
     26 -    def port(self):
     27          return self._port
     28
     29      @property
     30 -    def community(self):
     31          return self._community
     32
     33      @property
     34 -    def weight(self):
     35          return self._weight is None and self.defaultWeight or self._weight
     36
     37
     38 -    def __init__(self, ip, weight=None, port=161, timeout=2.5, retries=2,
     39          community='public'):
     40          self._ip = ip
     41          self._weight = weight
     42          self._port = port
     43          self._timeout = timeout
     44          self._retries = retries
     45          self._community = community
     46
     47
     48 -    def __str__(self):
     49          return "(%s) %s:%s, SNMP%s, timeout=%ss, retries=%s, community=%s" % (
     50              self.weight, self._ip, self._port, self.version, self._timeout,
     51              self._retries, self.community)
     52
     53
     54 -    def getAgentProxy(self):
     55          return AgentProxy(
     56              ip=self._ip,
     57              port=self._port,
     58              timeout=self._timeout,
     59              tries=self._retries,
     60              snmpVersion=self.version,
     61              community=self._community)
     62
     63
     64 -    def test(self, oid='.1.3.6.1.2.1.1.5.0'):
     65          _LOG.debug("SnmpConfig.test: oid=%s" % oid)
     66          self._proxy = self.getAgentProxy()
     67          self._proxy.open()
     68          return self._proxy.get([oid]).addBoth(self.enrichResult)
     69
     70
     71 -    def enrichResult(self, result):
     72          self._proxy.close()
     73          if isinstance(result, dict) and bool(result):
     74              # one and only one key/value pair _should_ be available in result,
     75              # and we only need the value (the device name)
     76              self.sysName = result.values()[0]
     77              self.succeeded = True
     78          else:
     79              self.succeeded = False
     80
     81          return self
     82
     83
     84 -class SnmpV1Config(SnmpConfig):
     85      version = 'v1'
     86      defaultWeight = 10
     87
     88
     89 -class SnmpV2cConfig(SnmpConfig):
     90      version = 'v2c'
     91      defaultWeight = 20
     92
     93
     94 -class SnmpV3Config(SnmpConfig):
     95      version = 'v3'
     96      defaultWeight = 30
     97
     98 -    def __init__(self, ip, weight=None, port=161, timeout=2.5, retries=2,
     99          community='public', securityName=None, authType=None,
    100          authPassphrase=None, privType=None, privPassphrase=None):
    101          super(SnmpV3Config, self).__init__(
    102              ip, weight, port, timeout, retries, community)
    103
    104          self._securityName = securityName
    105          self._authType = authType
    106          self._authPassphrase = authPassphrase
    107          self._privType = privType
    108          self._privPassphrase = privPassphrase
    109
    110
    111 -    def __str__(self):
    112          v3string = "securityName=%s" % self._securityName
    113          if self._authType:
    114              v3string += ", authType=%s, authPassphrase=%s" % (
    115                  self._authType, self._authPassphrase)
    116
    117          if self._privType:
    118              v3string += " privType=%s, privPassphrase=%s" % (
    119                  self._privType, self._privPassphrase)
    120
    121          return "(%s) %s:%s, SNMP%s, timeout=%ss, retries=%s, %s" % (
    122              self.weight, self._ip, self._port, self.version, self._timeout,
    123              self._retries, v3string)
    124
    125
    126 -    def getAgentProxy(self):
    127          cmdLineArgs = ['-u', self._securityName]
    128
    129          if self._privType:
    130              cmdLineArgs += [
    131                  '-l', 'authPriv',
    132                  '-x', self._privType,
    133                  '-X', self._privPassphrase]
    134          elif self._authType:
    135              cmdLineArgs += [
    136                  '-l', 'authNoPriv']
    137          else:
    138              cmdLineArgs += [
    139                  '-l', 'noAuthNoPriv']
    140
    141          if self._authType:
    142              cmdLineArgs += [
    143                  '-a', self._authType,
    144                  '-A', self._authPassphrase]
    145
    146          return AgentProxy(
    147              ip=self._ip,
    148              port=self._port,
    149              timeout=self._timeout,
    150              tries=self._retries,
    151              snmpVersion=self.version,
    152              community=self._community,
    153              cmdLineArgs=cmdLineArgs)
    154
    155
    156 -    def enrichResult(self, result):
    157          self._proxy.close()
    158          if isinstance(result, dict) \
    159              and len(result.keys()) > 0 \
    160              and not result.keys()[0].startswith('.1.3.6.1.6.3.15.1.1.'):
    161              self.sysName = result.values()[0]
    162              self.succeeded = True
    163          else:
    164              self.succeeded = False
    165
    166          return self
    167
    168
    169 -class SnmpAgentDiscoverer(object):
    170      _bestsofar = None
    171
    172 -    def _handleResult(self, result):
    173          if not hasattr(result, 'weight'):
    174              # http://dev.zenoss.org/trac/ticket/6268
    175              return
    176
    177          for i, p in enumerate(self._pending):
    178              if p.weight == result.weight:
    179                  self._pending.pop(i)
    180
    181          if result.succeeded:
    182              # Record this result as the best so far.
    183              if self._bestsofar:
    184                  if result.weight > self._bestsofar.weight:
    185                      self._bestsofar = result
    186              else:
    187                  self._bestsofar = result
    188
    189              # Short-circuit the rest of the tests if this result's weight is
    190              # higher than any still pending.
    191              for config in self._pending:
    192                  if config.weight >= self._bestsofar.weight:
    193                      break
    194              else:
    195                  if not self._d.called:
    196                      self._d.callback(self._bestsofar)
    197
    198                  return
    199
    200          # We got responses to all of our queries without being able to short-
    201          # circuit the test. Return the best match or none.
    202          if len(self._pending) < 1 and not self._d.called:
    203              self._d.callback(self._bestsofar)
    204
    205
    206 -    def findBestConfig(self, configs):
    207          """
    208          Returns the best SnmpConfig in the provided configs list.
    209          """
    210          _LOG.debug("findBestConfig: configs=%s" % configs)
    211          self._pending = configs
    212          self._d = Deferred()
    213
    214          for c in configs:
    215              c.test().addBoth(self._handleResult)
    216
    217          return self._d
    218
    219
    220  if __name__ == '__main__':
    221      """
    222      The following snmpd.conf is a good one to run the following tests on.
    223
    224      rocommunity zenosszenoss
    225      rouser noauthtest noauth
    226      createUser noauthtest MD5 "zenosszenoss"
    227      rouser authtest
    228      createUser authtest SHA "zenosszenoss"
    229      rouser privtest
    230      createUser privtest SHA "zenosszenoss" DES "zenosszenoss"
    231      """
    232 -    def printAndExit(result):
    233          print result
    234          reactor.stop()
    235
    236      configs = [
    237          SnmpV3Config('127.0.0.1', weight=33, securityName='privtest',
    238              authType='SHA', authPassphrase='zenosszenoss',
    239              privType='DES', privPassphrase='zenosszenoss'),
    240
    241          SnmpV3Config('127.0.0.1', weight=32, securityName='authtest',
    242              authType='SHA', authPassphrase='zenosszenoss'),
    243
    244          SnmpV3Config('127.0.0.1', weight=31, securityName='noauthtest'),
    245
    246          SnmpV2cConfig('127.0.0.1', weight=22, community='zenosszenoss'),
    247          SnmpV2cConfig('127.0.0.1', weight=21, community='public'),
    248
    249          SnmpV1Config('127.0.0.1', weight=12, community='zenosszenoss'),
    250          SnmpV1Config('127.0.0.1', weight=11, community='public'),
    251          ]
    252
    253      sad = SnmpAgentDiscoverer()
    254      sad.findBestConfig(configs).addBoth(printAndExit)
    255      reactor.run()
    256