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