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

Source Code for Module DataCollector.SnmpSession

  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  import warnings 
 14  warnings.warn("SnmpSession is deprecated", DeprecationWarning) 
 15   
 16  __doc__="""snmp 
 17   
 18  snmp utility library to have a more sane interface than pysnmp 
 19   
 20  $Id: SnmpSession.py,v 1.16 2003/07/14 19:58:49 edahl Exp $""" 
 21   
 22  __version__ = "$Revision: 1.16 $"[11:-2] 
 23   
 24  import copy 
 25  from struct import unpack 
 26  import Globals 
 27   
 28  from pysnmp.compat.pysnmp2x import asn1, v1, asynrole 
 29  from pysnmp.proto import v2c 
 30  from pysnmp.mapping.udp import role 
 31  from pysnmp.proto.api import alpha 
 32   
 33  from Products.ZenUtils.Exceptions import ZentinelException 
 34   
35 -class ZenSnmpError(ZentinelException): pass
36
37 -class SnmpSession:
38
39 - def __init__(self, host, community='public', port=161, 40 version=1, timeout=2, retries=2, callback=None):
41 if version != 1 and version != 2: 42 raise ZenSnmpError('Unsupported SNMP protocol version: %s' 43 % (version,)) 44 self.community = community 45 if version == 2: 46 self.version = '2c' 47 else: 48 self.version = '1' 49 if callback: 50 self.client = asynrole.manager(callback, iface=(host, port)) 51 else: 52 self.client = role.manager((host, port)) 53 self.client.timeout = timeout 54 self.client.retries = retries
55 56
57 - def collectSnmpAttMap(self, snmpmap):
58 """collect snmp information from device 59 snmpmap is an SnmpAttMap object""" 60 oidmap = snmpmap.getOidMap() 61 oids = oidmap.keys() 62 snmpdata = self.get(oids) 63 retdata = {} 64 for oid, value in snmpdata.items(): 65 if snmpmap.getPropertyType(oid) == 'oidmac': 66 retdata[oidmap[oid]] = self.asmac(value) 67 else: 68 retdata[oidmap[oid]] = value 69 return retdata
70 71
72 - def collectSnmpTableMapClass(self, snmpmap):
73 """collect and map snmp table data returns a list of dictionaries 74 which have attribute names as keys and snmp data as values 75 snmpmap is an SnmpTableMap object""" 76 tablemap = self.collectSnmpTable(snmpmap.tableOid) 77 datamaps = [] 78 oidmap = snmpmap.getOidMap() 79 for row in tablemap.values(): 80 nrow = {} 81 for col in row.keys(): 82 if oidmap.has_key(col): 83 if snmpmap.getPropertyType(col) == 'oidmac': 84 nrow[oidmap[col]] = self.asmac(row[col]) 85 elif snmpmap.getPropertyType(col) == 'oidfs': 86 nrow[oidmap[col]] = row[col].replace('/', '-') 87 else: 88 nrow[oidmap[col]] = row[col] 89 datamaps.append(nrow) 90 return datamaps
91 92
93 - def collectSnmpTableMap(self, tableOid, dataMap, bulk=0):
94 """optimized table collection we only get the columns in datamap""" 95 if bulk: 96 collector = self.getBulkTable 97 else: 98 collector = self.getTable 99 retdata = {} 100 tblen = len(tableOid) 101 for col in dataMap.keys(): 102 snmpdata = collector(tableOid + col) 103 colname = dataMap[col] 104 for key, data in snmpdata.items(): 105 rowcol = key[tblen:].split('.') 106 row = '.'.join(rowcol[2:]) 107 if not retdata.has_key(row): 108 retdata[row] = {} 109 retdata[row][colname] = data 110 return retdata
111 112 113
114 - def collectSnmpTable(self, tableOid, bulk=0):
115 """collect and snmp table based on its oid and return 116 a dict of dicts with row, col as keys""" 117 if bulk: 118 snmpdata = self.getBulkTable(tableOid) 119 else: 120 snmpdata = self.getTable(tableOid) 121 tblen = len(tableOid) 122 tablemap = {} 123 for oid, value in snmpdata.items(): 124 rowcol = oid[tblen:].split('.') 125 col = '.'.join(rowcol[:2]) 126 row = '.'.join(rowcol[2:]) 127 if not tablemap.has_key(row): 128 tablemap[row] = {} 129 tablemap[row][col] = value 130 return tablemap
131 132
133 - def asmac(self, val):
134 """convert a byte string to a mac address string""" 135 mac = [] 136 for char in val: 137 tmp = unpack('B', char)[0] 138 tmp = str(hex(tmp))[2:] 139 if len(tmp) == 1: tmp = '0' + tmp 140 mac.append(tmp) 141 return ":".join(mac).upper()
142 143
144 - def asip(self, val):
145 ip = "" 146 for char in val: 147 tmp = unpack('B', char)[0] 148 ip = ip + str(tmp) + "." 149 return ip[:-1]
150 151
152 - def snmpTableMap(self, tabledata, oidmap):
153 """map the results of a full table query (as returned from 154 collectSnmpTable) the oidmap should be in the same format 155 has descripbed by snmpRowMap below 156 """ 157 datamaps = [] 158 for row in tabledata.values(): 159 nrow = self.snmpRowMap(row, oidmap) 160 datamaps.append(nrow) 161 return datamaps
162 163
164 - def snmpRowMap(self, row, oidmap):
165 """map the results of a single row from a table query 166 a row map has column numbers as keys (with the .) 167 and object attributes as the values. 168 {'.2' : 'id', '.3' : 'type',}""" 169 nrow = {} 170 for col in row.keys(): 171 if oidmap.has_key(col): 172 nrow[oidmap[col]] = row[col] 173 return nrow
174 175
176 - def get(self, head_oids):
177 req = eval('v' + self.version).GETREQUEST() 178 return self._get(req, head_oids)
179 180
181 - def getnext(self, head_oids):
182 req = eval('v' + self.version).GETNEXTREQUEST() 183 return self._get(req, head_oids)
184 185
186 - def _get(self, req, head_oids):
187 """get a list of oids""" 188 if type(head_oids) == type(''): 189 head_oids = [head_oids,] 190 encoded_oids = map(asn1.OBJECTID().encode, head_oids) 191 (oids, vals, rsp) = self._perfreq(req, encoded_oids) 192 retval={} 193 for (oid, val) in map(None, oids, vals): 194 retval[oid] = val 195 return retval
196 197
198 - def getTable(self, head_oids, bulk=0):
199 """walk a list of table oids""" 200 if bulk: 201 return self.getBulkTable(head_oids) 202 if type(head_oids) == type(''): 203 head_oids = [head_oids,] 204 retval = {} 205 encoded_oids = map(asn1.OBJECTID().encode, head_oids) 206 req = eval('v' + self.version).GETNEXTREQUEST() 207 while 1: 208 (oids, vals, rsp) = self._perfreq(req, encoded_oids) 209 if rsp['error_status'] == 2: 210 # One of the tables exceeded 211 for l in oids, vals, head_oids: 212 del l[rsp['error_index']-1] 213 # Exclude completed OIDs 214 while 1: 215 for idx in range(len(head_oids)): 216 if not asn1.OBJECTID(head_oids[idx]).isaprefix(oids[idx]): 217 # One of the tables exceeded 218 for l in oids, vals, head_oids: 219 del l[idx] 220 break 221 else: 222 break 223 224 if not head_oids: return retval 225 226 # Print out results 227 for (oid, val) in map(None, oids, vals): 228 retval[oid] = val 229 230 # BER encode next SNMP Object IDs to query 231 encoded_oids = map(asn1.OBJECTID().encode, oids) 232 233 # Update request object 234 req['request_id'] = req['request_id'] + 1
235 236 237
238 - def getBulkTable(self, head_oids):
239 """get a set of table oids using snmp bulk requests 240 if a list of oids is passed in they must have result 241 rows that are the same length (ie different columns 242 of the same table)""" 243 if type(head_oids) == type(''): 244 head_oids = [head_oids,] 245 retdata = {} 246 oids = copy.copy(head_oids) 247 req = v2c.GetBulkRequest() 248 req['community'].set(self.community) 249 req['pdu']['get_bulk_request']['variable_bindings'].extend( 250 map(lambda x: v2c.VarBind(name=v2c.ObjectName(x)), oids)) 251 rsp = v2c.Response(); 252 while 1: 253 vb = map(lambda x: v2c.VarBind(name=v2c.ObjectName(x)), oids) 254 req['pdu'].values()[0]['variable_bindings']=v2c.VarBindList(*vb) 255 # Encode SNMP request message and try to send it to SNMP agent and 256 # receive a response 257 (answer, src) = self.client.send_and_receive(req.encode()) 258 # Attempt to decode SNMP response 259 rsp.decode(answer) 260 # Make sure response matches request 261 if not req.match(rsp): 262 raise ZenSnmpError('Unmatched response: %s vs %s' % (req, rsp)) 263 # Fetch Object ID's and associated values 264 oids = map(lambda x: x['name'].get(), \ 265 rsp['pdu'].values()[0]['variable_bindings']) 266 vals = map(lambda x: x['value'], \ 267 rsp['pdu'].values()[0]['variable_bindings']) 268 # Check for remote SNMP agent failure 269 if rsp['pdu'].values()[0]['error_status']: 270 raise ZenSnmpError(str(rsp['pdu'].values()[0]['error_status'])+ 271 ' at '+str(oids[rsp['pdu'].values()[0]['error_index'].get()-1])) 272 # The following is taken from RFC1905 273 # (fixed not to depend of repetitions) 274 N = 0; 275 R = len(req['pdu'].values()[0]['variable_bindings']) - N 276 L = len(rsp['pdu'].values()[0]['variable_bindings']) 277 M = L / R 278 cut=(R*M)-L 279 if cut < 0: 280 oids=oids[:cut] 281 vals=vals[:cut] 282 for i in range(1, M+1): 283 for r in range(1, R+1): 284 idx = N + ((i-1)*R) + r 285 oid = oids[idx-1] 286 if oid.find(head_oids[r-1]) > -1: 287 retdata[oid] = \ 288 vals[idx-1].apiAlphaGetTerminalValue().get() 289 else: 290 oids[idx-1]="None" 291 oids = oids[-R:] 292 vals = vals[-R:] 293 toids = copy.copy(oids) 294 for oid in toids: 295 if oid == 'None': 296 oids.remove(oid) 297 if not oids: 298 break 299 req['pdu'].values()[0]['request_id'] = \ 300 req['pdu'].values()[0]['request_id'] + 1 301 return retdata
302 303
304 - def _perfreq(self, req, encoded_oids):
305 """perform a get based on req and a list of encoded_oids""" 306 rsp = eval('v' + self.version).GETRESPONSE() 307 myreq = req.encode(community=self.community, encoded_oids=encoded_oids) 308 (answer, src) = self.client.send_and_receive(myreq) 309 rsp.decode(answer) 310 if req != rsp: 311 raise ZenSnmpError('Unmatched response: %s vs %s' % 312 (str(req), str(rsp))) 313 if rsp['error_status']: 314 raise ZenSnmpError('SNMP error #' + str(rsp['error_status']) + 315 ' for OID #' + str(rsp['error_index'])) 316 oids = map(lambda x: x[0], map(asn1.OBJECTID().decode, 317 rsp['encoded_oids'])) 318 vals = map(lambda x: x[0](), map(asn1.decode, rsp['encoded_vals'])) 319 return (oids, vals, rsp)
320 321 322 323 324 325 326 327 if __name__ == '__main__': 328 s = SnmpSession('laser', community='public') 329 #print "uptime =", s.get('.1.3.6.1.2.1.1.3.0').values()[0] 330 #print "descr =", s.get('.1.3.6.1.2.1.1.1').values()[0] 331 #print 'conrad mac = ', asmac(s.get('.1.3.6.1.2.1.2.2.1.6.2').values()[0]) 332 #r = s.getTable(['.1.3.6.1.2.1.1', '.1.3.6.1.2.1.2.2.1']) 333 #r = s.getTable(['.1.3.6.1.2.1.2.2.1.1',]) 334 r = s.getTable(['.1.3.6.1.2.1.1',]) 335 #r = s.getTable(['.1.3.6.1.2.1.2.2.1.10',]) 336 #r = s.getTable(['.1.3.6.1.2.1.2.2.1.1', '.1.3.6.1.2.1.2.2.1.6',]) 337 #for i in range(4,12): 338 # r = s.getTable(['.1.3.6.1.2.1.2.2.1.'+str(i),]) 339 a = r.keys() 340 a.sort() 341 for k in a: 342 print k + "-->" + str(r[k]) 343