pysnmp - ValueError: too many values to unpack (expected 4) - python

If I try something like this, I got
ValueError: too many values to unpack (expected 4)
Can someone explain why?
from pysnmp.hlapi import *
errorIndication, errorStatus, errorIndex, varBinds = nextCmd(
SnmpEngine(),
CommunityData('public', mpModel=1),
UdpTransportTarget(('giga-int-2', 161)),
ContextData(),
ObjectType(ObjectIdentity('1.3.6.1.2.1.31.1.1.1.1')),
lexicographicMode=False
)
if errorIndication:
print(errorIndication)
elif errorStatus:
print('%s at %s' % (errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
else:
for v in varBinds:
for name, val in v:
print('%s = %s' % (name.prettyPrint(), val.prettyPrint()))

The nextCmd() function (as well as other pysnmp functions) returns a single Python generator object which you should iterate over:
>>> from pysnmp.hlapi import *
>>> g = nextCmd(SnmpEngine(),
... CommunityData('public'),
... UdpTransportTarget(('demo.snmplabs.com', 161)),
... ContextData(),
... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr')))
>>> next(g)
(None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')),
DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'))])
You can use this generator like any Python iterable, for example in a loop. Or, if you need to run just a single request/response, you can simply call next on it.
On each iteration pysnmp sends out a request (one or more depending of circumstances) asking for a single OID which is greater than the previous one. That way you "walk" the SNMP agent till you break out of the loop or exhaust OIDs on agent's side.
Your mistake here is that you are expecting pysnmp's nextCmd to run SNMP query immediately and return a value. Instead pysnmp gives you a generator-coroutine which you can use repeatedly to perform multiple queries (you can also .send() it OIDs to query).

Thanks for the answer. I rewrote the code. Now it's doing what I wanted. It just searches through the '1.3.6.1.2.1.31.1.1.1.x' tree.
from pysnmp.hlapi import *
for errorIndication, errorStatus, errorIndex, varBinds in nextCmd(
SnmpEngine(),
CommunityData('public', mpModel=1),
UdpTransportTarget(('giga-int-2', 161)),
ContextData(),
ObjectType(ObjectIdentity('1.3.6.1.2.1.31.1.1.1.1')),
lexicographicMode=False
):
if errorIndication:
print(errorIndication)
elif errorStatus:
print('%s at %s' % (errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
else:
for v in varBinds:
print(v.prettyPrint())
SNMPv2-SMI::mib-2.31.1.1.1.1.1 = sc0
SNMPv2-SMI::mib-2.31.1.1.1.1.2 = sl0
SNMPv2-SMI::mib-2.31.1.1.1.1.3 = sc1
SNMPv2-SMI::mib-2.31.1.1.1.1.5 = VLAN-1
SNMPv2-SMI::mib-2.31.1.1.1.1.6 = VLAN-1002
...

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.

SNMP Simulator for Testing PySNMP?

I am looking for a way to test PySNMP scripts, since it seems like demo.snmplabs.com and snmpsim.try.thola.io are down - at least I can't get a response with the following example script from the PySNMP docs. Are there any other hosts I could try?
from pysnmp.hlapi import *
for (errorIndication,
errorStatus,
errorIndex,
varBinds) in nextCmd(SnmpEngine(),
CommunityData('public'),
UdpTransportTarget(('snmpsim.try.thola.io', 161)),
ContextData(),
ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0')),
lookupMib=False):
if errorIndication:
print(errorIndication)
break
elif errorStatus:
print('%s at %s' % (errorStatus.prettyPrint(),
errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
break
else:
print("hello")
for varBind in varBinds:
print(' = '.join([x.prettyPrint() for x in varBind]))
Response: No SNMP response received before timeout
EDIT: I have tried snmp.live.gambitcommunications.com, demo.snmplabs.com, and snmpsim.try.thola.io so at this point I feel like I'm missing something. Any ideas?
While there were so many attempts to fill the gaps, you will find demo.pysnmp.com a more reliable option from me, as I plan to take over the whole ecosystem, https://github.com/etingof/pysnmp/issues/429

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.

Categories