pysnmp poll specific process index within HOST-RESOURCES-MIB - python

I have the following code which I've been using to poll with pysnmp. Up until now it has been used to walk but I'd like to be able to get a specific index. For example I'd like to poll HOST-RESOURCES-MIB::hrSWRunPerfMem.999
I can use this to sucessfully get back everything in hrSWRunPerfMem using getCounter('1.1.1.1', 'public', 'HOST-RESOURCES-MIB', 'hrSWRunPerfMem')
However once I try to include the index number getCounter('1.1.1.1', 'public', 'HOST-RESOURCES-MIB', 'hrSWRunPerfMem', indexNum=999) I always get varBindTable == []
from pysnmp.entity.rfc3413.oneliner import cmdgen
from pysnmp.smi import builder, view
def getCounter(ip, community, mibName, counterName, indexNum=None):
cmdGen = cmdgen.CommandGenerator()
mibBuilder = cmdGen.mibViewController.mibBuilder
mibPath = mibBuilder.getMibSources() + (builder.DirMibSource("/path/to/mibs"),)
mibBuilder.setMibSources(*mibPath)
mibBuilder.loadModules(mibName)
mibView = view.MibViewController(mibBuilder)
retList = []
if indexNum is not None:
mibVariable = cmdgen.MibVariable(mibName, counterName, int(indexNum))
else:
mibVariable = cmdgen.MibVariable(mibName, counterName)
errorIndication, errorStatus, errorIndex, varBindTable = cmdGen.nextCmd(cmdgen.CommunityData('test-agent', community),
cmdgen.UdpTransportTarget((ip, snmpPort)),
mibVariable)
Does anyone have some insight into how to poll specific indexes using pysnmp?

You should be using cmdGen.getCmd() call instead of nextCmd() call. There's no 'next' OID past the leaf one hence empty response.
Here's a bit optimized version of your code. It should run as-is right from your Python prompt:
from pysnmp.entity.rfc3413.oneliner import cmdgen
def getCounter(ip, community, mibName, counterName, indexNum=None):
if indexNum is not None:
mibVariable = cmdgen.MibVariable(mibName, counterName, int(indexNum))
else:
mibVariable = cmdgen.MibVariable(mibName, counterName)
cmdGen = cmdgen.CommandGenerator()
errorIndication, errorStatus, errorIndex, varBindTable = cmdGen.getCmd(
cmdgen.CommunityData(community),
cmdgen.UdpTransportTarget((ip, 161)),
mibVariable.addMibSource("/path/to/mibs")
)
if not errorIndication and not errorStatus:
return varBindTable
#from pysnmp import debug
#debug.setLogger(debug.Debug('msgproc'))
print(getCounter('demo.snmplabs.com',
'recorded/linux-full-walk',
'HOST-RESOURCES-MIB',
'hrSWRunPerfMem',
970))
Performance wise, it's recommended to reuse CommandGenerator instance to save on [heavy] snmpEngine initialisation happening under the hood.

Related

Retrieving printer toner information with pysnmp

I am trying to retrieve printer toner information from networked printers.
I found the following reference record for printer supplies -> http://oidref.com/1.3.6.1.2.1.43.11 (OID = prtMarkerSupplies)
I tried integrating the OID in the following code:
from pysnmp.hlapi import *
iterator = getCmd(
SnmpEngine(),
CommunityData('public', mpModel=0),
UdpTransportTarget(('here goes ip of a printer', 161)),
ContextData(),
ObjectType(ObjectIdentity('SNMPv2-MIB', "prtMarkerSupplies", 0))
)
errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
if errorIndication:
print(errorIndication)
elif errorStatus:
print('%s at %s' % (errorStatus.prettyPrint(),
errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
else:
for varBind in varBinds:
print(' = '.join([x.prettyPrint() for x in varBind]))
The above code returns:
pysnmp.smi.error.SmiError: No symbol SNMPv2-MIB::prtMarkerSupplies at <pysnmp.smi.builder.MibBuilder object at 0x000001F8D1FC3D00>
How can I retrieve toner information using the SNMP protocol and pysnmp?
Retrieving system information works as intended:
ObjectType(ObjectIdentity('SNMPv2-MIB', "sysDescr", 0))
I used the answer from the following thread -> snmpwalk with PySNMP
Instead of iterating over getCmd, I used SNMP walk to walk through all of the OIDs.

Reading OID and display its variable or name in python using pysnmp

I am trying to write a code in python to run a function that reads the OID variable and name of a device.
I managed to find out their OID's but every time I enter the OID number in my code it shows me there is no OID
here is the Python code using pysnmp:
#########################
from pysnmp.entity.rfc3413.oneliner import cmdgen
cmd_gen = cmdgen.CommandGenerator()
error_indication, error_status, error_index, var_binds = cmd_gen.getCmd(
cmdgen.CommunityData('public'),
cmdgen.UdpTransportTarget(('192.168.178.213', 161)),
'.1.3.6.1.4.1.9986.3.22.1.1.3.1.10')
for name, val in var_binds:
print('%s' % val.prettyPrint())
#################
here is the device with one of the OIDs
There is a simple way of traversing OIDs in SNMP called SNMP WALK. It can be implemented as simple as this:
def walk_mib(ipaddress, oid):
for (errorIndication, errorStatus, errorIndex, varBinds) in nextCmd(SnmpEngine(),
CommunityData('public'),
UdpTransportTarget((ipaddress, 161)),
ContextData(),
ObjectType(ObjectIdentity(oid)),
):
if not errorIndication and not errorStatus:
for varBind in varBinds:
result=' = '.join([x.prettyPrint() for x in varBind])
print(result)
walk_mib('<ip address>', start_oid)

pysnmp v3 GETBULK

I currently have a script which polls multiple oids on multiple devices using PySNMP. It reads the list of hosts in from a file and for some hosts needs to poll 3 or 4 oids, at the moment it is doing this sequentially, so to make it more efficient I want to do a getbulk so I'm only polling each host once.
I've done multiple searches on this and can find plenty of examples using pysnmp and snmp v2 but I can't find an example with snmpv3. I've tried the test script below but it's throwing up an error so can someone take a look and let me know what I'm doing wrong please? My test script looks like this:
from pysnmp.entity.rfc3413.oneliner import cmdgen
host='10.0.0.1'
incount = '.1.3.6.1.2.1.31.1.1.1.6.16'
outcount ='.1.3.6.1.2.1.31.1.1.1.10.16'
errorIndication, errorStatus, errorIndex,
varBindTable = cmdgen.CommandGenerator().bulkCmd(
UsmUserData('snmp_user', 'password', 'password',
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol),
UdpTransportTarget((host, 161)),
0,
25,
(incount),
(outcount),
)
if errorIndication:
print errorIndication
else:
if errorStatus:
print '%s at %s\n' % (
errorStatus.prettyPrint(),
errorIndex and varBindTable[-1][int(errorIndex)-1] or '?'
)
else:
for varBindTableRow in varBindTable:
for name, val in varBindTableRow:
print '%s = %s' % (name.prettyPrint(), val.prettyPrint())
and the error:
Traceback (most recent call last):
File "./multiget.py", line 7, in <module>
errorIndication, errorStatus, errorIndex,
NameError: name 'errorIndication' is not defined
It's pretty much falling at the first hurdle so I've evidently got the syntax wrong, but like I say, I couldn't find an example of this with snmpv3.
Thanks
Ed
It looks like a formatting error in the first place. Try this layout:
from pysnmp.entity.rfc3413.oneliner import cmdgen
host='10.0.0.1'
incount = '.1.3.6.1.2.1.31.1.1.1.6.16'
outcount ='.1.3.6.1.2.1.31.1.1.1.10.16'
cmdGen = cmdgen.CommandGenerator()
(errorIndication, errorStatus, errorIndex,
varBindTable) = cmdGen.bulkCmd(
UsmUserData('snmp_user', 'password', 'password',
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol),
UdpTransportTarget((host, 161)),
0,
25,
incount,
outcount,
)
...
Also, CommandGenerator (i.e. underlying SnmpEngine object) is expensive to create. Therefore it makes sense to keep one around for as long as you plan to use it.

PySNMP 4.4 with Python 2.7 bulkCmd output not including child OID's

To start off with, I'm new to Python and PySNMP. I'm trying to pass a list of network devices to bulkCmd to obtain information on all the physical interfaces.
Currently it is only collecting the first interface and then moves on to the next network device in the list. I have made changes with lexicographic and maxCalls, repetitions but none make any difference.
I have successfully polled all interfaces when sending a single bulkCmd to single network device.
Code:
from pysnmp.hlapi import *
routers = ["router1", "router2"]
#adds routers to getCmd and bulkCmd
def snmpquery (hostip):
errorIndication, errorStatus, errorIndex, varBinds = next (
bulkCmd(SnmpEngine(),
CommunityData('communitystring'),
UdpTransportTarget((hostip, 161)),
ContextData(),
0, 50,
ObjectType(ObjectIdentity('IF-MIB', 'ifDescr')),
ObjectType(ObjectIdentity('IF-MIB', 'ifAlias')),
ObjectType(ObjectIdentity('IF-MIB', 'ifOperStatus')),
lexicographicMode=True
)
)
# Check for errors and print out results
if errorIndication:
print(errorIndication)
elif errorStatus:
print('%s at %s' % (errorStatus.prettyPrint(),
errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
else:
for varBind in varBinds:
print(' = '.join([x.prettyPrint() for x in varBind]))
# calls snmpquery for all routers in list
for router in routers:
snmpquery(router)
Output:
IF-MIB::ifDescr.1 = GigabitEthernet0/0
IF-MIB::ifAlias.1 = InterfaceDesc
IF-MIB::ifOperStatus.1 = 'up'
IF-MIB::ifDescr.1 = GigabitEthernet0/0
IF-MIB::ifAlias.1 = InterfaceDesc
IF-MIB::ifOperStatus.1 = 'up'
bulkSNMP returns an iterator and you were using next() on it which retrieves only the first of the iterations. You probably got the idea from the PySNMP documentation, which doesn't do a great job of showing how to retrieve all the results.
You should use a for loop to loop over all of the iterations, as follows:
from pysnmp.hlapi import *
routers = ["router1", "router2"]
def snmpquery (hostip):
snmp_iter = bulkCmd(SnmpEngine(),
CommunityData('communitystring'),
UdpTransportTarget((hostip, 161)),
ContextData(),
0, 50,
ObjectType(ObjectIdentity('IF-MIB', 'ifDescr')),
ObjectType(ObjectIdentity('IF-MIB', 'ifAlias')),
ObjectType(ObjectIdentity('IF-MIB', 'ifOperStatus')),
lexicographicMode=True)
for errorIndication, errorStatus, errorIndex, varBinds in snmp_iter:
# Check for errors and print out results
if errorIndication:
print(errorIndication)
elif errorStatus:
print('%s at %s' % (errorStatus.prettyPrint(),
errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
else:
for varBind in varBinds:
print(' = '.join([x.prettyPrint() for x in varBind]))
# calls snmpquery for all routers in list
for router in routers:
snmpquery(router)
Also, be careful about indentation when posting Python-related questions, as it is significant.
You need to iterate over the generator produced by the bulkCmd function to repeat SNMP queries to pull SNMP managed objects that did not fit into previous response packet(s). Just ditch the next() call and run for loop over bulkCmd().
Side note 1: you may not need lexicographicMode=True if you want to fetch managed objects that reside just under the MIB table columns (e.g. IF-MIB::ifDescr etc).
Side note 2: if you have many SNMP agents on your network, you may consider speeding up the process of data retrieval by talking to the in parallel. You'd use the same getBulk() call, it's just the underlaying network I/O that does the parallelism.

pysnmp output format issue

I am trying to get some snmp variables from cisco routers using PySNMP but I am getting a hex output using prettyprint instead of the output I get from my normal snmp browser.
I have tried multiple encode (hex, utf-8 and ascii) and without encode, always not what I was expecting.
Any ideas?
Thanks
Start discovery of 10.148.8.15
1.3.6.1.2.1.1.1.0 = 0x436973636f20494f5320536f6674776172652c20494f532d584520536f66747761726520285838365f36345f4c494e55585f494f53442d554e4956455253414c4b392d4d292c2056657273696f6e2031352e3228342953352c2052454c4541534520534f4654574152452028666331290d0a546563686e6963616c20537570706f72743a20687474703a2f2f7777772e636973636f2e636f6d2f74656368737570706f72740d0a436f707972696768742028632920313938362d3230313420627920436973636f2053797374656d732c20496e632e0d0a436f6d70696c6564205475652032352d4665622d31342031313a3336206279206d63707265
result = {'error': 1, 'value': "default"}
cmdGen = cmdgen.CommandGenerator()
errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd(
cmdgen.CommunityData(community),
cmdgen.UdpTransportTarget((destination, 161)),
cmdgen.MibVariable(oid)
)
# Check for errors and print out results
if errorIndication:
print(errorIndication)
else:
if errorStatus:
result['error'] = 1
# print('%s at %s' % (
# errorStatus.prettyPrint(),
# errorIndex and varBinds[int(errorIndex)-1] or '?'
# )
# )
else:
result['error'] = 0
for name, val in varBinds:
print('%s = %s' % (name.prettyPrint(), val.prettyPrint()))
result['value'] = val.prettyPrint().encode("ascii")
That is because Cisco SNMP Agent reports control characters (\n) what may potentially screw your script's output. There are several ways to handle this:
Pass lookupMib=True like shown in this example. Then pysnmp would try to look up proper output format for this particular OID at MIB. For this to work pysnmp must be able to find and load pysnmp-formatted MIB file(s).
Add some code to trigger a hex string decoder when 0x prefix is seen:
s = '436973636f...06d63707265'
print(''.join([ chr(int(s[x:x+2], 16)) for x in range(0, len(s), 2) ]))
Cisco IOS Software, IOS-XE Software ...Compiled Tue 25-Feb-14 11:36 by mcpre

Categories