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

# Source Code for Module Products.ZenUtils.snmp

      1  ##############################################################################
      2  #
      3  # Copyright (C) Zenoss, Inc. 2010, 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  import logging
     12  from twisted.internet import reactor
     13  from twisted.internet.defer import Deferred
     14  from pynetsnmp.twistedsnmp import AgentProxy
     15
     16  _LOG = logging.getLogger("zen.ZenUtils.snmp")
     17
     18 -class SnmpConfig(object):
     19      succeeded = None
     20      sysName = None
     21
     22      @property
     23 -    def port(self):
     24          return self._port
     25
     26      @property
     27 -    def community(self):
     28          return self._community
     29
     30      @property
     31 -    def weight(self):
     32          return self._weight is None and self.defaultWeight or self._weight
     33
     34
     35 -    def __init__(self, ip, weight=None, port=161, timeout=2.5, retries=2,
     36          community='public'):
     37          self._ip = ip
     38          self._weight = weight
     39          self._port = port
     40          self._timeout = timeout
     41          self._retries = retries
     42          self._community = community
     43
     44
     45 -    def __str__(self):
     46          return "(%s) %s:%s, SNMP%s, timeout=%ss, retries=%s, community=%s" % (
     47              self.weight, self._ip, self._port, self.version, self._timeout,
     48              self._retries, self.community)
     49
     50
     51 -    def getAgentProxy(self):
     52          return AgentProxy(
     53              ip=self._ip,
     54              port=self._port,
     55              timeout=self._timeout,
     56              tries=self._retries,
     57              snmpVersion=self.version,
     58              community=self._community)
     59
     60
     61 -    def test(self, oid='.1.3.6.1.2.1.1.5.0'):
     62          _LOG.debug("SnmpConfig.test: oid=%s" % oid)
     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          _LOG.debug("findBestConfig: configs=%s" % configs)
    208          self._pending = configs
    209          self._d = Deferred()
    210
    211          for c in configs:
    212              c.test().addBoth(self._handleResult)
    213
    214          return self._d
    215
    216
    217  if __name__ == '__main__':
    218      """
    219      The following snmpd.conf is a good one to run the following tests on.
    220
    221      rocommunity zenosszenoss
    222      rouser noauthtest noauth
    223      createUser noauthtest MD5 "zenosszenoss"
    224      rouser authtest
    225      createUser authtest SHA "zenosszenoss"
    226      rouser privtest
    227      createUser privtest SHA "zenosszenoss" DES "zenosszenoss"
    228      """
    229 -    def printAndExit(result):
    230          print result
    231          reactor.stop()
    232
    233      configs = [
    234          SnmpV3Config('127.0.0.1', weight=33, securityName='privtest',
    235              authType='SHA', authPassphrase='zenosszenoss',
    236              privType='DES', privPassphrase='zenosszenoss'),
    237
    238          SnmpV3Config('127.0.0.1', weight=32, securityName='authtest',
    239              authType='SHA', authPassphrase='zenosszenoss'),
    240
    241          SnmpV3Config('127.0.0.1', weight=31, securityName='noauthtest'),
    242
    243          SnmpV2cConfig('127.0.0.1', weight=22, community='zenosszenoss'),
    244          SnmpV2cConfig('127.0.0.1', weight=21, community='public'),
    245
    246          SnmpV1Config('127.0.0.1', weight=12, community='zenosszenoss'),
    247          SnmpV1Config('127.0.0.1', weight=11, community='public'),
    248          ]
    249
    250      sad = SnmpAgentDiscoverer()
    251      sad.findBestConfig(configs).addBoth(printAndExit)
    252      reactor.run()
    253