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

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