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

Source Code for Module Products.DataCollector.SnmpClient

  1  ############################################################################## 
  2  #  
  3  # Copyright (C) Zenoss, Inc. 2007, 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 sys 
 12  import logging 
 13  log = logging.getLogger("zen.SnmpClient") 
 14   
 15  from twisted.internet import reactor, error, defer 
 16  from twisted.python import failure 
 17  from twisted.internet.error import TimeoutError 
 18   
 19  from Products.ZenUtils.snmp import SnmpV1Config, SnmpV2cConfig 
 20  from Products.ZenUtils.snmp import SnmpAgentDiscoverer 
 21   
 22  from pynetsnmp.twistedsnmp import snmpprotocol, Snmpv3Error 
 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 self.proxy = None
55
56 - def initSnmpProxy(self):
57 if self.proxy is not None: self.proxy.close() 58 srcport = snmpprotocol.port() 59 self.proxy = self.connInfo.createSession(srcport.protocol) 60 self.proxy.open()
61
62 - def run(self):
63 """Start snmp collection. 64 """ 65 log.debug("Starting %s", self.connInfo.summary()) 66 self.initSnmpProxy() 67 drive(self.doRun).addBoth(self.clientFinished)
68 69 70 # FIXME: cleanup --force option #2660
71 - def checkCiscoChange(self, driver):
72 """Check to see if a cisco box has changed. 73 """ 74 device = self.device 75 yield self.proxy.get(['.1.3.6.1.4.1.9.9.43.1.1.1.0']) 76 lastpolluptime = device.getLastPollSnmpUpTime() 77 log.debug("lastpolluptime = %s", lastpolluptime) 78 result = True 79 try: 80 lastchange = driver.next().values()[0] 81 log.debug("lastchange = %s", lastchange) 82 if lastchange <= lastpolluptime: 83 log.info("skipping cisco device %s no change detected", 84 device.id) 85 result = False 86 else: 87 device.setLastPollSnmpUpTime(lastchange) 88 except Exception: 89 pass 90 yield defer.succeed(result)
91 92
93 - def doRun(self, driver):
94 # test snmp connectivity 95 log.debug("Testing SNMP configuration") 96 yield self.proxy.walk('.1.3') 97 try: 98 driver.next() 99 except TimeoutError, ex: 100 log.info("Device timed out: " + self.connInfo.summary()) 101 if self.options.discoverCommunity: 102 yield self.findSnmpCommunity() 103 snmp_config = driver.next() 104 if not snmp_config: 105 log.warn( 106 'Failed to rediscover the SNMP connection info for %s', 107 self.device.manageIp) 108 return 109 if snmp_config.version: 110 self.connInfo.zSnmpVer = snmp_config.version 111 if snmp_config.port: 112 self.connInfo.zSnmpPort = snmp_config.port 113 if snmp_config.community: 114 self.connInfo.zSnmpCommunity = snmp_config.community 115 self.connInfo.changed = True 116 self.initSnmpProxy() 117 else: 118 return 119 except Snmpv3Error, ex: 120 log.info("Cannot connect to SNMP agent: {0}".format(self.connInfo.summary())) 121 return 122 except Exception, ex: 123 log.exception("Unable to talk: " + self.connInfo.summary()) 124 return 125 126 changed = True 127 # FIXME: cleanup --force option #2660 128 if not self.options.force and self.device.snmpOid.startswith(".1.3.6.1.4.1.9"): 129 yield drive(self.checkCiscoChange) 130 changed = driver.next() 131 if changed: 132 yield drive(self.collect)
133
134 - def findSnmpCommunity(self):
135 def inner(driver): 136 """ 137 Twisted driver class to iterate through devices 138 139 @param driver: Zenoss driver 140 @type driver: Zenoss driver 141 @return: successful result is a list of IPs that were added 142 @rtype: Twisted deferred 143 """ 144 log.info("Rediscovering SNMP connection info for %s", 145 self.device.id) 146 147 communities = list(self.device.zSnmpCommunities) 148 communities.reverse() 149 150 configs = [] 151 weight = 0 152 port = int(self.device.zSnmpPort) 153 for community in communities: 154 weight+=1 155 configs.append(SnmpV1Config( 156 self.device.manageIp, weight=weight, 157 port=port, 158 timeout=self.connInfo.zSnmpTimeout, 159 retries=self.connInfo.zSnmpTries, 160 community=community)) 161 configs.append(SnmpV2cConfig( 162 self.device.manageIp, weight=weight+1000, port=port, 163 timeout=self.connInfo.zSnmpTimeout, 164 retries=self.connInfo.zSnmpTries, 165 community=community)) 166 167 yield SnmpAgentDiscoverer().findBestConfig(configs) 168 driver.next()
169 return drive(inner)
170 171
172 - def collect(self, driver):
173 maxOidsPerRequest = getattr(self.device, 'zMaxOIDPerRequest', DEFAULT_MAX_OIDS_BACK) 174 log.debug("Using a max of %s OIDs per request", maxOidsPerRequest) 175 for plugin in self.plugins: 176 try: 177 log.debug('running %s', plugin) 178 pname = plugin.name() 179 self._tabledata[pname] = {} 180 log.debug("sending queries for plugin %s", pname) 181 if plugin.snmpGetMap: 182 results = {} 183 for oid in plugin.snmpGetMap.getoids(): 184 yield self.proxy.get([oid]) 185 results.update(driver.next()) 186 self._getdata[pname] = results 187 for tmap in plugin.snmpGetTableMaps: 188 rowSize = len(tmap.getoids()) 189 maxRepetitions = max(maxOidsPerRequest / rowSize, 1) 190 yield self.proxy.getTable(tmap.getoids(), 191 maxRepetitions=maxRepetitions, 192 limit=sys.maxint) 193 self._tabledata[pname][tmap] = driver.next() 194 except Exception, ex: 195 if not isinstance( ex, error.TimeoutError ): 196 log.exception("device %s plugin %s unexpected error", 197 self.hostname, pname)
198 199
200 - def getResults(self):
201 """Return data for this client in the form 202 ((plugin, (getdata, tabledata),) 203 getdata = {'.1.2.4.5':"value",} 204 tabledata = {tableMap : {'.1.2.3.4' : {'.1.2.3.4.1': "value",...}}} 205 """ 206 data = [] 207 for plugin in self.plugins: 208 pname = plugin.name() 209 getdata = self._getdata.get(pname,{}) 210 tabledata = self._tabledata.get(pname,{}) 211 if getdata or tabledata: 212 data.append((plugin, (getdata, tabledata))) 213 return data
214 - def clientFinished(self, result):
215 log.info("snmp client finished collection for %s" % self.hostname) 216 if isinstance(result, failure.Failure): 217 from twisted.internet import error 218 if isinstance(result.value, error.TimeoutError): 219 log.warning("Device %s timed out: are " 220 "your SNMP settings correct?", self.hostname) 221 elif isinstance(result.value, Snmpv3Error): 222 log.warning("Connection to device {0.hostname} failed: {1.value.message}".format(self, result)) 223 else: 224 log.exception("Device %s had an error: %s",self.hostname,result) 225 self.proxy.close() 226 """tell the datacollector that we are all done""" 227 if self.datacollector: 228 self.datacollector.clientFinished(self) 229 else: 230 reactor.stop()
231
232 - def stop(self):
233 self.proxy.close()
234
235 -def buildOptions(parser=None, usage=None):
236 "build options list that both telnet and ssh use" 237 if not usage: 238 usage = "%prog [options] hostname[:port] oids" 239 if not parser: 240 from optparse import OptionParser 241 parser = OptionParser(usage=usage) 242 243 parser.add_option('--snmpCommunity', 244 dest='snmpCommunity', 245 default=defaultSnmpCommunity, 246 help='Snmp Community string')
247 248 249 if __name__ == "__main__": 250 import pprint 251 logging.basicConfig() 252 log = logging.getLogger() 253 log.setLevel(20) 254 import sys 255 sys.path.append("plugins") 256 from plugins.zenoss.snmp.InterfaceMap import InterfaceMap 257 ifmap = InterfaceMap() 258 sc = SnmpClient("gate.confmon.loc", community="zentinel", plugins=[ifmap,]) 259 reactor.run() 260 pprint.pprint(sc.getResults()) 261